Parent

EventMachine::HttpClient

Attributes

content_charset[R]
cookies[R]
error[R]
req[R]
response[RW]
response_header[R]
state[RW]

Public Class Methods

new(conn, options) click to toggle source
# File lib/em-http/client.rb, line 27
def initialize(conn, options)
  @conn = conn
  @req  = options

  @stream    = nil
  @headers   = nil
  @cookies   = []
  @cookiejar = CookieJar.new

  reset!
end

Public Instance Methods

build_request() click to toggle source
# File lib/em-http/client.rb, line 134
def build_request
  head    = @req.headers ? munge_header_keys(@req.headers) : {}
  
  if @conn.connopts.http_proxy?
    proxy = @conn.connopts.proxy
    head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization]
  end

  # Set the cookie header if provided
  if cookie = head['cookie']
    @cookies << encode_cookie(cookie) if cookie
  end
  head['cookie'] = @cookies.compact.uniq.join("; ").squeeze(";") unless @cookies.empty?

  # Set connection close unless keepalive
  if !@req.keepalive
    head['connection'] = 'close'
  end

  # Set the Host header if it hasn't been specified already
  head['host'] ||= encode_host

  # Set the User-Agent if it hasn't been specified
  head['user-agent'] ||= "EventMachine HttpClient"

  # Set the auth from the URI if given
  head['Authorization'] = @req.uri.userinfo.split(/:/, 2) if @req.uri.userinfo

  head
end
close(msg = nil) click to toggle source
Alias for: on_error
connection_completed() click to toggle source
# File lib/em-http/client.rb, line 53
def connection_completed
  @state = :response_header

  head, body = build_request, @req.body
  @conn.middleware.each do |m|
    head, body = m.request(self, head, body) if m.respond_to?(:request)
  end

  send_request(head, body)
end
continue?() click to toggle source
# File lib/em-http/client.rb, line 74
def continue?
  @response_header.status == 100 && (@req.method == 'POST' || @req.method == 'PUT')
end
finished?() click to toggle source
# File lib/em-http/client.rb, line 78
def finished?
  @state == :finished || (@state == :body && @response_header.content_length.nil?)
end
headers(&blk) click to toggle source
# File lib/em-http/client.rb, line 128
def headers(&blk); @headers = blk; end
last_effective_url() click to toggle source
# File lib/em-http/client.rb, line 49
def last_effective_url; @req.uri; end
normalize_body(body) click to toggle source
# File lib/em-http/client.rb, line 130
def normalize_body(body)
  body.is_a?(Hash) ? form_encode_body(body) : body
end
on_body_data(data) click to toggle source
# File lib/em-http/client.rb, line 199
def on_body_data(data)
  if @content_decoder
    begin
      @content_decoder << data
    rescue HttpDecoders::DecoderError
      on_error "Content-decoder error"
    end
  else
    on_decoded_body_data(data)
  end
end
on_decoded_body_data(data) click to toggle source
# File lib/em-http/client.rb, line 211
def on_decoded_body_data(data)
  data.force_encoding @content_charset if @content_charset
  if @stream
    @stream.call(data)
  else
    @response << data
  end
end
on_error(msg = nil) click to toggle source
# File lib/em-http/client.rb, line 121
def on_error(msg = nil)
  @error = msg
  fail(self)
end
Also aliased as: close
on_request_complete() click to toggle source
# File lib/em-http/client.rb, line 64
def on_request_complete
  begin
    @content_decoder.finalize! if @content_decoder
  rescue HttpDecoders::DecoderError
    on_error "Content-decoder error"
  end

  unbind
