123456789_123456789_123456789_123456789_123456789_

Class: Net::HTTP

Relationships & Source Files
Namespace Children
Modules:
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Protocol
Instance Chain:
self, Protocol
Inherits: Protocol
  • Object
Defined in: lib/net/http.rb,
lib/net/http/backward.rb

Overview

Class Net::HTTP provides a rich library that implements the client in a client-server model that uses the HTTP request-response protocol. For information about HTTP, see

Note: If you are performing only a few GET requests, consider using OpenURI; otherwise, read on.

Synopsis

If you are already familiar with HTTP, this synopsis may be helpful.

Session with multiple requests for HTTP methods:

Net::HTTP.start(hostname) do |http|
  # Session started automatically before block execution.

http.get(path_or_uri, headers = {}) http.head(path_or_uri, headers = {}) http.post(path_or_uri, data, headers = {}) # Can also have a block. http.put(path_or_uri, data, headers = {}) http.delete(path_or_uri, headers = ‘Infinity’) http.options(path_or_uri, headers = {}) http.trace(path_or_uri, headers = {}) http.patch(path_or_uri, data, headers = {}) # Can also have a block.

  # Session finished automatically at block exit.
end

Session with multiple requests for WebDAV methods:

Net::HTTP.start(hostname) do |http|
  # Session started automatically before block execution.

http.copy(path_or_uri, headers = {}) http.lock(path_or_uri, body, headers = {}) http.mkcol(path_or_uri, body = nil, headers = {}) http.move(path_or_uri, headers = {}) http.propfind(path_or_uri, body = nil, headers = => ‘0’) http.proppatch(path_or_uri, body, headers = {}) http.unlock(path_or_uri, body, headers = {})

  # Session finished automatically at block exit.
end

Each of the following methods automatically starts and finishes a session that sends a single request:

# Return string response body.
Net::HTTP.get(hostname, path, port = 80)
Net::HTTP.get(uri, headers = {}, port = 80)

# Write string response body to $stdout.
Net::HTTP.get_print(hostname, path_or_uri, port = 80)
Net::HTTP.get_print(uri, headers = {}, port = 80)

# Return response as Net::HTTPResponse object.
Net::HTTP.get_response(hostname, path_or_uri, port = 80)
Net::HTTP.get_response(uri, headers = {}, port = 80)

Net::HTTP.post(uri, data, headers = {})
Net::HTTP.post_form(uri, params)

About the Examples

Examples here assume that net/http has been required (which also requires uri):

require 'net/http'

Many code examples here use these example websites:

Some examples also assume these variables:

uri = URI('https://jsonplaceholder.typicode.com')
uri.freeze # Examples may not modify.
hostname = uri.hostname # => "jsonplaceholder.typicode.com"
port = uri.port         # => 443

So that example requests may be written as:

Net::HTTP.get(uri)
Net::HTTP.get(hostname, '/index.html')
Net::HTTP.start(hostname) do |http|

http.get(‘/todos/1’) http.get(‘/todos/2’)

end

An example that needs a modified URI first duplicates uri, then modifies the duplicate:

_uri = uri.dup
_uri.path = '/todos/1'

URIs

On the internet, a URI (Universal Resource Identifier) is a string that identifies a particular resource. It consists of some or all of: scheme, hostname, path, query, and fragment; see URI syntax.

A Ruby URI::Generic object represents an internet URI. It provides, among others, methods scheme, hostname, path, query, and fragment.

Schemes

An internet URI has a scheme.

The two schemes supported in Net::HTTP are 'https' and 'http':

uri.scheme                       # => "https"
URI('http://example.com').scheme # => "http"

Hostnames

A hostname identifies a server (host) to which requests may be sent:

hostname = uri.hostname # => "jsonplaceholder.typicode.com"
Net::HTTP.start(hostname) do |http|
  # Some HTTP stuff.
end

Paths

A host-specific path identifies a resource on the host:

_uri = uri.dup
_uri.path = '/todos/1'
hostname = _uri.hostname
path = _uri.path
Net::HTTP.get(hostname, path)

Queries

A host-specific query adds name/value pairs to the URI:

_uri = uri.dup
params = {userId: 1, completed: false}
_uri.query = URI.encode_www_form(params)
_uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com?userId=1&completed=false>
Net::HTTP.get(_uri)

Fragments

A URI fragment has no effect in Net::HTTP; the same data is returned, regardless of whether a fragment is included.

Request Headers

Request headers may be used to pass additional information to the host, similar to arguments passed in a method call; each header is a name/value pair.

Each of the Net::HTTP methods that sends a request to the host has optional argument headers, where the headers are expressed as a hash of field-name/value pairs:

headers = {Accept: 'application/json', Connection: 'Keep-Alive'}
Net::HTTP.get(uri, headers)

See lists of both standard request fields and common request fields at Request Fields. A host may also accept other custom fields.

Sessions

A session is a connection between a server (host) and a client that:

  • Is begun by instance method #start.

  • May contain any number of requests.

  • Is ended by instance method #finish.

See example sessions at the Synopsis.

Session Using Net::HTTP.start

If you have many requests to make to a single host (and port), consider using singleton method .start with a block; the method handles the session automatically by:

  • Calling #start before block execution.

  • Executing the block.

  • Calling #finish after block execution.

In the block, you can use these instance methods, each of which that sends a single request:

  • HTTP methods:

    • #get, #request_get: GET.

    • #head, #request_head: HEAD.

    • #post, #request_post: POST.

    • #delete: DELETE.

    • #options: OPTIONS.

    • #trace: TRACE.

    • #patch: PATCH.

  • WebDAV methods:

    • #copy: COPY.

    • #lock: LOCK.

    • #mkcol: MKCOL.

    • #move: MOVE.

    • #propfind: PROPFIND.

    • #proppatch: PROPPATCH.

    • #unlock: UNLOCK.

Session Using Net::HTTP.start and Net::HTTP.finish

You can manage a session manually using methods #start and #finish:

http = HTTP.new(hostname) http.start http.get(‘/todos/1’) http.get(‘/todos/2’) http.delete(‘/posts/1’) http.finish # Needed to free resources.

Single-Request Session

Certain convenience methods automatically handle a session by:

  • Creating an HTTP object

  • Starting a session.

  • Sending a single request.

  • Finishing the session.

  • Destroying the object.

Such methods that send GET requests:

Such methods that send POST requests:

HTTP Requests and Responses

Many of the methods above are convenience methods, each of which sends a request and returns a string without directly using Net::HTTPRequest and Net::HTTPResponse objects.

You can, however, directly create a request object, send the request, and retrieve the response object; see:

Following Redirection

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

For example, all 2XX responses are instances of a HTTPSuccess subclass, a 3XX response is an instance of a HTTPRedirection subclass and a 200 response is an instance of the 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')

Basic Authentication

Basic authentication is performed according to RFC2617.

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

