Skip to content

Issuing Requests

Ilya Grigorik edited this page Oct 8, 2013 · 11 revisions

Getting Started

All requests must be dispatched from within the EventMachine run loop. If you need to stop EventMachine after your request has finished, you need to explicitly terminate the runloop by calling EM.stop – which is the pattern you will see in the following. Let’s do a simple GET request to google.com:

    EventMachine.run {
      http = EventMachine::HttpRequest.new('http://google.com/').get :query => {'keyname' => 'value'}

      http.errback { p 'Uh oh'; EM.stop }
      http.callback {
        p http.response_header.status
        p http.response_header
        p http.response

        EventMachine.stop
      }
    }

When you call HttpRequest.new(URL), em-http will resolve the destination of the URL (perform the DNS lookup and connect to the server). By default, no request is dispatched when you call new, only the connection is established. Then, we call .get on the connection to issue the request. In this case, .get does not specify a path and em-http will default to the path originally specified in the initializer. Note that we can customize the query string by passing in an arbitrary Ruby hash.

Once the request is dispatched, we setup a callback, and an errback – these functions will be called by EventMachine when the request is complete. Errback function is invoked only in the case of a failed connection such as a timeout or bad DNS hostname. As long as the connection is established, EventMachine will call the callback and pass you the returned http response.

Optionally, you can also specify stream and headers callbacks. When you specify a headers callback, once em-http successfully parses the HTTP header (and before any body data is processed), it will call your function with the hash of the response headers for you to inspect. Following that, if you specify a stream callback, then all data received by em-http after the headers will be passed in chunks to your function right as it arrives on the wire.

EventMachine.run do
  http = EventMachine::HttpRequest.new('http://google.com/').get

  http.headers { |hash|  p [:headers, hash] }
  http.stream  { |chunk| p [:data, chunk] }
end

Issuing GET / POST / HEAD / PUT / DELETE’s

    EventMachine.run {
      http = EventMachine::HttpRequest.new('http://google.com/').get
      http = EventMachine::HttpRequest.new('http://google.com/').post
      http = EventMachine::HttpRequest.new('http://google.com/').head
      http = EventMachine::HttpRequest.new('http://google.com/').put
      http = EventMachine::HttpRequest.new('http://google.com/').delete

      # ...
    }

Customizing Query Parameters

    EventMachine.run {
      http1 = EventMachine::HttpRequest.new('http://google.com/?q=paramA').get
      http2 = EventMachine::HttpRequest.new('http://google.com/?q=paramA').get :query => {'q2' => 'paramB'}
      http3 = EventMachine::HttpRequest.new('http://google.com/'?q=paramA).get :query => 'q2=paramB'
      # ...
    }

You can customize your request query string in a variety of ways:

  • pass it in directly as part of the URL
  • provide a ruby hash (which will be URL encoded for you)
  • provide a string
  • mix any of the above approaches: em-http will merge the parameters of your original URL with your custom parameters

Customizing Request Path

    EventMachine.run {
      http1 = EventMachine::HttpRequest.new('http://google.com/search').get
      http2 = EventMachine::HttpRequest.new('http://google.com/').get :path => '/search'
      # ...
    }

Both of the above approaches will result in the same request. If you’re wondering why em-http supports both.. hint: keep-alive & pipelining.

POSTing data

    EventMachine.run {
      http = EventMachine::HttpRequest.new('http://google.com/').post :body => "string"
      http = EventMachine::HttpRequest.new('http://google.com/').post :body => {:string => [:value1, :value2]}
      # ...
    }

If you provide a Ruby string, then make sure to specify the correct encoding headers such that the upstream servers knows how to parse your data. Alternatively, you can provide a Ruby hash, in which case em-http will form-encode the data for you, set it as the POST body, and set the proper form-encoding HTTP headers within the request.

Customizing Request Headers

    EventMachine.run {
      http = EventMachine::HttpRequest.new('http://google.com/').get :head => {"connection" => "close"}
      # ...
    }

You can specify your own custom HTTP headers by providing a ruby hash of key-value pairs to em-http.

Available connection & request parameters

Available connection specific settings with em-http:

    EventMachine.run {
      options = {
          :connect_timeout => 5,        # default connection setup timeout
          :inactivity_timeout => 10,    # default connection inactivity (post-setup) timeout

          :ssl => {
              :private_key_file => '/tmp/server.key',
              :cert_chain_file => '/tmp/server.crt',
              :verify_peer => false
          },

          :bind => {
              :host => '123.123.123.123',   # use a specific interface for outbound request
              :port => '123'
          }

          :proxy => {
              :host => '127.0.0.1',    # proxy address
              :port => 9000,           # proxy port
              :type => :socks5         # default proxy mode is HTTP proxy, change to :socks5 if required

              :authorization => ['user', 'pass']  # proxy authorization header
          }
      }

      http = EventMachine::HttpRequest.new('http://google.com/', options).get
      # ...
    }

Available request specific settings with em-http:

    EventMachine.run {
      connection_options = { ... }

      request_options = {
          :redirects => 5,              # follow 3XX redirects up to depth 5
          :keepalive => true,           # enable keep-alive (don't send Connection:close header)
          :file => 'path/to/file',      # stream data off disk through EM's fast file stream

          :path => '/string',           # request path (will override one in host)
          :query => 'key=val' || {},  # query string, can be passed as string or as a ruby hash
          :body => 'string' || {},      # string, or ruby hash (which will be form encoded)

          :head => {
              'authorization' => ['user', 'pass'] # basic auth will be automatically encoded
              'x-header' => 'string',   # list of request headers                
          }
      }

      http = EventMachine::HttpRequest.new('http://google.com/', connection_options).get request_options
      # ...
    }