end
parse_response_header(header, version, status) click to toggle source
# File lib/em-http/client.rb, line 220
def parse_response_header(header, version, status)
  @response_header.raw = header
  header.each do |key, val|
    @response_header[key.upcase.gsub('-','_')] = val
  end

  @response_header.http_version = version.join('.')
  @response_header.http_status  = status
  @response_header.http_reason  = CODE[status] || 'unknown'

  # invoke headers callback after full parse
  # if one is specified by the user
  @headers.call(@response_header) if @headers

  unless @response_header.http_status and @response_header.http_reason
    @state = :invalid
    on_error "no HTTP response"
    return
  end

  # add set-cookie's to cookie list
  if @response_header.cookie && @req.pass_cookies
    [@response_header.cookie].flatten.each {|cookie| @cookiejar.set(cookie, @req.uri)}
  end

  # correct location header - some servers will incorrectly give a relative URI
  if @response_header.location
    begin
      location = Addressable::URI.parse(@response_header.location)

      if location.relative?
        location = @req.uri.join(location)
        @response_header[LOCATION] = location.to_s
      else
        # if redirect is to an absolute url, check for correct URI structure
        raise if location.host.nil?
      end

    rescue
      on_error "Location header format error"
      return
    end
  end

  # Fire callbacks immediately after recieving header requests
  # if the request method is HEAD. In case of a redirect, terminate
  # current connection and reinitialize the process.
  if @req.method == "HEAD"
    @state = :finished
    return
  end

  if @response_header.chunked_encoding?
    @state = :chunk_header
  elsif @response_header.content_length
    @state = :body
  else
    @state = :body
  end

  if @req.decoding && decoder_class = HttpDecoders.decoder_for_encoding(response_header[CONTENT_ENCODING])
    begin
      @content_decoder = decoder_class.new do |s| on_decoded_body_data(s) end
    rescue HttpDecoders::DecoderError
      on_error "Content-decoder error"
    end
  end

  # handle malformed header - Content-Type repetitions.
  content_type = [response_header[CONTENT_TYPE]].flatten.first

  if String.method_defined?(:force_encoding) && /;\s*charset=\s*(.+?)\s*(;|$)/.match(content_type)
    @content_charset = Encoding.find($1.gsub(/^\"|\"$/, '')) rescue Encoding.default_external
  end
end
peer() click to toggle source
# File lib/em-http/client.rb, line 51
def peer; @conn.peer; end
redirect?() click to toggle source
# File lib/em-http/client.rb, line 82
def redirect?
  @response_header.location && @req.follow_redirect?
end
redirects() click to toggle source
# File lib/em-http/client.rb, line 50
def redirects; @req.followed; end
reset!() click to toggle source
# File lib/em-http/client.rb, line 39
def reset!
  @response_header = HttpResponseHeader.new
  @state = :response_header

  @response = ''
  @error = nil
  @content_decoder = nil
  @content_charset = nil
end
send_request(head, body) click to toggle source
# File lib/em-http/client.rb, line 165
def send_request(head, body)
  body    = normalize_body(body)
  file    = @req.file
  query   = @req.query

  # Set the Content-Length if file is given
  head['content-length'] = File.size(file) if file

  # Set the Content-Length if body is given,
  # or we're doing an empty post or put
  if body
    head['content-length'] = body.bytesize
  elsif @req.method == 'POST' or @req.method == 'PUT'
    # wont happen if body is set and we already set content-length above
    head['content-length'] ||= 0
  end

  # Set content-type header if missing and body is a Ruby hash
  if not head['content-type'] and @req.body.is_a? Hash
    head['content-type'] = 'application/x-www-form-urlencoded'
  end

  request_header ||= encode_request(@req.method, @req.uri, query, @conn.connopts.proxy)
  request_header << encode_headers(head)
  request_header << CRLF
  @conn.send_data request_header

  if body
    @conn.send_data body
  elsif @req.file
    @conn.stream_file_data @req.file, :http_chunks => false
  end
end
stream(&blk) click to toggle source
# File lib/em-http/client.rb, line 127
def stream(&blk); @stream = blk; end
unbind(reason = nil) click to toggle source
# File lib/em-http/client.rb, line 86
def unbind(reason = nil)
  if finished?
    if redirect?

      begin
        @conn.middleware.each do |m|
          m.response(self) if m.respond_to?(:response)
        end

        # one of the injected middlewares could have changed
        # our redirect settings, check if we still want to
        # follow the location header
        if redirect?
          @req.followed += 1

          @cookies.clear
          @cookies = @cookiejar.get(@response_header.location).map(&:to_s) if @req.pass_cookies
          @req.set_uri(@response_header.location)
          @conn.redirect(self)
        else
          succeed(self)
        end

      rescue Exception => e
        on_error(e.message)
      end
    else
      succeed(self)
    end

  else
    on_error(reason)
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.