req = Net::HTTP::Get.new(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 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

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 #use_ssl=.

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

Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
  request = Net::HTTP::Get.new uri
  response = http.request request # Net::HTTPResponse object
end

Or if you simply want to make a GET request, you may pass in an URI object that has an HTTPS URL. HTTP automatically turns on TLS verification if the URI object has a ‘https’ URI scheme.

uri = URI('https://example.com/')
Net::HTTP.get(uri) # => String

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

Proxies

HTTP will automatically create a proxy from the http_proxy environment variable if it is present. To disable use of http_proxy, pass nil for the proxy address.

You may also create a custom proxy:

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

Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
  # always proxy via your.proxy.addr:8080
}

See .new for further details and examples such as proxies that require a username and password.

Compression

HTTP automatically adds Accept-Encoding for compression of response bodies and automatically decompresses gzip and deflate responses unless a Range header was sent.

Compression can be disabled through the Accept-Encoding: identity header.

Constant Summary

  • HTTPVersion =
    # File 'lib/net/http.rb', line 384
    '1.1'
  • IDEMPOTENT_METHODS_ = Internal use only
    # File 'lib/net/http.rb', line 1847
    %w/GET HEAD PUT DELETE OPTIONS TRACE/
  • ProxyMod = Internal use only
    # File 'lib/net/http/backward.rb', line 7
    ProxyDelta
  • Revision =
    # File 'lib/net/http.rb', line 383
    %q$Revision$.split[1]
  • SSL_ATTRIBUTES =
    # File 'lib/net/http.rb', line 1143
    [
      :ca_file,
      :ca_path,
      :cert,
      :cert_store,
      :ciphers,
      :extra_chain_cert,
      :key,
      :ssl_timeout,
      :ssl_version,
      :min_version,
      :max_version,
      :verify_callback,
      :verify_depth,
      :verify_mode,
      :verify_hostname,
    ]
  • SSL_IVNAMES =
    # File 'lib/net/http.rb', line 1126
    [
      :@ca_file,
      :@ca_path,
      :@cert,
      :@cert_store,
      :@ciphers,
      :@extra_chain_cert,
      :@key,
      :@ssl_timeout,
      :@ssl_version,
      :@min_version,
      :@max_version,
      :@verify_callback,
      :@verify_depth,
      :@verify_mode,
      :@verify_hostname,
    ]
  • STATUS_CODES =
    # File 'lib/net/http/status.rb', line 22
    {
      100 => 'Continue',
      101 => 'Switching Protocols',
      102 => 'Processing',
      103 => 'Early Hints',
      200 => 'OK',
      201 => 'Created',
      202 => 'Accepted',
      203 => 'Non-Authoritative Information',
      204 => 'No Content',
      205 => 'Reset Content',
      206 => 'Partial Content',
      207 => 'Multi-Status',
      208 => 'Already Reported',
      226 => 'IM Used',
      300 => 'Multiple Choices',
      301 => 'Moved Permanently',
      302 => 'Found',
      303 => 'See Other',
      304 => 'Not Modified',
      305 => 'Use Proxy',
      307 => 'Temporary Redirect',
      308 => 'Permanent Redirect',
      400 => 'Bad Request',
      401 => 'Unauthorized',
      402 => 'Payment Required',
      403 => 'Forbidden',
      404 => 'Not Found',
      405 => 'Method Not Allowed',
      406 => 'Not Acceptable',
      407 => 'Proxy Authentication Required',
      408 => 'Request Timeout',
      409 => 'Conflict',
      410 => 'Gone',
      411 => 'Length Required',
      412 => 'Precondition Failed',
      413 => 'Payload Too Large',
      414 => 'URI Too Long',
      415 => 'Unsupported Media Type',
      416 => 'Range Not Satisfiable',
      417 => 'Expectation Failed',
      421 => 'Misdirected Request',
      422 => 'Unprocessable Entity',
      423 => 'Locked',
      424 => 'Failed Dependency',
      426 => 'Upgrade Required',
      428 => 'Precondition Required',
      429 => 'Too Many Requests',
      431 => 'Request Header Fields Too Large',
      451 => 'Unavailable For Legal Reasons',
      500 => 'Internal Server Error',
      501 => 'Not Implemented',
      502 => 'Bad Gateway',
      503 => 'Service Unavailable',
      504 => 'Gateway Timeout',
      505 => 'HTTP Version Not Supported',
      506 => 'Variant Also Negotiates',
      507 => 'Insufficient Storage',
      508 => 'Loop Detected',
      510 => 'Not Extended',
      511 => 'Network Authentication Required',
    }
  • VERSION =
    # File 'lib/net/http.rb', line 382
    "0.3.2"

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil) ⇒ HTTP

Returns a new HTTP object http (but does not open a TCP connection or HTTP session).

No Proxy

With only string argument hostname given (and ENV['http_proxy'] undefined or nil), the returned http:

  • Has the given address.

  • Has the default port number, .default_port (80).

  • Has no proxy.

Example:

http = HTTP.new(hostname)

# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>

http.address # => “jsonplaceholder.typicode.com” http.port # => 80 http.proxy? # => false

With integer argument #port also given, the returned http has the given port:

http = HTTP.new(hostname, 8000)

# => #<Net::HTTP jsonplaceholder.typicode.com:8000 open=false>

http.port # => 8000

Proxy Using Argument p_addr as a String

When argument p_addr is a string hostname, the returned http has a proxy:

http = HTTP.new(hostname, nil, ‘proxy.example’)

# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>

http.proxy? # => true http.proxy_address # => “proxy.example”

# These use default values.

http.proxy_port # => 80 http.proxy_user # => nil http.proxy_pass # => nil

The port, username, and password for the proxy may also be given:

http = HTTP.new(hostname, nil, ‘proxy.example’, 8000, ‘pname’, ‘ppass’)

# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>

http.proxy? # => true http.proxy_address # => “proxy.example” http.proxy_port # => 8000 http.proxy_user # => “pname” http.proxy_pass # => “ppass”

Proxy Using ENV['http_proxy']

When environment variable 'http_proxy' is set to a URI string, the returned http will have that URI as its proxy; note that the URI string must have a protocol such as 'http' or 'https':

ENV['http_proxy'] = 'http://example.com'
# => "http://example.com"

http = HTTP.new(hostname)

# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>

http.proxy? # => true http.address # => “jsonplaceholder.typicode.com” http.proxy_address # => “example.com”

The URI string may include proxy username, password, and port number:

ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
# => "http://pname:ppass@example.com:8000"

http = HTTP.new(hostname)

# => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>

http.proxy_port # => 8000 http.proxy_user # => “pname” http.proxy_pass # => “ppass”

Argument p_no_proxy

You can use argument p_no_proxy to reject certain proxies:

  • Reject a certain address:

http = HTTP.new(‘example.com’, nil, ‘proxy.example’, 8000, ‘pname’, ‘ppass’, ‘proxy.example’) http.proxy_address # => nil

  • Reject certain domains or subdomains:

http = HTTP.new(‘example.com’, nil, ‘my.proxy.example’, 8000, ‘pname’, ‘ppass’, ‘proxy.example’) http.proxy_address # => nil

  • Reject certain addresses and port combinations:

http = HTTP.new(‘example.com’, nil, ‘proxy.example’, 8000, ‘pname’, ‘ppass’, ‘proxy.example:1234’) http.proxy_address # => “proxy.example”

http = HTTP.new(‘example.com’, nil, ‘proxy.example’, 8000, ‘pname’, ‘ppass’, ‘proxy.example:8000’) http.proxy_address # => nil

  • Reject a list of the types above delimited using a comma:

