1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

Add a lot of YARD docs to various classes.

Also switch to Markdown as the markup language, rather than rdoc.
This commit is contained in:
Andy Brody 2017-05-30 01:34:42 -04:00
parent 3001348c8a
commit f54f14398d
12 changed files with 403 additions and 128 deletions

View file

@ -1,3 +1,4 @@
--markup markdown
- -
history.md history.md
LICENSE LICENSE

View file

@ -123,3 +123,8 @@ end
require 'yard' require 'yard'
YARD::Rake::YardocTask.new do |t| YARD::Rake::YardocTask.new do |t|
end end
desc 'Run YARD documentation server, reload with changes'
task :yardserver do
sh 'yard server --reload'
end

View file

@ -18,47 +18,88 @@ require File.dirname(__FILE__) + '/restclient/windows'
# This module's static methods are the entry point for using the REST client. # This module's static methods are the entry point for using the REST client.
# #
# # GET # These helpers provide a concise way to issue simple requests with headers. If
# xml = RestClient.get 'http://example.com/resource' # you need to set other options on a request (e.g. timeout, SSL options, etc.)
# jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg' # then use {RestClient::Request.execute}, which supports all of these options.
# #
# # authentication and SSL # The {.get}, {.head}, {.delete}, and {.options} methods take a URL String and
# RestClient.get 'https://user:password@example.com/private/resource' # optional HTTP headers Hash.
# #
# # POST or PUT with a hash sends parameters as a urlencoded form body # The {.post}, {.put}, and {.patch} methods take a URL String, a payload, and
# RestClient.post 'http://example.com/resource', :param1 => 'one' # an optional HTTP headers Hash.
# #
# # nest hash parameters # All of these helpers are just thin wrappers around
# RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' } # {RestClient::Request.execute RestClient::Request.execute}.
# #
# # POST and PUT with raw payloads
# RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
# RestClient.post 'http://example.com/resource.xml', xml_doc
# RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
# #
# # DELETE # ```ruby
# RestClient.delete 'http://example.com/resource' # # Simple GET request, potentially with headers.
# RestClient.get('http://example.com/')
# # => <RestClient::Response 200 "<!doctype h...">
# #
# # retreive the response http code and headers # RestClient.get('http://example.com/resource', accept: 'image/jpg')
# res = RestClient.get 'http://example.com/some.jpg'
# res.code # => 200
# res.headers[:content_type] # => 'image/jpg'
# #
# # HEAD # RestClient.get('http://example.com', 'If-Modified-Since': 'Sat, 10 Aug 2013 10:23:00 GMT')
# RestClient.head('http://example.com').headers # # raises RestClient::NotModified: 304 Not Modified
#
# # Basic authentication and SSL
# RestClient.get 'https://user:password@example.com/private/resource'
#
# # POST or PUT with a hash sends parameters as a urlencoded form body
# RestClient.post 'http://example.com/resource', :param1 => 'one'
#
# # nest hash parameters
# RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
#
# # POST and PUT with raw payloads
# RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
# RestClient.post 'http://example.com/resource.xml', xml_doc
# RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
#
# # DELETE
# RestClient.delete 'http://example.com/resource'
#
# # Retrieve the response http code and headers
# res = RestClient.get 'http://example.com/some.jpg'
# res.code # => 200
# res.headers[:content_type] # => 'image/jpg'
#
# # HEAD
# RestClient.head('http://example.com').headers
# ```
# #
# To use with a proxy, just set RestClient.proxy to the proper http proxy: # To use with a proxy, just set RestClient.proxy to the proper http proxy:
# #
# RestClient.proxy = "http://proxy.example.com/" # RestClient.proxy = "http://proxy.example.com/"
# #
# Or inherit the proxy from the environment: # Proxies can also be set via the `http_proxy`/`https_proxy` environment
# variables, or with the `:proxy` option on an individual {RestClient::Request}.
# #
# RestClient.proxy = ENV['http_proxy'] # For live tests of RestClient, try using https://httpbin.org/. This service
# echoes back information about the HTTP request.
# #
# For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call: # r = RestClient.post('https://httpbin.org/post', foo: 'bar')
# # # => <RestClient::Response 200 "{\n \"args\":...">
# >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz' # puts r.body
# => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}" # {
# "args": {},
# "data": "",
# "files": {},
# "form": {
# "foo": "bar"
# },
# "headers": {
# "Accept": "*/*",
# "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
# "Connection": "close",
# "Content-Length": "7",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "httpbin.org",
# "User-Agent": "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.3.3p222"
# },
# "json": null,
# "url": "https://httpbin.org/post"
# }
# #
module RestClient module RestClient
@ -96,6 +137,10 @@ module RestClient
@proxy ||= nil @proxy ||= nil
end end
# Set a proxy URL to use for all requests.
#
# @param value [String] The proxy URL.
#
def self.proxy=(value) def self.proxy=(value)
@proxy = value @proxy = value
@proxy_set = true @proxy_set = true
@ -113,12 +158,21 @@ module RestClient
# Setup the log for RestClient calls. # Setup the log for RestClient calls.
# Value should be a logger but can can be stdout, stderr, or a filename. # Value should be a logger but can can be stdout, stderr, or a filename.
# You can also configure logging by the environment variable RESTCLIENT_LOG. # You can also configure logging by the environment variable RESTCLIENT_LOG.
#
# @param log [Logger, #<<, String] The log to write to. See {.create_log}
#
def self.log= log def self.log= log
@@log = create_log log @@log = create_log log
end end
# Create a log that respond to << like a logger # Create a log that responds to `<<` like a Logger.
# param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it) #
# @param param [Logger, #<<, String, nil] The log to write to. Should be a
# Logger, IO, or other object with a `<<` method. If param is a String, it
# will be treated as a filename and that file will be opened as a log file.
# The special Strings `"stdout"` and `"stderr"` will log to `STDOUT` and
# `STDERR`.
#
def self.create_log param def self.create_log param
if param if param
if param.is_a? String if param.is_a? String
@ -158,10 +212,16 @@ module RestClient
@@log = nil @@log = nil
def self.log # :nodoc: # The RestClient global logger. This will be used for all requests unless a
# `:log` option is set on the individual request.
#
# @see log=
#
def self.log
@@env_log || @@log @@env_log || @@log
end end
# Array of procs executed prior to each request.
@@before_execution_procs = [] @@before_execution_procs = []
# Add a Proc to be called before each request in executed. # Add a Proc to be called before each request in executed.
@ -176,7 +236,8 @@ module RestClient
@@before_execution_procs = [] @@before_execution_procs = []
end end
def self.before_execution_procs # :nodoc: # Array of procs executed prior to each request.
def self.before_execution_procs
@@before_execution_procs @@before_execution_procs
end end

