Flowdock

An HTTP client API for Ruby.

Net::HTTP provides a rich library which can be used to build HTTP user-agents. For more details about HTTP see [RFC2616](http://www.ietf.org/rfc/rfc2616.txt)

Net::HTTP is designed to work closely with URI. URI::HTTP#host, URI::HTTP#port and URI::HTTP#request_uri are designed to work with Net::HTTP.

If you are only performing a few GET requests you should try OpenURI.

Simple Examples

All examples assume you have loaded Net::HTTP with:

require 'net/http'

This will also require ‘uri’ so you don’t need to require it separately.

The Net::HTTP methods in the following section do not persist connections. They are not recommended if you are performing many HTTP requests.

GET

Net::HTTP.get('example.com', '/index.html') # => String

GET by URI

uri = URI('http://example.com/index.html?count=10')
Net::HTTP.get(uri) # => String

GET with Dynamic Parameters

uri = URI('http://example.com/index.html')
params = { :limit => 10, :page => 3 }
uri.query = URI.encode_www_form(params)

res = Net::HTTP.get_response(uri)
puts res.body if res.is_a?(Net::HTTPSuccess)

POST

uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
puts res.body

POST with Multiple Values

uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
puts res.body

How to use Net::HTTP

The following example code can be used as the basis of a HTTP user-agent which can perform a variety of request types using persistent connections.

uri = URI('http://example.com/some_path?query=string')

Net::HTTP.start(uri.host, uri.port) do |http|
  request = Net::HTTP::Get.new uri.request_uri

  response = http.request request # Net::HTTPResponse object
end

Net::HTTP::start immediately creates a connection to an HTTP server which is kept open for the duration of the block. The connection will remain open for multiple requests in the block if the server indicates it supports persistent connections.

The request types Net::HTTP supports are listed below in the section “HTTP Request Classes”.

If you wish to re-use a connection across multiple HTTP requests without automatically closing it you can use ::new instead of ::start. #request will automatically open a connection to the server if one is not currently open. You can manually close the connection with #finish.

Response Data

uri = URI('http://example.com/index.html')
res = Net::HTTP.get_response(uri)

# Headers
res['Set-Cookie']            # => String
res.get_fields('set-cookie') # => Array
res.to_hash['set-cookie']    # => Array
puts "Headers: #{res.to_hash.inspect}"

# Status
puts res.code       # => '200'
puts res.message    # => 'OK'
puts res.class.name # => 'HTTPOK'

# Body
puts res.body if res.response_body_permitted?

Following Redirection

Each Net::HTTPResponse object belongs to a class for its response code.

For example, all 2XX responses are instances of a Net::HTTPSuccess subclass, a 3XX response is an instance of a Net::HTTPRedirection subclass and a 200 response is an instance of the Net::HTTPOK class. For details of response classes, see the section “HTTP Response Classes” below.

Using a case statement you can handle various types of responses properly:

def fetch(uri_str, limit = 10)
  # You should choose a better exception.
  raise ArgumentError, 'too many HTTP redirects' if limit == 0

  response = Net::HTTP.get_response(URI(uri_str))

  case response
  when Net::HTTPSuccess then
    response
  when Net::HTTPRedirection then
    location = response['location']
    warn "redirected to #{location}"
    fetch(location, limit - 1)
  else
    response.value
  end
end

print fetch('http://www.ruby-lang.org')

POST

A POST can be made using the Net::HTTP::Post request class. This example creates a urlencoded POST body:

uri = URI('http://www.example.com/todo.cgi')
req = Net::HTTP::Post.new(uri.path)
req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')

res = Net::HTTP.start(uri.hostname, uri.port) do |http|
  http.request(req)
end

case res
when Net::HTTPSuccess, Net::HTTPRedirection
  # OK
else
  res.value
end

At this time Net::HTTP does not support multipart/form-data. To send multipart/form-data use Net::HTTPRequest#body= and Net::HTTPRequest#content_type=:

req = Net::HTTP::Post.new(uri.path)
req.body = multipart_data
req.content_type = 'multipart/form-data'

Other requests that can contain a body such as PUT can be created in the same way using the corresponding request class (Net::HTTP::Put).

Setting Headers

The following example performs a conditional GET using the If-Modified-Since header. If the files has not been modified since the time in the header a Not Modified response will be returned. See RFC 2616 section 9.3 for further details.

uri = URI('http://example.com/cached_response')
file = File.stat 'cached_response'

req = Net::HTTP::Get.new(uri.request_uri)
req['If-Modified-Since'] = file.mtime.rfc2822

res = Net::HTTP.start(uri.hostname, uri.port) {|http|
  http.request(req)
}

open 'cached_response', 'w' do |io|
  io.write res.body
end if res.is_a?(Net::HTTPSuccess)

Basic Authentication

Basic authentication is performed according to [RFC2617](http://www.ietf.org/rfc/rfc2617.txt)

uri = URI('http://example.com/index.html?key=value')

req = Net::HTTP::Get.new(uri.request_uri)
req.basic_auth 'user', 'pass'

res = Net::HTTP.start(uri.hostname, uri.port) {|http|
  http.request(req)
}
puts res.body

Streaming Response Bodies

By default Net::HTTP reads an entire response into memory. If you are handling large files or wish to implement a progress bar you can instead stream the body directly to an IO.

uri = URI('http://example.com/large_file')

Net::HTTP.start(uri.host, uri.port) do |http|
  request = Net::HTTP::Get.new uri.request_uri

  http.request request do |response|
    open 'large_file', 'w' do |io|
      response.read_body do |chunk|
        io.write chunk
      end
    end
  end
end

HTTPS

HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.

uri = URI('https://secure.example.com/some_path?query=string')

Net::HTTP.start(uri.host, uri.port,
  :use_ssl => uri.scheme == 'https').start do |http|
  request = Net::HTTP::Get.new uri.request_uri

  response = http.request request # Net::HTTPResponse object
end

In previous versions of ruby you would need to require ‘net/https’ to use HTTPS. This is no longer true.

Proxies

Net::HTTP::Proxy has the same methods as Net::HTTP but its instances always connect via the proxy instead of directly to the given host.

proxy_addr = 'your.proxy.host'
proxy_port = 8080

Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
  # always connect to your.proxy.addr:8080
}

Net::HTTP::Proxy returns a Net::HTTP instance when proxy_addr is nil so there is no need for conditional code.

See Net::HTTP::Proxy for further details and examples such as proxies that require a username and password.

HTTP Request Classes

Here is the HTTP request class hierarchy.

HTTP Response Classes

Here is HTTP response class hierarchy. All classes are defined in Net module and are subclasses of Net::HTTPResponse.

HTTPUnknownResponse

For unhandled HTTP extensions

HTTPInformation

1xx

HTTPContinue

100

HTTPSwitchProtocol

101

HTTPSuccess

2xx

HTTPOK

200

HTTPCreated

201

HTTPAccepted

202

HTTPNonAuthoritativeInformation

203

HTTPNoContent

204

HTTPResetContent

205

HTTPPartialContent

206

HTTPRedirection

3xx

HTTPMultipleChoice

300

HTTPMovedPermanently

301

HTTPFound

302

HTTPSeeOther

303

HTTPNotModified

304

HTTPUseProxy

305

HTTPTemporaryRedirect

307

HTTPClientError

4xx

HTTPBadRequest

400

HTTPUnauthorized

401

HTTPPaymentRequired

402

HTTPForbidden

403

HTTPNotFound

404

HTTPMethodNotAllowed

405

HTTPNotAcceptable

406

HTTPProxyAuthenticationRequired

407

HTTPRequestTimeOut

408

HTTPConflict

409

HTTPGone

410

HTTPLengthRequired

411

HTTPPreconditionFailed

412

HTTPRequestEntityTooLarge

413

HTTPRequestURITooLong

414

HTTPUnsupportedMediaType

415

HTTPRequestedRangeNotSatisfiable

416

HTTPExpectationFailed

417

HTTPServerError

5xx

HTTPInternalServerError

500

HTTPNotImplemented

501

HTTPBadGateway

502

HTTPServiceUnavailable

503

HTTPGatewayTimeOut

504

HTTPVersionNotSupported

505

There is also the Net::HTTPBadResponse exception which is raised when there is a protocol error.

Aliases

  • HTTPSession

Constants

SSL_ATTRIBUTES = %w( ssl_version key cert ca_file ca_path cert_store ciphers verify_mode verify_callback verify_depth ssl_timeout )

Attributes

[R] proxy_pass

User password for accessing proxy. If Net::HTTP does not use a proxy, nil.

[R] proxy_user

User name for accessing proxy. If Net::HTTP does not use a proxy, nil.

[R] proxy_port

Port number of proxy host. If Net::HTTP does not use a proxy, nil.

[R] proxy_address

Address of proxy host. If Net::HTTP does not use a proxy, nil.

[RW] verify_mode

Sets the flags for server the certification verification at beginning of SSL/TLS session.

OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.

[RW] verify_depth

Sets the maximum depth for the certificate chain verification.

[RW] verify_callback

Sets the verify callback for the server certification verification.

[RW] ssl_version

Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version=

[RW] ssl_timeout

Sets the SSL timeout seconds.

[RW] key

Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object. (This method is appeared in Michal Rokos’s OpenSSL extension.)

[RW] ciphers

Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers=

[RW] cert_store

Sets the X509::Store to verify peer certificate.

[RW] cert

Sets an OpenSSL::X509::Certificate object as client certificate. (This method is appeared in Michal Rokos’s OpenSSL extension).

[RW] ca_path

Sets path of a CA certification directory containing certifications in PEM format.

[RW] ca_file

Sets path of a CA certification file in PEM format.

The file can contain several CA certificates.

[RW] close_on_empty_response
[R] continue_timeout

Seconds to wait for 100 Continue response. If the HTTP object does not receive a response in this many seconds it sends the request body.

[R] read_timeout

Number of seconds to wait for one block to be read (via one read(2) call). Any number may be used, including Floats for fractional seconds. If the HTTP object cannot read data in this many seconds, it raises a TimeoutError exception.

[RW] open_timeout

Number of seconds to wait for the connection to open. Any number may be used, including Floats for fractional seconds. If the HTTP object cannot open a connection in this many seconds, it raises a TimeoutError exception.

[R] port

The port number to connect to.

[R] address

The DNS host name or IP address to connect to.

Show files where this class is defined (1 file)
Register or log in to add new notes.
October 3, 2008
0 thanks

POST DATA

post data should be separed with ‘&’ and not ‘;’

your example

req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')

should be

req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, '&')

isnt it?

February 16, 2010
0 thanks

Re: POST DATA

The ampersand is more common, but the W3C recommends that all web servers support semicolon separators in the place of ampersand separators:

http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2

June 3, 2010
0 thanks

Testing Net:HTTP connections

You can use this excellent library to stub Net:HTTP connections in your automatic tests:

http://github.com/bblimke/webmock

April 4, 2013
0 thanks

HTTPS request

Hey, guys!

You have one mistake in example code.

uri = URI('https://secure.example.com/some_path?query=string')

Net::HTTP.start(uri.host, uri.port,
  :use_ssl => uri.scheme == 'https').start do |http|
  request = Net::HTTP::Get.new uri.request_uri

  response = http.request request
end

Here HTTP::start method called twice. This code should look like

Net::HTTP.start(uri.host, uri.port,
  :use_ssl => uri.scheme == 'https') do |http|
  request = Net::HTTP::Get.new uri.request_uri

  response = http.request request
end

It’s work - I checked.