http = HTTP.new(‘example.com’, nil, ‘proxy.example’, 8000, ‘pname’, ‘ppass’, ‘my.proxy,proxy.example:8000’) http.proxy_address # => nil

http = HTTP.new(‘example.com’, nil, ‘my.proxy’, 8000, ‘pname’, ‘ppass’, ‘my.proxy,proxy.example:8000’) http.proxy_address # => nil

[ GitHub ]

  
# File 'lib/net/http.rb', line 802

def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
  http = super address, port

  if proxy_class? then # from Net::HTTP::Proxy()
    http.proxy_from_env = @proxy_from_env
    http.proxy_address  = @proxy_address
    http.proxy_port     = @proxy_port
    http.proxy_user     = @proxy_user
    http.proxy_pass     = @proxy_pass
  elsif p_addr == :ENV then
    http.proxy_from_env = true
  else
    if p_addr && p_no_proxy && !URI::Generic.use_proxy?(p_addr, p_addr, p_port, p_no_proxy)
      p_addr = nil
      p_port = nil
    end
    http.proxy_address = p_addr
    http.proxy_port    = p_port || default_port
    http.proxy_user    = p_user
    http.proxy_pass    = p_pass
  end

  http
end

#initialize(address, port = nil) ⇒ HTTP

Creates a new HTTP object for the specified server address, without opening the TCP connection or initializing the HTTP session. The #address should be a DNS hostname or IP address.

[ GitHub ]

  
# File 'lib/net/http.rb', line 830

def initialize(address, port = nil)
  @address = address
  @port    = (port || HTTP.default_port)
  @ipaddr = nil
  @local_host = nil
  @local_port = nil
  @curr_http_version = HTTPVersion
  @keep_alive_timeout = 2
  @last_communicated = nil
  @close_on_empty_response = false
  @socket  = nil
  @started = false
  @open_timeout = 60
  @read_timeout = 60
  @write_timeout = 60
  @continue_timeout = nil
  @max_retries = 1
  @debug_output = nil
  @response_body_encoding = false
  @ignore_eof = true

  @proxy_from_env = false
  @proxy_uri      = nil
  @proxy_address  = nil
  @proxy_port     = nil
  @proxy_user     = nil
  @proxy_pass     = nil

  @use_ssl = false
  @ssl_context = nil
  @ssl_session = nil
  @sspi_enabled = false
  SSL_IVNAMES.each do |ivname|
    instance_variable_set ivname, nil
  end
end

Class Attribute Details

.is_version_1_1? (readonly)

This method is for internal use only.

Alias for .version_1_1?.

[ GitHub ]

  
# File 'lib/net/http.rb', line 409

alias is_version_1_1? version_1_1?   #:nodoc:

.is_version_1_2? (readonly)

This method is for internal use only.

Alias for .version_1_2?.

[ GitHub ]

  
# File 'lib/net/http.rb', line 410

alias is_version_1_2? version_1_2?   #:nodoc:

.proxy_address (readonly)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1428

attr_reader :proxy_address

.proxy_class?Boolean (readonly)

returns true if self is a class which was created by HTTP::Proxy.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1423

def proxy_class?
  defined?(@is_proxy_class) ? @is_proxy_class : false
end

.proxy_pass (readonly)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1438

attr_reader :proxy_pass

.proxy_port (readonly)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1431

attr_reader :proxy_port

.proxy_user (readonly)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1434

attr_reader :proxy_user

.version_1_1?Boolean (readonly) Also known as: .is_version_1_1?

This method is for internal use only.

Returns false; retained for compatibility.

[ GitHub ]

  
# File 'lib/net/http.rb', line 404

def HTTP.version_1_1?  #:nodoc:
  false
end

.version_1_2 (readonly)

Returns true; retained for compatibility.

[ GitHub ]

  
# File 'lib/net/http.rb', line 394

def HTTP.version_1_2
  true
end

.version_1_2?Boolean (readonly) Also known as: .is_version_1_2?

Returns true; retained for compatibility.

[ GitHub ]

  
# File 'lib/net/http.rb', line 399

def HTTP.version_1_2?
  true
end

Class Method Details

.default_port

Returns intger 80, the default port to use for HTTP requests:

Net::HTTP.default_port # => 80
[ GitHub ]

  
# File 'lib/net/http.rb', line 558

def HTTP.default_port
  http_default_port()
end

.get(hostname, path, port = 80) ⇒ body Net::HTTPbody

Sends a GET request and returns the HTTP response body as a string.

With string arguments hostname and path:

hostname = 'jsonplaceholder.typicode.com'
path = '/todos/1'
puts Net::HTTP.get(hostname, path)

Output:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

With URI object uri and optional hash argument headers:

uri = URI('https://jsonplaceholder.typicode.com/todos/1')
headers = {'Content-type' => 'application/json; charset=UTF-8'}
Net::HTTP.get(uri, headers)

Related:

  • HTTP::Get: request class for HTTP method GET.

  • #get: convenience method for HTTP method GET.

[ GitHub ]

  
# File 'lib/net/http.rb', line 460

def HTTP.get(uri_or_host, path_or_headers = nil, port = nil)
  get_response(uri_or_host, path_or_headers, port).body
end

.get_print(hostname, path, port = 80) ⇒ nil Net::HTTPnil

Like .get, but writes the returned body to $stdout; returns nil.

[ GitHub ]

  
# File 'lib/net/http.rb', line 419

def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
  get_response(uri_or_host, path_or_headers, port) {|res|
    res.read_body do |chunk|
      $stdout.print chunk
    end
  }
  nil
end

.get_response(hostname, path, port = 80) ⇒ HTTP Net::HTTPHTTP

Like .get, but returns a HTTPResponse object instead of the body string.

[ GitHub ]

  
# File 'lib/net/http.rb', line 470

def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
  if path_or_headers && !path_or_headers.is_a?(Hash)
    host = uri_or_host
    path = path_or_headers
    new(host, port || HTTP.default_port).start {|http|
      return http.request_get(path, &block)
    }
  else
    uri = uri_or_host
    headers = path_or_headers
    start(uri.hostname, uri.port,
          :use_ssl => uri.scheme == 'https') {|http|
      return http.request_get(uri, headers, &block)
    }
  end
end

.http_default_port

Returns integer 80, the default port to use for HTTP requests:

Net::HTTP.http_default_port # => 80
[ GitHub ]

  
# File 'lib/net/http.rb', line 566

def HTTP.http_default_port
  80
end

.https_default_port

Returns integer 443, the default port to use for HTTPS requests:

Net::HTTP.https_default_port # => 443
[ GitHub ]

  
# File 'lib/net/http.rb', line 574

def HTTP.https_default_port
  443
end

.newobj

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http.rb', line 691

alias newobj new # :nodoc:

.post(url, data, header = nil)

Posts data to a host; returns a HTTPResponse object.

Argument url must be a URL; argument data must be a string:

