Class: REST::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/rest/request.rb

Overview

Request holds a HTTP request

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(verb, url, body = nil, headers = {}, options = {}, &configure_block) ⇒ Request

  • verb: The verb to use in the request, either :get, :head, :patch, :put, or :post

  • url: The URL to send the request to, must be a URI instance

  • body: The body to use in the request

  • headers: A hash of headers to add to the request

  • options: A hash of additional options

    • username: Username to use for basic authentication

    • password: Password to use for basic authentication

    • tls_verify/verify_ssl: Verify the server certificate against known CA’s

    • tls_ca_file: Use a specific file for CA certificates instead of the built-in one this only works when :tls_verify is also set.

    • tls_key_and_certificate_file: The client key and certificate file to use for this request

    • tls_certificate: The client certficate to use for this request

    • tls_key: The client private key to use for this request

  • configure_block: An optional block that yields the underlying Net::HTTP request object allowing for more fine-grained configuration

Examples

request = REST::Request.new(:get, URI.parse('http://example.com/pigeons/1'))

request = REST::Request.new(:head, URI.parse('http://example.com/pigeons/1'))

request = REST::Request.new(:post,
  URI.parse('http://example.com/pigeons'),
  {'name' => 'Homr'}.to_json,
  {'Accept' => 'application/json, */*', 'Content-Type' => 'application/json; charset=utf-8'}
)

# Pass a block to configure the underlying +Net::HTTP+ request.
request = REST::Request.new(:get, URI.parse('http://example.com/pigeons/largest')) do |http_request|
  http_request.open_timeout = 15 # seconds
end

Authentication example

request = REST::Request.new(:put,
  URI.parse('http://example.com/pigeons/1'),
  {'name' => 'Homer'}.to_json,
  {'Accept' => 'application/json, */*', 'Content-Type' => 'application/json; charset=utf-8'},
  {:username => 'Admin', :password => 'secret'}
)

TLS / SSL examples

# Use a client key and certificate
request = REST::Request.new(:get, URI.parse('https://example.com/pigeons/1'), nil, {}, {
  :tls_key_and_certificate_file => '/home/alice/keys/example.pem'
})

# Use a client certificate and key from a specific location
key_and_certificate = File.read('/home/alice/keys/example.pem')
request = REST::Request.new(:get, URI.parse('https://example.com/pigeons/1'), nil, {}, {
  :tls_key => OpenSSL::PKey::RSA.new(key_and_certificate),
  :tls_certificate => OpenSSL::X509::Certificate.new(key_and_certificate)
})

# Verify the server certificate against a specific certificate
request = REST::Request.new(:get, URI.parse('https://example.com/pigeons/1'), nil, {}, {
  :tls_verify => true,
  :tls_ca_file => '/home/alice/keys/example.pem'
})


71
72
73
74
75
76
77
78
# File 'lib/rest/request.rb', line 71

def initialize(verb, url, body=nil, headers={}, options={}, &configure_block)
  @verb = verb
  @url = url
  @body = body
  @headers = headers
  @options = options
  @configure_block = configure_block
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



7
8
9
# File 'lib/rest/request.rb', line 7

def body
  @body
end

#headersObject

Returns the value of attribute headers.



7
8
9
# File 'lib/rest/request.rb', line 7

def headers
  @headers
end

#optionsObject

Returns the value of attribute options.



7
8
9
# File 'lib/rest/request.rb', line 7

def options
  @options
end

#requestObject

Returns the value of attribute request.



7
8
9
# File 'lib/rest/request.rb', line 7

def request
  @request
end

#urlObject

Returns the value of attribute url.



7
8
9
# File 'lib/rest/request.rb', line 7

def url
  @url
end

#verbObject

Returns the value of attribute verb.



7
8
9
# File 'lib/rest/request.rb', line 7

def verb
  @verb
end

Class Method Details

.perform(*args, &configure_block) ⇒ Object

Shortcut for REST::Request.new(*args).perform.

See new for options.



