lib/rev/http_client.rb in rev-0.1.4 vs lib/rev/http_client.rb in rev-0.2.0

- old
+ new

@@ -3,11 +3,10 @@ # Includes portions originally Copyright (C)2005 Zed Shaw # You can redistribute this under the terms of the Ruby license # See file LICENSE for details #++ -require File.dirname(__FILE__) + '/../rev' require File.dirname(__FILE__) + '/../http11_client' module Rev # A simple hash is returned for each request made by HttpClient with # the headers that were given by the server for that request. @@ -77,17 +76,17 @@ # redirects will tack on the :80 which is annoying. def encode_host remote_host + (remote_port.to_i != 80 ? ":#{remote_port}" : "") end - def encode_request(method, uri, query) - HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(uri, query)] + def encode_request(method, path, query) + HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(path, query)] end - def encode_query(uri, query) - return uri unless query - uri + "?" + query.map { |k, v| encode_param(k, v) }.join('&') + def encode_query(path, query) + return path unless query + path + "?" + query.map { |k, v| encode_param(k, v) }.join('&') end # URL encodes a single k=v parameter. def encode_param(k, v) escape(k) + "=" + escape(v) @@ -165,31 +164,25 @@ # Specify hash of cookies (auto-escaped) # # body: String # Specify the request body (you must encode it for now) # - def request(method, uri, options = {}) + def request(method, path, options = {}) + raise ArgumentError, "invalid request path" unless path[0] == '/' raise RuntimeError, "request already sent" if @requested - @method, @uri, @options = method, uri, options + @method, @path, @options = method, path, options @requested = true return unless @connected send_request end - - # Requests can be made through method missing by invoking the HTTP method to use, i.e.: - # - # httpclient.get(path, options) - # - # Valid for: get, post, put, delete, head - # - # To use other HTTP methods, invoke the request method directly - # - def method_missing(method, *args) - raise NoMethodError, "method not supported" unless ALLOWED_METHODS.include? method.to_sym - request method, *args + + # Enable the HttpClient if it has been disabled + def enable + super + dispatch unless @data.empty? end # Called when response header has been received def on_response_header(response_header) end @@ -203,26 +196,27 @@ # Called when the request has completed def on_request_complete close end - # Called when an error occurs during the request + # Called when an error occurs dispatching the request def on_error(reason) + close raise RuntimeError, reason end ######### protected ######### # # Rev callbacks # - + def on_connect @connected = true - send_request if @method and @uri + send_request if @method and @path end def on_read(data) @data << data dispatch @@ -254,11 +248,11 @@ # Default to Connection: close head['connection'] ||= 'close' # Build the request - request_header = encode_request(@method, @uri, query) + request_header = encode_request(@method, @path, query) request_header << encode_headers(head) request_header << encode_cookies(cookies) if cookies request_header << CRLF write request_header @@ -271,11 +265,11 @@ # # Response processing # def dispatch - while case @state + while enabled? and case @state when :response_header parse_response_header when :chunk_header parse_chunk_header when :chunk_body @@ -294,11 +288,17 @@ end def parse_header(header) return false if @data.empty? - @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes) + begin + @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes) + rescue Rev::HttpClientParserError + on_error "invalid HTTP format, parsing fails" + @state = :invalid + end + return false unless @parser.finished? # Clear parsed data from the buffer @data.read(@parser_nbytes) @parser.reset @@ -383,17 +383,20 @@ false end def process_body - # FIXME the proper thing to do here is probably to keep reading until - # the socket closes, then assume that's the end of the body, provided - # the server has specified Connection: close if @bytes_remaining.nil? - on_error "no content length specified" - @state = :invalid + on_body_data @data.read + return false end + + if @bytes_remaining.zero? + on_request_complete + @state = :finished + return false + end if @data.size < @bytes_remaining @bytes_remaining -= @data.size on_body_data @data.read return false @@ -411,6 +414,6 @@ end false end end -end \ No newline at end of file +end