_uri = uri.dup
_uri.path = '/posts'
data = '{"title": "foo", "body": "bar", "userId": 1}'
headers = {'content-type': 'application/json'}
res = Net::HTTP.post(_uri, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true>
puts res.body

Output:

{
  "title": "foo",
  "body": "bar",
  "userId": 1,
  "id": 101
}

Related:

  • HTTP::Post: request class for HTTP method POST.

  • #post: convenience method for HTTP method POST.

[ GitHub ]

  
# File 'lib/net/http.rb', line 513

def HTTP.post(url, data, header = nil)
  start(url.hostname, url.port,
        :use_ssl => url.scheme == 'https' ) {|http|
    http.post(url, data, header)
  }
end

.post_form(url, params)

Posts data to a host; returns a HTTPResponse object.

Argument url must be a URI; argument data must be a hash:

_uri = uri.dup
_uri.path = '/posts'
data = {title: 'foo', body: 'bar', userId: 1}
res = Net::HTTP.post_form(_uri, data) # => #<Net::HTTPCreated 201 Created readbody=true>
puts res.body

Output:

{
  "title": "foo",
  "body": "bar",
  "userId": "1",
  "id": 101
}
[ GitHub ]

  
# File 'lib/net/http.rb', line 540

def HTTP.post_form(url, params)
  req = Post.new(url)
  req.form_data = params
  req.basic_auth url.user, url.password if url.user
  start(url.hostname, url.port,
        :use_ssl => url.scheme == 'https' ) {|http|
    http.request(req)
  }
end

Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)

This method is for internal use only.

Creates an HTTP proxy class which behaves like HTTP, but performs all access via the specified proxy.

This class is obsolete. You may pass these same parameters directly to .new. See .new for details of the arguments.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1400

def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) #:nodoc:
  return self unless p_addr

  Class.new(self) {
    @is_proxy_class = true

    if p_addr == :ENV then
      @proxy_from_env = true
      @proxy_address = nil
      @proxy_port    = nil
    else
      @proxy_from_env = false
      @proxy_address = p_addr
      @proxy_port    = p_port || default_port
    end

    @proxy_user = p_user
    @proxy_pass = p_pass
  }
end

.socket_type

This method is for internal use only.

obsolete

[ GitHub ]

  
# File 'lib/net/http.rb', line 578

def HTTP.socket_type   #:nodoc: obsolete
  BufferedIO
end

.start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) ⇒ HTTP .start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) {|http| ... } ⇒ Object

Creates a new Net::HTTP object, http, via Net::HTTP.new:

Net::HTTP.new(address, port, p_addr, p_port, p_user, p_pass)
  • For arguments hostname through p_pass, see .new.

  • For argument opts, see below.

Note: If #port is nil and opts[:use_ssl] is a truthy value, the value passed to .new is .https_default_port, not #port.

With no block given:

  • Calls http.start with no block (see #start), which opens a TCP connection and HTTP session.

  • Returns http.

  • The caller should call #finish to close the session:

http = HTTP.start(hostname) http.started? # => true http.finish http.started? # => false

With a block given:

  • Calls http.start with the block (see #start), which:

    • Opens a TCP connection and HTTP session.

    • Calls the block, which may make any number of requests to the host.

    • Closes the HTTP session and TCP connection on block exit.

    • Returns the block’s value object.

  • Returns object.

Example:

hostname = 'jsonplaceholder.typicode.com'
Net::HTTP.start(hostname) do |http|
  puts http.get('/todos/1').body
  puts http.get('/todos/2').body
end

Output:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}
{
  "userId": 1,
  "id": 2,
  "title": "quis ut nam facilis et officia qui",
  "completed": false
}

If the last argument given is a hash, it is the opts hash, where each key is a method or accessor to be called, and its value is the value to be set.

The keys may include:

[ GitHub ]

  
# File 'lib/net/http.rb', line 668

def HTTP.start(address, *arg, &block) # :yield: http
  arg.pop if opt = Hash.try_convert(arg[-1])
  port, p_addr, p_port, p_user, p_pass = *arg
  p_addr = :ENV if arg.size < 2
  port = https_default_port if !port && opt && opt[:use_ssl]
  http = new(address, port, p_addr, p_port, p_user, p_pass)
  http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr]

  if opt
    if opt[:use_ssl]
      opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
    end
    http.methods.grep(/\A(\w+)=\z/) do |meth|
      key = $1.to_sym
      opt.key?(key) or next
      http.__send__(meth, opt[key])
    end
  end

  http.start(&block)
end

Instance Attribute Details

#active? (readonly)

This method is for internal use only.

Alias for #started?.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1105

alias active? started?   #:nodoc: obsolete

#address (readonly)

The DNS host name or IP address to connect to.

[ GitHub ]

  
# File 'lib/net/http.rb', line 931

attr_reader :address

#ca_file (rw)

Sets path of a CA certification file in PEM format.

The file can contain several CA certificates.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1164

attr_accessor :ca_file

#ca_path (rw)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1168

attr_accessor :ca_path

#cert (rw)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1172

attr_accessor :cert

#cert_store (rw)

Sets the X509::Store to verify peer certificate.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1175

attr_accessor :cert_store

#ciphers (rw)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1178

attr_accessor :ciphers

#close_on_empty_response (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1107

attr_accessor :close_on_empty_response

#continue_timeout (rw)

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. The default value is nil.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1082

attr_reader :continue_timeout

#continue_timeout=(sec) (rw)

Setter for the continue_timeout attribute.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1085

def continue_timeout=(sec)
  @socket.continue_timeout = sec if @socket
  @continue_timeout = sec
end

#extra_chain_cert (rw)

Sets the extra X509 certificates to be added to the certificate chain. See OpenSSL::SSL::SSLContext#extra_chain_cert=

[ GitHub ]

  
# File 'lib/net/http.rb', line 1182

attr_accessor :extra_chain_cert

#ignore_eof (rw)

Whether to ignore EOF when reading response bodies with defined Content-Length headers. For backwards compatibility, the default is true.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1098

attr_accessor :ignore_eof

#ipaddr (rw)

Returns the IP address for the connection.

If the session has not been started, returns the value set by #ipaddr=, or nil if it has not been set:

http = HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = ‘172.67.155.76’ http.ipaddr # => “172.67.155.76”

If the session has been started, returns the IP address from the socket:

http = HTTP.new(hostname) http.start http.ipaddr # => “172.67.155.76” http.finish

[ GitHub ]

  
# File 'lib/net/http.rb', line 995

def ipaddr
  started? ?  @socket.io.peeraddr[3] : @ipaddr
end

#ipaddr=(addr) (rw)

Sets the IP address for the connection:

http = HTTP.new(hostname) http.ipaddr # => nil http.ipaddr = ‘172.67.155.76’ http.ipaddr # => “172.67.155.76”

The IP address may not be set if the session has been started.

Raises:

  • (IOError)
[ GitHub ]

  
# File 'lib/net/http.rb', line 1007

def ipaddr=(addr)
  raise IOError, "ipaddr value changed, but session already started" if started?
  @ipaddr = addr
end

#keep_alive_timeout (rw)

Seconds to reuse the connection of the previous request. If the idle time is less than this Keep-Alive Timeout, HTTP reuses the TCP/IP socket used by the previous communication. The default value is 2 seconds.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1094

attr_accessor :keep_alive_timeout

#key (rw)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1186

