class EventMachine::Protocols::HeaderAndContentProtocol
Changed 13Sep08 by FCianfrocca.
handle the transitions between lines and binary text.
turn relies on BufferedTokenizer, which doesn’t gracefully
Originally, this subclassed LineAndTextProtocol, which in
–
}
EM.start_server ‘localhost’, 80, RequestHandler
EM.run{
end
end
p [:request, headers, content]
def receive_request headers, content
class RequestHandler < EM::P::HeaderAndContentProtocol
=== Usage
def dispatch_request
def dispatch_request if respond_to?(:receive_request) receive_request @hc_headers, @hc_content end init_for_request end
def headers_2_hash hdrs
Basically a convenience method. We might create a subclass that does this
def headers_2_hash hdrs self.class.headers_2_hash hdrs end
def headers_2_hash hdrs
def headers_2_hash hdrs hash = {} hdrs.each {|h| if /\A([^\s:]+)\s*:\s*/ =~ h tail = $'.dup hash[ $1.downcase.gsub(/-/,"_").intern ] = tail end } hash end
def init_for_request
def init_for_request @hc_mode = :discard_blanks @hc_headers = [] # originally was @hc_headers ||= []; @hc_headers.clear to get a performance # boost, but it's counterproductive because a subclassed handler will have to # call dup to use the header array we pass in receive_headers. @hc_content_length = nil @hc_content = "" end
def initialize *args
def initialize *args super init_for_request end
def receive_binary_data text
def receive_binary_data text @hc_content = text dispatch_request end
def receive_line line
def receive_line line case @hc_mode when :discard_blanks unless line == "" @hc_mode = :headers receive_line line end when :headers if line == "" raise "unrecognized state" unless @hc_headers.length > 0 if respond_to?(:receive_headers) receive_headers @hc_headers end # @hc_content_length will be nil, not 0, if there was no content-length header. if @hc_content_length.to_i > 0 set_binary_mode @hc_content_length else dispatch_request end else @hc_headers << line if ContentLengthPattern =~ line # There are some attacks that rely on sending multiple content-length # headers. This is a crude protection, but needs to become tunable. raise "extraneous content-length header" if @hc_content_length @hc_content_length = $1.to_i end if @hc_headers.length == 1 and respond_to?(:receive_first_header_line) receive_first_header_line line end end else raise "internal error, unsupported mode" end end