View file

@ -3,6 +3,17 @@ require 'http-cookie'
module RestClient module RestClient
# The AbstractResponse module provides common functionality for RestClient
# responses. It is included by {RestClient::Response} and
# {RestClient::RawResponse}.
#
# Classes that include AbstractResponse should call {response_set_vars} as
# part of their `#initialize` method.
#
# Ideally this would have been a parent class, not a module. But the original
# RestClient API made {Response} be a subclass of `String`, so we are
# stuck with that for backwards compatibility.
#
module AbstractResponse module AbstractResponse
attr_reader :net_http_res, :request, :start_time, :end_time, :duration attr_reader :net_http_res, :request, :start_time, :end_time, :duration
@ -12,10 +23,17 @@ module RestClient
end end
# Logger from the request, potentially nil. # Logger from the request, potentially nil.
#
# @see Request#log
#
def log def log
request.log request.log
end end
# Write log information about the response.
#
# @return [void]
#
def log_response def log_response
return unless log return unless log
@ -27,21 +45,39 @@ module RestClient
end end
# HTTP status code # HTTP status code
#
# @return [Integer]
#
def code def code
@code ||= @net_http_res.code.to_i @code ||= @net_http_res.code.to_i
end end
# An array of prior responses in the redirection chain, if any. If
# RestClient followed any redirects, this provides a way to see each
# individual response in the chain.
#
# @return [Array<Response>]
#
# @see Request#redirection_history
#
def history def history
@history ||= request.redirection_history || [] @history ||= request.redirection_history || []
end end
# A hash of the headers, beautified with symbols and underscores. # A hash of the headers, beautified with symbols and underscores.
# e.g. "Content-type" will become :content_type. # e.g. `"Content-type"` will become `:content_type`.
#
# @see beautify_headers
#
# @return [Hash]
#
def headers def headers
@headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash) @headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
end end
# The raw headers. # The raw headers.
#
# @return [Hash]
def raw_headers def raw_headers
@raw_headers ||= @net_http_res.to_hash @raw_headers ||= @net_http_res.to_hash
end end
@ -49,6 +85,9 @@ module RestClient
# @param [Net::HTTPResponse] net_http_res # @param [Net::HTTPResponse] net_http_res
# @param [RestClient::Request] request # @param [RestClient::Request] request
# @param [Time] start_time # @param [Time] start_time
#
# @return [void]
#
def response_set_vars(net_http_res, request, start_time) def response_set_vars(net_http_res, request, start_time)
@net_http_res = net_http_res @net_http_res = net_http_res
@request = request @request = request
@ -67,9 +106,9 @@ module RestClient
# Hash of cookies extracted from response headers. # Hash of cookies extracted from response headers.
# #
# NB: This will return only cookies whose domain matches this request, and # **Note:** This will return only cookies whose domain matches this
# may not even return all of those cookies if there are duplicate names. # request, and may not even return all of those cookies if there are
# Use the full cookie_jar for more nuanced access. # duplicate names. Use the full cookie_jar for more nuanced access.
# #
# @see #cookie_jar # @see #cookie_jar
# #
@ -104,11 +143,20 @@ module RestClient
# #
# For 20x status codes: return the response itself # For 20x status codes: return the response itself
# #
# For 30x status codes: # For 30x status codes, if there is a `Location` header and we have not yet
# 301, 302, 307: redirect GET / HEAD if there is a Location header # reached {Request#max_redirects}:
# 303: redirect, changing method to GET, if there is a Location header
# #
# For all other responses, raise a response exception # - 301, 302, 307: redirect GET / HEAD requests
# - 303: redirect, changing method to GET
#
# For all other responses, raise a response exception, a subclass of
# {ExceptionWithResponse} corresponding to the HTTP status code.
#
# For example, HTTP 404 => {RestClient::NotFound RestClient::NotFound}
#
# @raise [ExceptionWithResponse] for non-20x status codes, the exception
# from {RestClient::Exceptions::EXCEPTIONS_MAP} based on
# {RestClient::STATUSES} will be thrown.
# #
def return!(&block) def return!(&block)
case code case code
@ -130,11 +178,13 @@ module RestClient
end end
end end
# @deprecated Use {code} instead.
def to_i def to_i
warn('warning: calling Response#to_i is not recommended') warn('warning: calling Response#to_i is deprecated. Use .code instead.')
super super
end end
# @return [String]
def description def description
"#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n" "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
end end