190
191
192
193
# File 'lib/rest/request.rb', line 190

def self.perform(*args, &configure_block)
  request = new(*args, &configure_block)
  request.perform
end

Instance Method Details

#http_proxyObject



96
97
98
99
100
# File 'lib/rest/request.rb', line 96

def http_proxy
  if settings = proxy_settings
    Net::HTTP.Proxy(settings.host, settings.port, settings.user, settings.password)
  end
end

#http_requestObject

Configures and returns a new Net::HTTP request object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/rest/request.rb', line 103

def http_request
  if http_proxy
    http_request = http_proxy.new(url.host, url.port)
  else
    http_request = Net::HTTP.new(url.host, url.port)
  end
  
  # enable SSL/TLS
  if url.scheme == 'https'
    require 'net/https'
    require 'openssl'
    Error::Connection.extend_classes!
    
    http_request.use_ssl = true
    
    if options[:tls_verify] or options[:verify_ssl]
      if http_request.respond_to?(:enable_post_connection_check=)
        http_request.enable_post_connection_check = true
      end
      # from http://curl.haxx.se/ca/cacert.pem
      http_request.ca_file = options[:tls_ca_file] || File.expand_path('../../../support/cacert.pem', __FILE__)
      http_request.verify_mode = OpenSSL::SSL::VERIFY_PEER
    else
      http_request.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
    
    if options[:tls_key_and_certificate_file]
      key_and_certificate       = File.read(options[:tls_key_and_certificate_file])
      options[:tls_key]         = OpenSSL::PKey::RSA.new(key_and_certificate)
      options[:tls_certificate] = OpenSSL::X509::Certificate.new(key_and_certificate)
    end
    
    if options[:tls_key] and options[:tls_certificate]
      http_request.key  = options[:tls_key]
      http_request.cert = options[:tls_certificate]
    elsif options[:tls_key] || options[:tls_certificate]
      raise ArgumentError, "Please specify both the certificate and private key (:tls_key and :tls_certificate)"
    end
  end
  
  if @configure_block
    @configure_block.call(http_request)
  end
  
  http_request
end

#pathObject

Returns the path (including the query) for the request



81
82
83
# File 'lib/rest/request.rb', line 81

def path
  [url.path.empty? ? '/' : url.path, url.query].compact.join('?')
end

#performObject

Performs the actual request and returns a REST::Response object with the response



174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/rest/request.rb', line 174

def perform
  self.request = request_for_verb
  request.body = body
  
  if options[:username] and options[:password]
    request.basic_auth(options[:username], options[:password])
  end
  
  http_request = http_request()
  response = http_request.start { |http| http.request(request) }
  REST::Response.new(response.code, response.instance_variable_get('@header'), response.body)
end

#proxy_envObject



85
86
87
88
89
90
# File 'lib/rest/request.rb', line 85

def proxy_env
  {
    'http'  => ENV['HTTP_PROXY']  || ENV['http_proxy'],
    'https' => ENV['HTTPS_PROXY'] || ENV['https_proxy']
  }
end

#proxy_settingsObject



92
93
94
# File 'lib/rest/request.rb', line 92

def proxy_settings
  proxy_env[url.scheme] ? URI.parse(proxy_env[url.scheme]) : nil
end

#request_for_verbObject



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rest/request.rb', line 150

def request_for_verb
  case verb
  when :get
    Net::HTTP::Get.new(path, headers)
  when :head
    Net::HTTP::Head.new(path, headers)
  when :delete
    Net::HTTP::Delete.new(path, headers)
  when :patch
    if defined?(Net::HTTP::Patch)
      Net::HTTP::Patch.new(path, headers)
    else
      raise ArgumentError, "This version of the Ruby standard library doesn't support PATCH"
    end
  when :put
    Net::HTTP::Put.new(path, headers)
  when :post
    Net::HTTP::Post.new(path, headers)
  else
    raise ArgumentError, "Unknown HTTP verb `#{verb}'"
  end
end