attr_accessor :key

#local_host (rw)

The local host used to establish the connection.

[ GitHub ]

  
# File 'lib/net/http.rb', line 937

attr_accessor :local_host

#local_port (rw)

The local port used to establish the connection.

[ GitHub ]

  
# File 'lib/net/http.rb', line 940

attr_accessor :local_port

#max_retries (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1051

attr_reader :max_retries

#max_retries=(retries) (rw)

Sets the maximum number of times to retry an idempotent request in case of Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError, Timeout::Error. The initial value is 1.

Argument retries must be a non-negative numeric value:

http = HTTP.new(hostname) http.max_retries = 2 # => 2 http.max_retries # => 2

[ GitHub ]

  
# File 'lib/net/http.rb', line 1043

def max_retries=(retries)
  retries = retries.to_int
  if retries < 0
    raise ArgumentError, 'max_retries should be non-negative integer number'
  end
  @max_retries = retries
end

#max_version (rw)

Sets the maximum SSL version. See OpenSSL::SSL::SSLContext#max_version=

[ GitHub ]

  
# File 'lib/net/http.rb', line 1198

attr_accessor :max_version

#min_version (rw)

Sets the minimum SSL version. See OpenSSL::SSL::SSLContext#min_version=

[ GitHub ]

  
# File 'lib/net/http.rb', line 1195

attr_accessor :min_version

#open_timeout (rw)

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 Net::OpenTimeout exception. The default value is 60 seconds.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1016

attr_accessor :open_timeout

#port (readonly)

The port number to connect to.

[ GitHub ]

  
# File 'lib/net/http.rb', line 934

attr_reader :port

#proxy?Boolean (readonly)

True if requests for this connection will be proxied

[ GitHub ]

  
# File 'lib/net/http.rb', line 1442

def proxy?
  !!(@proxy_from_env ? proxy_uri : @proxy_address)
end

#proxy_address (rw) Also known as: #proxyaddr

The address of the proxy server, if one is configured.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1461

def proxy_address
  if @proxy_from_env then
    proxy_uri&.hostname
  else
    @proxy_address
  end
end

#proxy_address=(value) (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 971

attr_writer :proxy_address

#proxy_from_env=(value) (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 970

attr_writer :proxy_from_env

#proxy_from_env?Boolean (rw)

True if the proxy for this connection is determined from the environment

[ GitHub ]

  
# File 'lib/net/http.rb', line 1447

def proxy_from_env?
  @proxy_from_env
end

#proxy_pass (rw)

The password of the proxy server, if one is configured.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1489

def proxy_pass
  if @proxy_from_env
    pass = proxy_uri&.password
    unescape(pass) if pass
  else
    @proxy_pass
  end
end

#proxy_pass=(value) (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 974

attr_writer :proxy_pass

#proxy_port (rw) Also known as: #proxyport

The port of the proxy server, if one is configured.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1470

def proxy_port
  if @proxy_from_env then
    proxy_uri&.port
  else
    @proxy_port
  end
end

#proxy_port=(value) (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 972

attr_writer :proxy_port

#proxy_user (rw)

The username of the proxy server, if one is configured.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1479

def proxy_user
  if @proxy_from_env
    user = proxy_uri&.user
    unescape(user) if user
  else
    @proxy_user
  end
end

#proxy_user=(value) (rw)

[ GitHub ]

  
# File 'lib/net/http.rb', line 973

attr_writer :proxy_user

#proxyaddr (readonly)

This method is for internal use only.

Alias for #proxy_address.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1498

alias proxyaddr proxy_address   #:nodoc: obsolete

#proxyport (readonly)

This method is for internal use only.

Alias for #proxy_port.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1499

alias proxyport proxy_port      #:nodoc: obsolete

#read_timeout (rw)

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 Net::ReadTimeout exception. The default value is 60 seconds.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1022

attr_reader :read_timeout

#read_timeout=(sec) (rw)

Sets the read timeout, in seconds, for self to integer sec; the initial value is 60.

Argument sec must be a non-negative numeric value:

http = HTTP.new(hostname) http.read_timeout # => 60 http.get(‘/todos/1’) # => #<Net::HTTPOK 200 OK readbody=true> http.read_timeout = 0 http.get(‘/todos/1’) # Raises Net::ReadTimeout.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1064

def read_timeout=(sec)
  @socket.read_timeout = sec if @socket
  @read_timeout = sec
end

#response_body_encoding (rw)

The encoding to use for the response body. If Encoding, uses the specified encoding. If other true value, tries to detect the response body encoding.

[ GitHub ]

  
# File 'lib/net/http.rb', line 945

attr_reader :response_body_encoding

#response_body_encoding=(value) (rw)

Sets the encoding to be used for the response body; returns the encoding.

The given value may be:

  • An Encoding object.

  • The name of an encoding.

  • An alias for an encoding name.

See Encoding.

Examples:

http = HTTP.new(hostname) http.response_body_encoding = Encoding::US_ASCII # => #<Encoding:US-ASCII> http.response_body_encoding = ‘US-ASCII’ # => “US-ASCII” http.response_body_encoding = ‘ASCII’ # => “ASCII”

[ GitHub ]

  
# File 'lib/net/http.rb', line 965

def response_body_encoding=(value)
  value = Encoding.find(value) if value.is_a?(String)
  @response_body_encoding = value
end

#ssl_timeout (rw)

Sets the SSL timeout seconds.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1189

attr_accessor :ssl_timeout

#ssl_version (rw)

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

[ GitHub ]

  
# File 'lib/net/http.rb', line 1192

attr_accessor :ssl_version

#started?Boolean (readonly) Also known as: #active?

Returns true if the HTTP session has been started.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1101

def started?
  @started
end

#use_ssl=(flag) (rw)

Turn on/off SSL. This flag must be set before starting session. If you change use_ssl value after session started, a HTTP object raises IOError.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1118

def use_ssl=(flag)
  flag = flag ? true : false
  if started? and @use_ssl != flag
    raise IOError, "use_ssl value changed, but session already started"
  end
  @use_ssl = flag
end

#use_ssl?Boolean (rw)

Returns true if SSL/TLS is being used with HTTP.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1110

def use_ssl?
  @use_ssl
end

#verify_callback (rw)

Sets the verify callback for the server certification verification.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1201

attr_accessor :verify_callback

#verify_depth (rw)

Sets the maximum depth for the certificate chain verification.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1204

attr_accessor :verify_depth

#verify_hostname (rw)

Sets to check the server certificate is valid for the hostname. See OpenSSL::SSL::SSLContext#verify_hostname=

[ GitHub ]

  
# File 'lib/net/http.rb', line 1214

attr_accessor :verify_hostname

#verify_mode (rw)

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.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1210

attr_accessor :verify_mode

#write_timeout (rw)

Number of seconds to wait for one block to be written (via one write(2) call). Any number may be used, including Floats for fractional seconds. If the HTTP object cannot write data in this many seconds, it raises a Net::WriteTimeout exception. The default value is 60 seconds. Net::WriteTimeout is not raised on Windows.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1029

attr_reader :write_timeout

#write_timeout=(sec) (rw)

Sets the write timeout, in seconds, for self to integer sec; the initial value is 60.