View file

@ -2,18 +2,26 @@ module RestClient
# Hash of HTTP status code => message. # Hash of HTTP status code => message.
# #
# 1xx: Informational - Request received, continuing process # ### HTTP status code families:
# 2xx: Success - The action was successfully received, understood, and #
# accepted # - 1xx: Informational --- Request received, continuing process
# 3xx: Redirection - Further action must be taken in order to complete the # - 2xx: Success --- The action was successfully received, understood, and
# request # accepted
# 4xx: Client Error - The request contains bad syntax or cannot be fulfilled # - 3xx: Redirection --- Further action must be taken in order to complete
# 5xx: Server Error - The server failed to fulfill an apparently valid # the request
# request # - 4xx: Client Error --- The request contains bad syntax or cannot be
# fulfilled
# - 5xx: Server Error --- The server failed to fulfill an apparently valid
# request
#
# This hash is used to populate all of the individual response exception
# classes, which are collected in {RestClient::Exceptions::EXCEPTIONS_MAP}.
# #
# @see # @see
# http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml # http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
# #
# **TODO:** Move these out of the top-level namespace and into {Exceptions}.
#
STATUSES = {100 => 'Continue', STATUSES = {100 => 'Continue',
101 => 'Switching Protocols', 101 => 'Switching Protocols',
102 => 'Processing', #WebDAV 102 => 'Processing', #WebDAV
@ -84,6 +92,11 @@ module RestClient
511 => 'Network Authentication Required', # RFC6585 511 => 'Network Authentication Required', # RFC6585
} }
# This Hash contains a mapping of aliases for the canonical HTTP status code
# classes that are preserved for backwards compatibility. For example,
# `RestClient::ResourceNotFound` is an alias for `RestClient::NotFound`.
#
# **TODO:** Move this out of the top-level namespace and into {Exceptions}.
STATUSES_COMPATIBILITY = { STATUSES_COMPATIBILITY = {
# The RFCs all specify "Not Found", but "Resource Not Found" was used in # The RFCs all specify "Not Found", but "Resource Not Found" was used in
# earlier RestClient releases. # earlier RestClient releases.
@ -101,16 +114,22 @@ module RestClient
# This is the base RestClient exception class. Rescue it if you want to # This is the base RestClient exception class. Rescue it if you want to
# catch any exception that your request might raise # catch any exception that your request might raise. Note that the underlying
# You can get the status code by e.http_code, or see anything about the # network and socket libraries may raise other exceptions.
# response via e.response. #
# For example, the entire result body (which is # You can get the status code with {#http_code}, or see anything about the
# probably an HTML error page) is e.response. # response via {#response}.
#
# For more detailed information from the response, just call the
# corresponding methods on the response object (e.g. `e.response.history`).
#
class Exception < RuntimeError class Exception < RuntimeError
attr_accessor :response attr_accessor :response
attr_accessor :original_exception attr_accessor :original_exception
attr_writer :message attr_writer :message
# @param response [RestClient::Response, RestClient::RawResponse]
#
def initialize response = nil, initial_response_code = nil def initialize response = nil, initial_response_code = nil
@response = response @response = response
@message = nil @message = nil
@ -126,10 +145,14 @@ module RestClient
end end
end end
# @see Response#headers
# @return [Hash, nil]
def http_headers def http_headers
@response.headers if @response @response.headers if @response
end end
# @see Response#body
# @return [String, nil]
def http_body def http_body
@response.body if @response @response.body if @response
end end
@ -169,7 +192,9 @@ module RestClient
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
# #
module Exceptions module Exceptions
# Map http status codes to the corresponding exception class # Map http status codes to the corresponding exception class.
# This Hash is populated when the library is loaded, so values won't appear
# in the YARD documentation.
EXCEPTIONS_MAP = {} EXCEPTIONS_MAP = {}
end end

View file

@ -10,6 +10,9 @@ rescue LoadError
end end
module RestClient module RestClient
# The Payload module contains several different classes used to process and
# represent different types of HTTP bodies / payloads.
module Payload module Payload
extend self extend self
@ -56,6 +59,7 @@ module RestClient
end end
end end
# The base class for all the Payload classes.
class Base class Base
def initialize(params) def initialize(params)
build_stream(params) build_stream(params)

View file

@ -29,10 +29,20 @@ module RestClient
RUBY_ENGINE == 'jruby' RUBY_ENGINE == 'jruby'
end end
# Return the host architecture and CPU from `RbConfig::CONFIG`.
#
# @return [String]
def self.architecture def self.architecture
"#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}" "#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}"
end end
# Return information about the ruby version from `RUBY_ENGINE`,
# `RUBY_VERSION`, and `RUBY_PATCHLEVEL`.
#
# When running in jruby, also return the jruby version.
#
# @return [String]
#
def self.ruby_agent_version def self.ruby_agent_version
case RUBY_ENGINE case RUBY_ENGINE
when 'jruby' when 'jruby'
@ -42,6 +52,17 @@ module RestClient
end end
end end
# Return a reasonable string for the `User-Agent` HTTP header.
#
# @example
# "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.3.3p222"
#
# @return [String]
#
# @see VERSION RestClient::VERSION
# @see .architecture
# @see .ruby_agent_version
#
def self.default_user_agent def self.default_user_agent
"rest-client/#{VERSION} (#{architecture}) #{ruby_agent_version}" "rest-client/#{VERSION} (#{architecture}) #{ruby_agent_version}"
end end

View file

@ -1,14 +1,35 @@
module RestClient module RestClient
# The response from RestClient on a raw request looks like a string, but is
# actually one of these. 99% of the time you're making a rest call all you # {RawResponse} is used to represent RestClient responses when
# care about is the body, but on the occassion you want to fetch the # `:raw_response => true` is passed to the {Request}.
# headers you can:
# #
# RestClient.get('http://example.com').headers[:content_type] # Instead of processing the response data in various ways, the `RawResponse`
# downloads the response body to a `Tempfile` and does little processing of
# the underlying `Net::HTTPResponse` object. This is especially useful for
# large downloads when you don't want to load the entire response into
# memory.
#
# Use {#file} to access the `Tempfile` containing the raw response body. The
# file path is accessible at `.file.path`.
#
# **Note that like all `Tempfile` objects, the {#file} will be deleted when
# the object is dereferenced.**
#
# This class brings in all the common functionality from {AbstractResponse},
# such as {AbstractResponse.headers}, etc.
#
# @example
#
# r = RestClient::Request.execute(method: :get, url: 'http://example.com', raw_response: true)
# r.code
# # => 200
# puts r.file.inspect
# # => #<Tempfile:/tmp/rest-client.20170102-15213-b8kgcj>
# r.file.path
# # => "/tmp/rest-client.20170102-15213-b8kgcj"
# r.size
# # => 1270
# #
# In addition, if you do not use the response as a string, you can access
# a Tempfile object at res.file, which contains the path to the raw
# downloaded request body.
class RawResponse class RawResponse
include AbstractResponse include AbstractResponse
@ -36,11 +57,18 @@ module RestClient
body body
end end
# Read the response body from {#file} into memory and return as a String.
#
# @return [String]
#
def body def body
@file.rewind @file.rewind
@file.read @file.read
end end
# Return the response body file size.
#
# @return [Integer]
def size def size
file.size file.size
end end

View file

@ -15,24 +15,27 @@ module RestClient
# call it directly if you'd like to use a method not supported by the # call it directly if you'd like to use a method not supported by the
# main API. # main API.
# #
# @example using {.execute} class method: # @example Using {.execute} class method:
# RestClient::Request.execute(method: :head, url: 'http://example.com') # RestClient::Request.execute(method: :head, url: 'http://example.com')
# #
# @example initializing {#initialize} and then calling {#execute}: # @example Initializing {#initialize} and then calling {#execute}:
# req = RestClient::Request.new(method: :get, url: 'http://example.com', timeout: 5) # req = RestClient::Request.new(method: :get, url: 'http://example.com', timeout: 5)
# req.execute # req.execute
# #
# The `:method` and `:url` parameters are required. All others are optional. # The `:method` and `:url` parameters are required. All others are optional.
# #
# @deprecated *Note:* # **See {#initialize} for the full list of available options.**
# The RestClient API has a very ugly misfeature that dates to the original #
# design, where certain options are destructively pulled out of the # **Deprecation note:**
# `:headers` hash that normally contains HTTP request headers. This is # Certain options are accepted as keys in the headers hash, but doing so is
# because in the top-level helper shortcuts like {RestClient.get}, the only # deprecated. This misfeature in the RestClient API dates to the original
# hash argument permitted is the headers hash, so there is no place to put # design, where certain options are destructively pulled out of the
# options. For example, while it is currently allowed to pass options like # `:headers` hash that normally contains HTTP request headers. This is
# `:params` or `:cookies` as keys inside the `:headers` hash, this is # because in the top-level helper shortcuts like {RestClient.get}, the only
# strongly discouraged. # hash argument permitted is the headers hash, so there is no place to put
# options. For example, while it is currently allowed to pass options like
# `:params` or `:cookies` as keys inside the `:headers` hash, this is
# strongly discouraged.
# #
class Request class Request
@ -46,12 +49,18 @@ module RestClient
# Shorthand for initializing a Request and executing it. # Shorthand for initializing a Request and executing it.
# #
# RestClient::Request.execute is a great way to pass complex options. # `RestClient::Request.execute` is the recommended way to pass complex
# options. It is shorthand for `RestClient::Request.new(args).execute`.
# #
# For example: # @example
# RestClient::Request.execute(method: get, url: 'http://example.com', timeout: 5) # RestClient::Request.execute(method: :get, url: 'http://example.com', timeout: 5)
# #
# @see RestClient::Request # @example
# RestClient::Request.execute(method: :get, url: 'http://httpbin.org/redirect/2', max_redirects: 1)
#
# @see RestClient::Request#initialize
#
# @return [RestClient::Response, RestClient::RawResponse]
# #
def self.execute(args, & block) def self.execute(args, & block)
new(args).execute(& block) new(args).execute(& block)
@ -71,15 +80,15 @@ module RestClient
# #
# @param [Hash] args # @param [Hash] args
# #
# @option args [String] :url *Required.* The HTTP URL to request. # @option args [String] :url **Required.** The HTTP URL to request.
# @option args [String, Symbol] :method *Required.* The HTTP request method # @option args [String, Symbol] :method **Required.** The HTTP request method
# or verb, such as "GET", "HEAD", or "POST". # or verb, such as `"GET"`, `"HEAD"`, or `"POST"`.
# #
# @option args [Hash] :headers The HTTP request headers. Keys may be # @option args [Hash] :headers The HTTP request headers. Keys may be
# Symbol or String. Symbol keys will be converted to String header names # Symbol or String. Symbol keys will be converted to String header names
# by {#stringify_headers}. For backwards compatibility, this Hash # by {#stringify_headers}. For backwards compatibility, this Hash
# recognizes certain keys that will be pulled out as options, but relying # recognizes certain keys that will be pulled out as options, but relying
# on this is deprecated and strongly discouraged. # on this behavior is deprecated and strongly discouraged.
# @option args :cookies [HTTP::CookieJar, Hash{String, Symbol => String}, # @option args :cookies [HTTP::CookieJar, Hash{String, Symbol => String},
# Array<HTTP::Cookie>] The cookies to be sent with the request. This can # Array<HTTP::Cookie>] The cookies to be sent with the request. This can
# be passed as a Hash, an array of HTTP::Cookie objects, or as a full # be passed as a Hash, an array of HTTP::Cookie objects, or as a full
@ -121,10 +130,10 @@ module RestClient
# timeout on an individual network read, but does not limit the overall # timeout on an individual network read, but does not limit the overall
# duration of the request so long as the server continues sending data at # duration of the request so long as the server continues sending data at
# a trickle. Pass nil to disable the timeout. See # a trickle. Pass nil to disable the timeout. See
# {Net::HTTP#read_timeout}. # `Net::HTTP#read_timeout`.
# @option args [Numeric, nil] :open_timeout Number of seconds to wait for # @option args [Numeric, nil] :open_timeout Number of seconds to wait for
# the connection to be established. Pass nil to disable the timeout. See # the connection to be established. Pass nil to disable the timeout. See
# {Net::HTTP#open_timeout}. # `Net::HTTP#open_timeout`.
# @option args [Numeric, nil] :timeout Set both `:read_timeout` and # @option args [Numeric, nil] :timeout Set both `:read_timeout` and
# `:open_timeout` # `:open_timeout`
# @option args :ssl_client_cert # @option args :ssl_client_cert
@ -258,7 +267,7 @@ module RestClient
# Extract the query parameters and append them to the url # Extract the query parameters and append them to the url
# #
# Look through the headers hash for a :params option (case-insensitive, # Look through the headers hash for a `:params` option (case-insensitive,
# may be string or symbol). If present and the value is a Hash or # may be string or symbol). If present and the value is a Hash or
# RestClient::ParamsArray, *delete* the key/value pair from the headers # RestClient::ParamsArray, *delete* the key/value pair from the headers
# hash and encode the value into a query string. Append this query string # hash and encode the value into a query string. Append this query string
@ -266,10 +275,12 @@ module RestClient
# #
# @param [String] url # @param [String] url
# @param [Hash] headers An options/headers hash to process. Mutation # @param [Hash] headers An options/headers hash to process. Mutation
# warning: the params key may be removed if present! # warning: the `params` key may be removed if present!
# #
# @return [String] resulting url with query string # @return [String] resulting url with query string
# #
# @api private
#
def process_url_params(url, headers) def process_url_params(url, headers)
url_params = nil url_params = nil
@ -342,19 +353,21 @@ module RestClient
end end
# Process cookies passed as hash or as HTTP::CookieJar. For backwards # Process cookies passed as hash or as HTTP::CookieJar. For backwards
# compatibility, these may be passed as a :cookies option masquerading # compatibility, these may be passed as a `:cookies` option masquerading
# inside the headers hash. To avoid confusion, if :cookies is passed in # inside the headers hash. To avoid confusion, if `:cookies` is passed in
# both headers and Request#initialize, raise an error. # both headers and {#initialize}, raise an error.
# #
# :cookies may be a: # `:cookies` may be a:
# - Hash{String/Symbol => String} #
# - Array<HTTP::Cookie> # - `Hash{String/Symbol => String}`
# - HTTP::CookieJar # - `Array<HTTP::Cookie>`
# - `HTTP::CookieJar`
#
# **Passing as a hash:**
# #
# Passing as a hash:
# Keys may be symbols or strings. Values must be strings. # Keys may be symbols or strings. Values must be strings.
# Infer the domain name from the request URI and allow subdomains (as # Infer the domain name from the request URI and allow subdomains (as
# though '.example.com' had been set in a Set-Cookie header). Assume a # though '.example.com' had been set in a `Set-Cookie` header). Assume a
# path of '/'. # path of '/'.
# #
# RestClient::Request.new(url: 'http://example.com', method: :get, # RestClient::Request.new(url: 'http://example.com', method: :get,
@ -362,28 +375,30 @@ module RestClient
# ) # )
# #
# results in cookies as though set from the server by: # results in cookies as though set from the server by:
#
# Set-Cookie: foo=Value; Domain=.example.com; Path=/ # Set-Cookie: foo=Value; Domain=.example.com; Path=/
# Set-Cookie: bar=123; Domain=.example.com; Path=/ # Set-Cookie: bar=123; Domain=.example.com; Path=/
# #
# which yields a client cookie header of: # which yields a client cookie header of:
#
# Cookie: foo=Value; bar=123 # Cookie: foo=Value; bar=123
# #
# Passing as HTTP::CookieJar, which will be passed through directly: # **Passing as HTTP::CookieJar, which will be passed through directly:**
# #
# jar = HTTP::CookieJar.new # jar = HTTP::CookieJar.new
# jar.add(HTTP::Cookie.new('foo', 'Value', domain: 'example.com', # jar.add(HTTP::Cookie.new('foo', 'Value', domain: 'example.com',
# path: '/', for_domain: false)) # path: '/', for_domain: false))
# #
# RestClient::Request.new(..., :cookies => jar) # RestClient::Request.new('...', :cookies => jar)
# #
# @param [URI::HTTP] uri The URI for the request. This will be used to # @param [URI::HTTP] uri The URI for the request. This will be used to
# infer the domain name for cookies passed as strings in a hash. To avoid # infer the domain name for cookies passed as strings in a hash. To avoid
# this implicit behavior, pass a full cookie jar or use HTTP::Cookie hash # this implicit behavior, pass a full cookie jar or use `HTTP::Cookie`
# values. # hash values.
# @param [Hash] headers The headers hash from which to pull the :cookies # @param [Hash] headers The headers hash from which to pull the `:cookies`
# option. MUTATION NOTE: This key will be deleted from the hash if # option. **MUTATION NOTE:** This key will be deleted from the hash if
# present. # present. Passing cookies in this way is deprecated.
# @param [Hash] args The options passed to Request#initialize. This hash # @param [Hash] args The options passed to {Request#initialize}. This hash
# will be used as another potential source for the :cookies key. # will be used as another potential source for the :cookies key.
# These args will not be mutated. # These args will not be mutated.
# #
@ -439,19 +454,20 @@ module RestClient
end end
# Generate headers for use by a request. Header keys will be stringified # Generate headers for use by a request. Header keys will be stringified
# using `#stringify_headers` to normalize them as capitalized strings. # using {#stringify_headers} to normalize them as capitalized strings.
# #
# The final headers consist of: # The final headers consist of:
# - default headers from #default_headers
# - user_headers provided here
# - headers from the payload object (e.g. Content-Type, Content-Lenth)
# - cookie headers from #make_cookie_header
# #
# BUG: stringify_headers does not alter the capitalization of headers that # - default headers from {#default_headers}
# are passed as strings, it only normalizes those passed as symbols. This # - `user_headers` provided here
# behavior will probably remain for a while for compatibility, but it means # - headers from the payload object (e.g. Content-Type, Content-Lenth)
# that the warnings that attempt to detect accidental header overrides may # - cookie headers from {#make_cookie_header}
# not always work. #
# **BUG:** stringify_headers does not alter the capitalization of headers
# that are passed as strings, it only normalizes those passed as symbols.
# This behavior will probably remain for a while for compatibility, but it
# means that the warnings that attempt to detect accidental header
# overrides may not always work.
# https://github.com/rest-client/rest-client/issues/599 # https://github.com/rest-client/rest-client/issues/599
# #
# @param [Hash] user_headers User-provided headers to include # @param [Hash] user_headers User-provided headers to include
@ -494,7 +510,7 @@ module RestClient
end end
# The proxy URI for this request. If `:proxy` was provided on this request, # The proxy URI for this request. If `:proxy` was provided on this request,
# use it over `RestClient.proxy`. # use it over {RestClient.proxy}.
# #
# Return false if a proxy was explicitly set and is falsy. # Return false if a proxy was explicitly set and is falsy.
# #
@ -518,6 +534,17 @@ module RestClient
end end
end end
# Create a new Net::HTTP object representing a connection to a server
# without actually opening the connection. This method will set up an HTTP
# proxy according to {#proxy_uri}.
#
# @param hostname [String]
# @param port [Integer]
#
# @return [Net::HTTP]
#
# @api private
#
def net_http_object(hostname, port) def net_http_object(hostname, port)
p_uri = proxy_uri p_uri = proxy_uri
@ -534,10 +561,28 @@ module RestClient
end end
end end
# Find the Net::HTTPRequest subclass for a given HTTP method/verb.
#
# @param method [Symbol, String]
#
# @return [Class] A subclass of Net::HTTPRequest.
#
# @api private
#
def net_http_request_class(method) def net_http_request_class(method)
Net::HTTP.const_get(method.capitalize, false) Net::HTTP.const_get(method.capitalize, false)
end end
# Actually execute the request with Net::HTTP.
#
# @param http [Net::HTTP]
# @param req [Net::HTTPRequest]
# @param body [String, IO, nil]
#
# @see https://ruby-doc.org/stdlib-2.4.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-request
# Net::HTTP#request
#
# @api private
def net_http_do_request(http, req, body=nil, &block) def net_http_do_request(http, req, body=nil, &block)
if body && body.respond_to?(:read) if body && body.respond_to?(:read)
req.body_stream = body req.body_stream = body
@ -557,6 +602,8 @@ module RestClient
# #
# @return [String] # @return [String]
# #
# @api private
#
def normalize_url(url) def normalize_url(url)
url = 'http://' + url unless url.match(%r{\A[a-z][a-z0-9+.-]*://}i) url = 'http://' + url unless url.match(%r{\A[a-z][a-z0-9+.-]*://}i)
url url
@ -605,11 +652,20 @@ module RestClient
redacted_uri.to_s redacted_uri.to_s
end end
# Default to the global logger if there's not a request-specific one # The log used for this request.
#
# Defaults to the global logger {RestClient.log} if there was no `:log`
# option set on this request.
#
def log def log
@log || RestClient.log @log || RestClient.log
end end
# Write log information about the request. Called just prior to sending the
# request to the server.
#
# @return [void]
#
def log_request def log_request
return unless log return unless log

View file

@ -4,34 +4,34 @@ module RestClient
# #
# Example: # Example:
# #
# resource = RestClient::Resource.new('http://some/resource') # resource = RestClient::Resource.new('http://some/resource')
# jpg = resource.get(:accept => 'image/jpg') # jpg = resource.get(:accept => 'image/jpg')
# #
# With HTTP basic authentication: # With HTTP basic authentication:
# #
# resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password') # resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password')
# resource.delete # resource.delete
# #
# With a timeout (seconds): # With a timeout (seconds):
# #
# RestClient::Resource.new('http://slow', :read_timeout => 10) # RestClient::Resource.new('http://slow', :read_timeout => 10)
# #
# With an open timeout (seconds): # With an open timeout (seconds):
# #
# RestClient::Resource.new('http://behindfirewall', :open_timeout => 10) # RestClient::Resource.new('http://behindfirewall', :open_timeout => 10)
# #
# You can also use resources to share common headers. For headers keys, # You can also use resources to share common headers. For headers keys,
# symbols are converted to strings. Example: # symbols are converted to strings. Example:
# #
# resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 }) # resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 })
# #
# This header will be transported as X-Client-Version (notice the X prefix, # This header will be transported as X-Client-Version (notice the X prefix,
# capitalization and hyphens) # capitalization and hyphens)
# #
# Use the [] syntax to allocate subresources: # Use the [] syntax to allocate subresources:
# #
# site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd') # site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd')
# site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain' # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
# #
class Resource class Resource
attr_reader :url, :options, :block attr_reader :url, :options, :block

View file

@ -2,6 +2,17 @@ module RestClient
# A Response from RestClient, you can access the response body, the code or the headers. # A Response from RestClient, you can access the response body, the code or the headers.
# #
# Response is a subclass of `String` for backwards compatibility. This may
# change in a future major release of RestClient, so it is recommended to
# explicitly call {#body} or {#to_s} before invoking `String` methods.
#
# The request that resulted in this response is accessible at {#request}.
#
# Much of the functionality is implemented on the {AbstractResponse} module.
#
# @see AbstractResponse
# @see RawResponse
#
class Response < String class Response < String
include AbstractResponse include AbstractResponse
@ -38,14 +49,17 @@ module RestClient
"<RestClient::Response #{code.inspect} #{body_truncated(10).inspect}>" "<RestClient::Response #{code.inspect} #{body_truncated(10).inspect}>"
end end
# Initialize a Response object. Because RestClient::Response is # Initialize a Response object. Because `RestClient::Response` is
# (unfortunately) a subclass of String for historical reasons, # (unfortunately) a subclass of String for historical reasons,
# Response.create is the preferred initializer. # `Response.create` is the preferred initializer.
# #
# @param [String, nil] body The response body from the Net::HTTPResponse # @param [String, nil] body The response body from the Net::HTTPResponse
# @param [Net::HTTPResponse] net_http_res # @param [Net::HTTPResponse] net_http_res
# @param [RestClient::Request] request # @param [RestClient::Request] request
# @param [Time] start_time # @param [Time] start_time
#
# @return [Response]
#
def self.create(body, net_http_res, request, start_time=nil) def self.create(body, net_http_res, request, start_time=nil)
result = self.new(body || '') result = self.new(body || '')
@ -55,8 +69,13 @@ module RestClient
result result
end end
# Set the String encoding according to the 'Content-Type: charset' header, # Set the String encoding according to the `Content-Type: charset` header,
# if possible. # if possible.
#
# @param response [Response]
#
# @return [Response]
#
def self.fix_encoding(response) def self.fix_encoding(response)
charset = RestClient::Utils.get_encoding_from_headers(response.headers) charset = RestClient::Utils.get_encoding_from_headers(response.headers)
encoding = nil encoding = nil

View file

@ -1,7 +1,12 @@
module RestClient module RestClient
# The current RestClient version array
VERSION_INFO = [2, 1, 0, 'rc1'] unless defined?(self::VERSION_INFO) VERSION_INFO = [2, 1, 0, 'rc1'] unless defined?(self::VERSION_INFO)
# The current RestClient version string
VERSION = VERSION_INFO.map(&:to_s).join('.') unless defined?(self::VERSION) VERSION = VERSION_INFO.map(&:to_s).join('.') unless defined?(self::VERSION)
# @return [String] The current RestClient version string
def self.version def self.version
VERSION VERSION
end end