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 = {}) ⇒ 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

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'}
)

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'
})


63
64
65
66
67
68
69
# File 'lib/rest/request.rb', line 63

def initialize(verb, url, body=nil, headers={}, options={})
  @verb = verb
  @url = url
  @body = body
  @headers = headers
  @options = options
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) ⇒ Object

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

See new for options.



172
173
174
175
# File 'lib/rest/request.rb', line 172

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

Instance Method Details

#http_proxyObject



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

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

#http_requestObject



93
94
95
96
97
98
99
# File 'lib/rest/request.rb', line 93

def http_request
  if http_proxy
    http_proxy.new(url.host, url.port)
  else
    Net::HTTP.new(url.host, url.port)
  end
end

#pathObject

Returns the path (including the query) for the request



72
73
74
# File 'lib/rest/request.rb', line 72

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

#performObject

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



102
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rest/request.rb', line 102

def perform
  case verb
  when :get
    self.request = Net::HTTP::Get.new(path, headers)
  when :head
    self.request = Net::HTTP::Head.new(path, headers)
  when :delete
    self.request = Net::HTTP::Delete.new(path, headers)
  when :patch
    self.request = Net::HTTP::Patch.new(path, headers)
    self.request.body = body
  when :put
    self.request = Net::HTTP::Put.new(path, headers)
    self.request.body = body
  when :post
    self.request = Net::HTTP::Post.new(path, headers)
    self.request.body = body
  else
    raise ArgumentError, "Unknown HTTP verb `#{verb}'"
  end
  
  if options[:username] and options[:password]
    request.basic_auth(options[:username], options[:password])
  end
  
  http_request = http_request()
  
  # enable SSL/TLS
  if url.scheme == 'https'
    require 'net/https'
    require 'openssl'
    
    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
  
  begin
    response = http_request.start { |http| http.request(request) }
  rescue EOFError => error
    raise REST::DisconnectedError, error.message
  end
  REST::Response.new(response.code, response.instance_variable_get('@header'), response.body)
end

#proxy_envObject



76
77
78
79
80
81
# File 'lib/rest/request.rb', line 76

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

#proxy_settingsObject



83
84
85
# File 'lib/rest/request.rb', line 83

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