Argument sec must be a non-negative numeric value.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1074

def write_timeout=(sec)
  @socket.write_timeout = sec if @socket
  @write_timeout = sec
end

Instance Method Details

#addr_port (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1984

def addr_port
  addr = address
  addr = "[#{addr}]" if addr.include?(":")
  default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port
  default_port == port ? addr : "#{addr}:#{port}"
end

#begin_transport(req) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1901

def begin_transport(req)
  if @socket.closed?
    connect
  elsif @last_communicated
    if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
      debug 'Conn close because of keep_alive_timeout'
      @socket.close
      connect
    elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
      debug "Conn close because of EOF"
      @socket.close
      connect
    end
  end

  if not req.response_body_permitted? and @close_on_empty_response
    req['connection'] ||= 'close'
  end

  req.update_uri address, port, use_ssl?
  req['host'] ||= addr_port()
end

#conn_address (private)

This method is for internal use only.

without proxy, obsolete

[ GitHub ]

  
# File 'lib/net/http.rb', line 1510

def conn_address # :nodoc:
  @ipaddr || address()
end

#conn_port (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http.rb', line 1514

def conn_port # :nodoc:
  port()
end

#connect (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1253

def connect
  if use_ssl?
    # reference early to load OpenSSL before connecting,
    # as OpenSSL may take time to load.
    @ssl_context = OpenSSL::SSL::SSLContext.new
  end

  if proxy? then
    conn_addr = proxy_address
    conn_port = proxy_port
  else
    conn_addr = conn_address
    conn_port = port
  end

  debug "opening connection to #{conn_addr}:#{conn_port}..."
  s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
    begin
      TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
    rescue => e
      raise e, "Failed to open TCP connection to " +
        "#{conn_addr}:#{conn_port} (#{e.message})"
    end
  }
  s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
  debug "opened"
  if use_ssl?
    if proxy?
      plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
                                  write_timeout: @write_timeout,
                                  continue_timeout: @continue_timeout,
                                  debug_output: @debug_output)
      buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n"
      buf << "Host: #{@address}:#{@port}\r\n"
      if proxy_user
        credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
        buf << "Proxy-Authorization: Basic #{credential}\r\n"
      end
      buf << "\r\n"
      plain_sock.write(buf)
      HTTPResponse.read_new(plain_sock).value
      # assuming nothing left in buffers after successful CONNECT response
    end

    ssl_parameters = Hash.new
    iv_list = instance_variables
    SSL_IVNAMES.each_with_index do |ivname, i|
      if iv_list.include?(ivname)
        value = instance_variable_get(ivname)
        unless value.nil?
          ssl_parameters[SSL_ATTRIBUTES[i]] = value
        end
      end
    end
    @ssl_context.set_params(ssl_parameters)
    unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
      @ssl_context.session_cache_mode =
          OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
              OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
    end
    if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
      @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
    end

    # Still do the post_connection_check below even if connecting
    # to IP address
    verify_hostname = @ssl_context.verify_hostname

    # Server Name Indication (SNI) RFC 3546/6066
    case @address
    when Resolv::IPv4::Regex, Resolv::IPv6::Regex
      # don't set SNI, as IP addresses in SNI is not valid
      # per RFC 6066, section 3.

      # Avoid openssl warning
      @ssl_context.verify_hostname = false
    else
      ssl_host_address = @address
    end

    debug "starting SSL for #{conn_addr}:#{conn_port}..."
    s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
    s.sync_close = true
    s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address

    if @ssl_session and
       Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
      s.session = @ssl_session
    end
    ssl_socket_connect(s, @open_timeout)
    if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
      s.post_connection_check(@address)
    end
    debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
  end
  @socket = BufferedIO.new(s, read_timeout: @read_timeout,
                           write_timeout: @write_timeout,
                           continue_timeout: @continue_timeout,
                           debug_output: @debug_output)
  @last_communicated = nil
  on_connect
rescue => exception
  if s
    debug "Conn close because of connect error #{exception}"
    s.close
  end
  raise
end

#copy(path, initheader = nil)

Sends a COPY request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1685

def copy(path, initheader = nil)
  request(Copy.new(path, initheader))
end

D(msg) (private)

Alias for #debug.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1998

alias_method :D, :debug

#debug(msg) (private) Also known as: #D

Adds a message to debugging output

[ GitHub ]

  
# File 'lib/net/http.rb', line 1992

def debug(msg)
  return unless @debug_output
  @debug_output << msg
  @debug_output << "\n"
end

#delete(path, initheader = {'Depth' => 'Infinity'})

Sends a DELETE request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1673

def delete(path, initheader = {'Depth' => 'Infinity'})
  request(Delete.new(path, initheader))
end

#do_finish (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1374

def do_finish
  @started = false
  @socket.close if @socket
  @socket = nil
end

#do_start (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1247

def do_start
  connect
  @started = true
end

#edit_path(path) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1518

def edit_path(path)
  if proxy?
    if path.start_with?("ftp://") || use_ssl?
      path
    else
      "http://#{addr_port}#{path}"
    end
  else
    path
  end
end

#end_transport(req, res) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1924

def end_transport(req, res)
  @curr_http_version = res.http_version
  @last_communicated = nil
  if @socket.closed?
    debug 'Conn socket closed'
  elsif not res.body and @close_on_empty_response
    debug 'Conn close'
    @socket.close
  elsif keep_alive?(req, res)
    debug 'Conn keep-alive'
    @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  else
    debug 'Conn close'
    @socket.close
  end
end

#finish

Finishes the HTTP session and closes the TCP connection. Raises IOError if the session has not been started.

Raises:

  • (IOError)
[ GitHub ]

  
# File 'lib/net/http.rb', line 1369

def finish
  raise IOError, 'HTTP session not yet started' unless started?
  do_finish
end

#get(path, initheader = nil, dest = nil, &block)

Retrieves data from path on the connected-to host which may be an absolute path String or a URI to extract the path from.

initheader must be a Hash like { ‘Accept’ => ‘/’, … }, and it defaults to an empty hash. If initheader doesn’t have the key ‘accept-encoding’, then a value of “gzip;q=1.0,deflate;q=0.6,identity;q=0.3” is used, so that gzip compression is used in preference to deflate compression, which is used in preference to no compression. Ruby doesn’t have libraries to support the compress (Lempel-Ziv) compression, so that is not supported. The intent of this is to reduce bandwidth by default. If this routine sets up compression, then it does the decompression also, removing the header as well to prevent confusion. Otherwise it leaves the body as it found it.

This method returns a HTTPResponse object.

If called with a block, yields each fragment of the entity body in turn as a string as it is read from the socket. Note that in this case, the returned response object will not contain a (meaningful) body.

dest argument is obsolete. It still works but you must not use it.

This method never raises an exception.

response = http.get('/index.html')

# using block
File.open('result.txt', 'w') {|f|

http.get(‘/~foo/’) do |str|

    f.write str
  end
}
[ GitHub ]

  
# File 'lib/net/http.rb', line 1573

def get(path, initheader = nil, dest = nil, &block) # :yield: body_segment
  res = nil
  request(Get.new(path, initheader)) {|r|
    r.read_body dest, &block
    res = r
  }
  res
