# frozen_string_literal: false
# Copyright (c) 1999-2007 Yukihiro Matsumoto
# Copyright (c) 1999-2007 Minero Aoki
# Copyright (c) 2001 GOTOU Yuuzou
# Written and maintained by Minero Aoki <aamine@loveruby.net>.
# HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
# This file is derived from "http-access.rb".
# Documented by Minero Aoki; converted to RDoc by William Webber.
# This program is free software. You can re-distribute and/or
# modify this program under the same terms of ruby itself ---
# Ruby Distribution License or GNU General Public License.
# See Net::HTTP for an overview and examples.
require_relative 'protocol'
autoload :OpenSSL, 'openssl'
class HTTPBadResponse < StandardError; end
class HTTPHeaderSyntaxError < StandardError; end
# == 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
# If you are only performing a few GET requests you should try OpenURI.
# All examples assume you have loaded Net::HTTP with:
# 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
# Net::HTTP.get('example.com', '/index.html') # => String
# 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)
# uri = URI('http://www.example.com/search.cgi')
# res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
# === POST with Multiple Values
# uri = URI('http://www.example.com/search.cgi')
# res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
# == How to use Net::HTTP
# The following example code can be used as the basis of an HTTP user-agent
# which can perform a variety of request types using persistent
# uri = URI('http://example.com/some_path?query=string')
# Net::HTTP.start(uri.host, uri.port) do |http|
# request = Net::HTTP::Get.new uri
# response = http.request request # Net::HTTPResponse object
# 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.
# If you wish to re-use a connection across multiple HTTP requests without
# automatically closing it you can use ::new and then call #start and
# The request types Net::HTTP supports are listed below in the section "HTTP
# For all the Net::HTTP request objects and shortcut request methods you may
# supply either a String for the request path or a URI from which Net::HTTP
# will extract the request path.
# uri = URI('http://example.com/index.html')
# res = Net::HTTP.get_response(uri)
# res['Set-Cookie'] # => String
# res.get_fields('set-cookie') # => Array
# res.to_hash['set-cookie'] # => Array
# puts "Headers: #{res.to_hash.inspect}"
# puts res.code # => '200'
# puts res.message # => 'OK'
# puts res.class.name # => 'HTTPOK'
# 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"
# 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))
# when Net::HTTPSuccess then
# when Net::HTTPRedirection then
# location = response['location']
# warn "redirected to #{location}"
# fetch(location, limit - 1)
# print fetch('http://www.ruby-lang.org')
# A POST can be made using the Net::HTTP::Post request class. This example
# creates a URL encoded POST body:
# uri = URI('http://www.example.com/todo.cgi')
# req = Net::HTTP::Post.new(uri)
# req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
# res = Net::HTTP.start(uri.hostname, uri.port) do |http|
# when Net::HTTPSuccess, Net::HTTPRedirection
# To send multipart/form-data use Net::HTTPHeader#set_form:
# req = Net::HTTP::Post.new(uri)
# req.set_form([['upload', File.open('foo.bar')]], '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).
# 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)
# req['If-Modified-Since'] = file.mtime.rfc2822
# res = Net::HTTP.start(uri.hostname, uri.port) {|http|
# open 'cached_response', 'w' do |io|
# 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)
# req.basic_auth 'user', 'pass'
# res = Net::HTTP.start(uri.hostname, uri.port) {|http|
# === 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
# http.request request do |response|
# open 'large_file', 'w' do |io|
# response.read_body do |chunk|
# 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 => true) do |http|
# request = Net::HTTP::Get.new uri
# response = http.request request # Net::HTTPResponse object
# Or if you simply want to make a GET request, you may pass in an URI
# object that has an HTTPS URL. Net::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.
# Net::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'
# Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
# # always proxy via your.proxy.addr:8080
# See Net::HTTP.new for further details and examples such as proxies that
# require a username and password.
# Net::HTTP automatically adds Accept-Encoding for compression of response
# bodies and automatically decompresses gzip and deflate responses unless a
# Compression can be disabled through the Accept-Encoding: identity header.
# == 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
# HTTPSwitchProtocol:: 101
# HTTPNonAuthoritativeInformation:: 203
# HTTPPartialContent:: 206
# HTTPMultipleChoices:: 300
# HTTPMovedPermanently:: 301
# HTTPTemporaryRedirect:: 307
# HTTPPaymentRequired:: 402
# HTTPMethodNotAllowed:: 405
# HTTPNotAcceptable:: 406
# HTTPProxyAuthenticationRequired:: 407
# HTTPRequestTimeOut:: 408
# HTTPLengthRequired:: 411
# HTTPPreconditionFailed:: 412
# HTTPRequestEntityTooLarge:: 413
# HTTPRequestURITooLong:: 414
# HTTPUnsupportedMediaType:: 415
# HTTPRequestedRangeNotSatisfiable:: 416
# HTTPExpectationFailed:: 417
# HTTPUnprocessableEntity:: 422
# HTTPFailedDependency:: 424
# HTTPUpgradeRequired:: 426
# HTTPPreconditionRequired:: 428
# HTTPTooManyRequests:: 429
# HTTPRequestHeaderFieldsTooLarge:: 431
# HTTPUnavailableForLegalReasons:: 451
# HTTPInternalServerError:: 500
# HTTPNotImplemented:: 501
# HTTPServiceUnavailable:: 503
# HTTPGatewayTimeOut:: 504
# HTTPVersionNotSupported:: 505
# HTTPInsufficientStorage:: 507
# HTTPNetworkAuthenticationRequired:: 511
# There is also the Net::HTTPBadResponse exception which is raised when
# there is a protocol error.
Revision = %q$Revision$.split[1]
require 'stringio' #for our purposes (unpacking gzip) lump these together
# Turns on net/http 1.2 (Ruby 1.8) features.
# Defaults to ON in Ruby 1.8 or later.
# Returns true if net/http is in version 1.2 mode.
def HTTP.version_1_1? #:nodoc:
alias is_version_1_1? version_1_1? #:nodoc:
alias is_version_1_2? version_1_2? #:nodoc:
# Gets the body text from the target and outputs it to $stdout. The
# target can either be specified as
# (+uri+), or as (+host+, +path+, +port+ = 80); so:
# Net::HTTP.get_print URI('http://www.example.com/index.html')
# Net::HTTP.get_print 'www.example.com', '/index.html'
def HTTP.get_print(uri_or_host, path = nil, port = nil)
get_response(uri_or_host, path, port) {|res|
# Sends a GET request to the target and returns the HTTP response
# as a string. The target can either be specified as
# (+uri+), or as (+host+, +path+, +port+ = 80); so:
# print Net::HTTP.get(URI('http://www.example.com/index.html'))
# print Net::HTTP.get('www.example.com', '/index.html')
def HTTP.get(uri_or_host, path = nil, port = nil)
get_response(uri_or_host, path, port).body
# Sends a GET request to the target and returns the HTTP response
# as a Net::HTTPResponse object. The target can either be specified as
# (+uri+), or as (+host+, +path+, +port+ = 80); so:
# res = Net::HTTP.get_response(URI('http://www.example.com/index.html'))
# res = Net::HTTP.get_response('www.example.com', '/index.html')
def HTTP.get_response(uri_or_host, path = nil, port = nil, &block)
new(host, port || HTTP.default_port).start {|http|
return http.request_get(path, &block)
start(uri.hostname, uri.port,
:use_ssl => uri.scheme == 'https') {|http|
return http.request_get(uri, &block)
# Posts data to the specified URI object.
# Net::HTTP.post URI('http://www.example.com/api/search'),
# { "q" => "ruby", "max" => "50" }.to_json,
# "Content-Type" => "application/json"
def HTTP.post(url, data, header = nil)
start(url.hostname, url.port,