end

#get2(path, initheader = nil, &block)

This method is for internal use only.

Alias for #request_get.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1778

alias get2   request_get    #:nodoc: obsolete

#head(path, initheader = nil)

Gets only the header from path on the connected-to host. header is a Hash like { ‘Accept’ => ‘/’, … }.

This method returns a HTTPResponse object.

This method never raises an exception.

response = nil
Net::HTTP.start('some.www.server', 80) {|http|
  response = http.head('/index.html')
}
p response['content-type']
[ GitHub ]

  
# File 'lib/net/http.rb', line 1595

def head(path, initheader = nil)
  request(Head.new(path, initheader))
end

#head2(path, initheader = nil, &block)

This method is for internal use only.

Alias for #request_head.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1779

alias head2  request_head   #:nodoc: obsolete

#inspect

Returns a string representation of self:

Net::HTTP.new(hostname).inspect
# => "#<Net::HTTP jsonplaceholder.typicode.com:80 open=false>"
[ GitHub ]

  
# File 'lib/net/http.rb', line 872

def inspect
  "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
end

#keep_alive?(req, res) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1941

def keep_alive?(req, res)
  return false if req.connection_close?
  if @curr_http_version <= '1.0'
    res.connection_keep_alive?
  else   # HTTP/1.1 or later
    not res.connection_close?
  end
end

#lock(path, body, initheader = nil)

Sends a LOCK request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1649

def lock(path, body, initheader = nil)
  request(Lock.new(path, initheader), body)
end

#mkcol(path, body = nil, initheader = nil)

Sends a MKCOL request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1691

def mkcol(path, body = nil, initheader = nil)
  request(Mkcol.new(path, initheader), body)
end

#move(path, initheader = nil)

Sends a MOVE request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1679

def move(path, initheader = nil)
  request(Move.new(path, initheader))
end

#on_connect (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1363

def on_connect
end

#options(path, initheader = nil)

Sends a OPTIONS request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1661

def options(path, initheader = nil)
  request(Options.new(path, initheader))
end

#patch(path, data, initheader = nil, dest = nil, &block)

Sends a PATCH request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1633

def patch(path, data, initheader = nil, dest = nil, &block) # :yield: body_segment
  send_entity(path, data, initheader, dest, Patch, &block)
end

#peer_cert

Returns the X.509 certificates the server presented.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1217

def peer_cert
  if not use_ssl? or not @socket
    return nil
  end
  @socket.io.peer_cert
end

#post(path, data, initheader = nil, dest = nil, &block)

Posts data (must be a String) to path. header must be a Hash like { ‘Accept’ => ‘/’, … }.

This method returns a HTTPResponse object.

If called with a block, yields each fragment of the entity body in turn as a string as it is read from the socket. Note that in this case, the returned response object will not contain a (meaningful) body.

dest argument is obsolete. It still works but you must not use it.

This method never raises exception.

response = http.post('/cgi-bin/search.rb', 'query=foo')

# using block
File.open('result.txt', 'w') {|f|

http.post(‘/cgi-bin/search.rb’, ‘query=foo’) do |str|

    f.write str
  end
}

You should set Content-Type: header field for POST. If no Content-Type: field given, this method uses “application/x-www-form-urlencoded” by default.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1627

def post(path, data, initheader = nil, dest = nil, &block) # :yield: body_segment
  send_entity(path, data, initheader, dest, Post, &block)
end

#post2(path, data, initheader = nil, &block)

This method is for internal use only.

Alias for #request_post.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1780

alias post2  request_post   #:nodoc: obsolete

#propfind(path, body = nil, initheader = {'Depth' => '0'})

Sends a PROPFIND request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1667

def propfind(path, body = nil, initheader = {'Depth' => '0'})
  request(Propfind.new(path, initheader), body)
end

#proppatch(path, body, initheader = nil)

Sends a PROPPATCH request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1643

def proppatch(path, body, initheader = nil)
  request(Proppatch.new(path, initheader), body)
end

#proxy_uri

This method is for internal use only.

The proxy URI determined from the environment for this connection.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1452

def proxy_uri # :nodoc:
  return if @proxy_uri == false
  @proxy_uri ||= URI::HTTP.new(
    "http".freeze, nil, address, port, nil, nil, nil, nil, nil
  ).find_proxy || false
  @proxy_uri || nil
end

#put(path, data, initheader = nil)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http.rb', line 1637

def put(path, data, initheader = nil)   #:nodoc:
  request(Put.new(path, initheader), data)
end

#put2(path, data, initheader = nil, &block)

This method is for internal use only.

Alias for #request_put.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1781

alias put2   request_put    #:nodoc: obsolete

#request(req, body = nil, &block)

Sends an HTTPRequest object req to the HTTP server.

If req is a HTTP::Post or HTTP::Put request containing data, the data is also sent. Providing data for a HTTP::Head or HTTP::Get request results in an ArgumentError.

Returns an HTTPResponse object.

When called with a block, passes an HTTPResponse object to the block. The body of the response will not have been read yet; the block can process it using HTTPResponse#read_body, if desired.

This method never raises Net.* exceptions.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1815

def request(req, body = nil, &block)  # :yield: response
  unless started?
    start {
      req['connection'] ||= 'close'
      return request(req, body, &block)
    }
  end
  if proxy_user()
    req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
  end
  req.set_body_internal body
  res = transport_request(req, &block)
  if sspi_auth?(res)
    sspi_auth(req)
    res = transport_request(req, &block)
  end
  res
end

#request_get(path, initheader = nil, &block) Also known as: #get2

Sends a GET request to the path. Returns the response as a HTTPResponse object.

When called with a block, passes an HTTPResponse object to the block. The body of the response will not have been read yet; the block can process it using HTTPResponse#read_body, if desired.

Returns the response.

This method never raises Net.* exceptions.

response = http.request_get('/index.html')
# The entity body is already read in this case.
p response['content-type']
puts response.body

# Using a block

http.request_get(‘/index.html’) {|response|

  p response['content-type']
  response.read_body do |str|   # read body now
    print str
  end
}
[ GitHub ]

  
# File 'lib/net/http.rb', line 1726

def request_get(path, initheader = nil, &block) # :yield: response
  request(Get.new(path, initheader), &block)
end

#request_head(path, initheader = nil, &block) Also known as: #head2

Sends a HEAD request to the path and returns the response as a HTTPResponse object.

Returns the response.

This method never raises Net.* exceptions.

response = http.request_head('/index.html')
p response['content-type']
[ GitHub ]

  
# File 'lib/net/http.rb', line 1740

def request_head(path, initheader = nil, &block)
  request(Head.new(path, initheader), &block)
end

#request_post(path, data, initheader = nil, &block) Also known as: #post2

Sends a POST request to the path.

Returns the response as a HTTPResponse object.

When called with a block, the block is passed an HTTPResponse object. The body of that response will not have been read yet; the block can process it using HTTPResponse#read_body, if desired.

Returns the response.

This method never raises Net.* exceptions.

# example
response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
p response.status
puts response.body          # body is already read in this case

# using block

http.request_post(‘/cgi-bin/nice.rb’, ‘datadatadata…’) {|response|

  p response.status
  p response['content-type']
  response.read_body do |str|   # read body now
    print str
  end
}
[ GitHub ]

  
# File 'lib/net/http.rb', line 1770

def request_post(path, data, initheader = nil, &block) # :yield: response
  request Post.new(path, initheader), data, &block
end

#request_put(path, data, initheader = nil, &block) Also known as: #put2

This method is for internal use only.
[ GitHub ]

  
# File 'lib/net/http.rb', line 1774

def request_put(path, data, initheader = nil, &block)   #:nodoc:
  request Put.new(path, initheader), data, &block
end

#send_entity(path, data, initheader, dest, type, &block) (private)

Executes a request which uses a representation and returns its body.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1838

def send_entity(path, data, initheader, dest, type, &block)
  res = nil
  request(type.new(path, initheader), data) {|r|
    r.read_body dest, &block
    res = r
  }
  res
end

#send_request(name, path, data = nil, header = nil)

Sends an HTTP request to the HTTP server. Also sends a DATA string if data is given.

Returns a HTTPResponse object.

This method never raises Net.* exceptions.

response = http.send_request('GET', '/index.html')
puts response.body
[ GitHub ]

  
# File 'lib/net/http.rb', line 1794

def send_request(name, path, data = nil, header = nil)
  has_response_body = name != 'HEAD'
  r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header)
  request r, data
end

#set_debug_output(output)

WARNING This method opens a serious security hole. Never use this method in production code.

Sets the output stream for debugging:

http = HTTP.new(hostname)

File.open('t.tmp', 'w') do |file|

http.set_debug_output(file) http.start http.get(‘/nosuch/1’) http.finish

end
puts File.read('t.tmp')

Output:

opening connection to jsonplaceholder.typicode.com:80...
opened
<- "GET /nosuch/1 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: jsonplaceholder.typicode.com\r\n\r\n"
#=> "HTTP/1.1 404 Not Found\r\n"
#=> "Date: Mon, 12 Dec 2022 21:14:11 GMT\r\n"
#=> "Content-Type: application/json; charset=utf-8\r\n"
#=> "Content-Length: 2\r\n"
#=> "Connection: keep-alive\r\n"
#=> "X-Powered-By: Express\r\n"
#=> "X-Ratelimit-Limit: 1000\r\n"
#=> "X-Ratelimit-Remaining: 999\r\n"
#=> "X-Ratelimit-Reset: 1670879660\r\n"
#=> "Vary: Origin, Accept-Encoding\r\n"
#=> "Access-Control-Allow-Credentials: true\r\n"
#=> "Cache-Control: max-age=43200\r\n"
#=> "Pragma: no-cache\r\n"
#=> "Expires: -1\r\n"
#=> "X-Content-Type-Options: nosniff\r\n"
#=> "Etag: W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"\r\n"
#=> "Via: 1.1 vegur\r\n"
#=> "CF-Cache-Status: MISS\r\n"
#=> "Server-Timing: cf-q-config;dur=1.3000000762986e-05\r\n"
#=> "Report-To: {\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yOr40jo%2BwS1KHzhTlVpl54beJ5Wx2FcG4gGV0XVrh3X9OlR5q4drUn2dkt5DGO4GDcE%2BVXT7CNgJvGs%2BZleIyMu8CLieFiDIvOviOY3EhHg94m0ZNZgrEdpKD0S85S507l1vsEwEHkoTm%2Ff19SiO\"}],\"group\":\"cf-nel\",\"max_age\":604800}\r\n"
#=> "NEL: {\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}\r\n"
#=> "Server: cloudflare\r\n"
#=> "CF-RAY: 778977dc484ce591-DFW\r\n"
#=> "alt-svc: h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400\r\n"
#=> "\r\n"
reading 2 bytes...
#=> "{}"
read 2 bytes
Conn keep-alive
[ GitHub ]

  
# File 'lib/net/http.rb', line 925

def set_debug_output(output)
  warn 'Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started?
  @debug_output = output
end

#sspi_auth(req) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1965

def sspi_auth(req)
  n = Win32::SSPI::NegotiateAuth.new
  req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
  # Some versions of ISA will close the connection if this isn't present.
  req["Connection"] = "Keep-Alive"
  req["Proxy-Connection"] = "Keep-Alive"
  res = transport_request(req)
  authphrase = res["Proxy-Authenticate"]  or return res
  req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
rescue => err
  raise HTTPAuthenticationError.new('HTTP authentication failed', err)
end

#sspi_auth?(res) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1950

def sspi_auth?(res)
  return false unless @sspi_enabled
  if res.kind_of?(HTTPProxyAuthenticationRequired) and
      proxy? and res["Proxy-Authenticate"].include?("Negotiate")
    begin
      require 'win32/sspi'
      true
    rescue LoadError
      false
    end
  else
    false
  end
end

#start

Opens a TCP connection and HTTP session.

When this method is called with a block, it passes the HTTP object to the block, and closes the TCP connection and HTTP session after the block has been executed.

When called with a block, it returns the return value of the block; otherwise, it returns self.

Raises:

  • (IOError)
[ GitHub ]

  
# File 'lib/net/http.rb', line 1233

def start  # :yield: http
  raise IOError, 'HTTP session already opened' if @started
  if block_given?
    begin
      do_start
      return yield(self)
    ensure
      do_finish
    end
  end
  do_start
  self
end

#trace(path, initheader = nil)

Sends a TRACE request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1697

def trace(path, initheader = nil)
  request(Trace.new(path, initheader))
end

#transport_request(req) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1849

def transport_request(req)
  count = 0
  begin
    begin_transport req
    res = catch(:response) {
      begin
        req.exec @socket, @curr_http_version, edit_path(req.path)
      rescue Errno::EPIPE
        # Failure when writing full request, but we can probably
        # still read the received response.
      end

      begin
        res = HTTPResponse.read_new(@socket)
        res.decode_content = req.decode_content
        res.body_encoding = @response_body_encoding
        res.ignore_eof = @ignore_eof
      end while res.kind_of?(HTTPInformation)

      res.uri = req.uri

      res
    }
    res.reading_body(@socket, req.response_body_permitted?) {
      yield res if block_given?
    }
  rescue Net::OpenTimeout
    raise
  rescue Net::ReadTimeout, IOError, EOFError,
         Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT,
         # avoid a dependency on OpenSSL
         defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
         Timeout::Error => exception
    if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
      count += 1
      @socket.close if @socket
      debug "Conn close because of error #{exception}, and retry"
      retry
    end
    debug "Conn close because of error #{exception}"
    @socket.close if @socket
    raise
  end

  end_transport req, res
  res
rescue => exception
  debug "Conn close because of error #{exception}"
  @socket.close if @socket
  raise exception
end

#unescape(value) (private)

[ GitHub ]

  
# File 'lib/net/http.rb', line 1503

def unescape(value)
  require 'cgi/util'
  CGI.unescape(value)
end

#unlock(path, body, initheader = nil)

Sends a UNLOCK request to the path and gets a response, as an HTTPResponse object.

[ GitHub ]

  
# File 'lib/net/http.rb', line 1655

def unlock(path, body, initheader = nil)
  request(Unlock.new(path, initheader), body)
end