Class: HTTP::Request

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Headers::Mixin
Defined in:
lib/http/request.rb,
lib/http/request/body.rb,
lib/http/request/writer.rb

Defined Under Namespace

Classes: Body, UnsupportedMethodError, UnsupportedSchemeError, Writer

Constant Summary collapse

USER_AGENT =

Default User-Agent header value

"http.rb/#{HTTP::VERSION}"
METHODS =
[
  # RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
  :options, :get, :head, :post, :put, :delete, :trace, :connect,

  # RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV
  :propfind, :proppatch, :mkcol, :copy, :move, :lock, :unlock,

  # RFC 3648: WebDAV Ordered Collections Protocol
  :orderpatch,

  # RFC 3744: WebDAV Access Control Protocol
  :acl,

  # RFC 6352: vCard Extensions to WebDAV -- CardDAV
  :report,

  # RFC 5789: PATCH Method for HTTP
  :patch,

  # draft-reschke-webdav-search: WebDAV Search
  :search
].freeze
SCHEMES =

Allowed schemes

%i[http https ws wss].freeze
PORTS =

Default ports of supported schemes

{
  :http   => 80,
  :https  => 443,
  :ws     => 80,
  :wss    => 443
}.freeze

Instance Attribute Summary collapse

Attributes included from Headers::Mixin

#headers

Instance Method Summary collapse

Methods included from Headers::Mixin

#[], #[]=

Constructor Details

#initialize(opts) ⇒ Request

Returns a new instance of Request.

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (opts):

  • :version (String)
  • :verb (#to_s)

    HTTP request method

  • :uri (HTTP::URI, #to_s)
  • :headers (Hash)
  • :proxy (Hash)
  • :body (String, Enumerable, IO, nil)

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/http/request.rb', line 80

def initialize(opts)
  @verb   = opts.fetch(:verb).to_s.downcase.to_sym
  @uri    = normalize_uri(opts.fetch(:uri))
  @scheme = @uri.scheme.to_s.downcase.to_sym if @uri.scheme

  raise(UnsupportedMethodError, "unknown method: #{verb}") unless METHODS.include?(@verb)
  raise(UnsupportedSchemeError, "unknown scheme: #{scheme}") unless SCHEMES.include?(@scheme)

  @proxy   = opts[:proxy] || {}
  @body    = (body = opts[:body]).is_a?(Request::Body) ? body : Request::Body.new(body)
  @version = opts[:version] || "1.1"
  @headers = HTTP::Headers.coerce(opts[:headers] || {})

  @headers[Headers::HOST]        ||= default_host_header_value
  @headers[Headers::USER_AGENT]  ||= USER_AGENT
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



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

def body
  @body
end

#proxyObject (readonly)

Returns the value of attribute proxy.



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

def proxy
  @proxy
end

#schemeObject (readonly)

Scheme is normalized to be a lowercase symbol e.g. :http, :https



67
68
69
# File 'lib/http/request.rb', line 67

def scheme
  @scheme
end

#uriObject (readonly)



71
72
73
# File 'lib/http/request.rb', line 71

def uri
  @uri
end

#verbObject (readonly)

Method is given as a lowercase symbol e.g. :get, :post



64
65
66
# File 'lib/http/request.rb', line 64

def verb
  @verb
end

#versionObject (readonly)

Returns the value of attribute version.



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

def version
  @version
end

Instance Method Details

#connect_using_proxy(socket) ⇒ Object

Setup tunnel through proxy for SSL request



144
145
146
# File 'lib/http/request.rb', line 144

def connect_using_proxy(socket)
  Request::Writer.new(socket, nil, proxy_connect_headers, proxy_connect_header).connect_through_proxy
end

#headlineObject

Compute HTTP request header for direct or proxy request



149
150
151
152
153
154
155
156
157
158
# File 'lib/http/request.rb', line 149

def headline
  request_uri =
    if using_proxy? && !uri.https?
      uri.omit(:fragment)
    else
      uri.request_uri
    end

  "#{verb.to_s.upcase} #{request_uri} HTTP/#{version}"
end

#include_proxy_authorization_headerObject

Compute and add the Proxy-Authorization header



134
135
136
# File 'lib/http/request.rb', line 134

def include_proxy_authorization_header
  headers[Headers::PROXY_AUTHORIZATION] = proxy_authorization_header
end

#include_proxy_headersObject



128
129
130
131
# File 'lib/http/request.rb', line 128

def include_proxy_headers
  headers.merge!(proxy[:proxy_headers]) if proxy.key?(:proxy_headers)
  include_proxy_authorization_header if using_authenticated_proxy?
end

#proxy_authorization_headerObject



138
139
140
141
# File 'lib/http/request.rb', line 138

def proxy_authorization_header
  digest = Base64.strict_encode64("#{proxy[:proxy_username]}:#{proxy[:proxy_password]}")
  "Basic #{digest}"
end

#proxy_connect_headerObject

Compute HTTP request header SSL proxy connection



161
162
163
# File 'lib/http/request.rb', line 161

def proxy_connect_header
  "CONNECT #{host}:#{port} HTTP/#{version}"
end

#proxy_connect_headersObject

Headers to send with proxy connect request



166
167
168
169
170
171
172
173
174
175
# File 'lib/http/request.rb', line 166

def proxy_connect_headers
  connect_headers = HTTP::Headers.coerce(
    Headers::HOST        => headers[Headers::HOST],
    Headers::USER_AGENT  => headers[Headers::USER_AGENT]
  )

  connect_headers[Headers::PROXY_AUTHORIZATION] = proxy_authorization_header if using_authenticated_proxy?
  connect_headers.merge!(proxy[:proxy_headers]) if proxy.key?(:proxy_headers)
  connect_headers
end

#redirect(uri, verb = @verb) ⇒ Object

Returns new Request with updated uri



98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/http/request.rb', line 98

def redirect(uri, verb = @verb)
  headers = self.headers.dup
  headers.delete(Headers::HOST)

  self.class.new(
    :verb         => verb,
    :uri          => @uri.join(uri),
    :headers      => headers,
    :proxy        => proxy,
    :body         => body.source,
    :version      => version
  )
end

#socket_hostObject

Host for tcp socket



178
179
180
# File 'lib/http/request.rb', line 178

def socket_host
  using_proxy? ? proxy[:proxy_address] : host
end

#socket_portObject

Port for tcp socket



183
184
185
# File 'lib/http/request.rb', line 183

def socket_port
  using_proxy? ? proxy[:proxy_port] : port
end

#stream(socket) ⇒ Object

Stream the request to a socket



113
114
115
116
# File 'lib/http/request.rb', line 113

def stream(socket)
  include_proxy_headers if using_proxy? && !@uri.https?
  Request::Writer.new(socket, body, headers, headline).stream
end

#using_authenticated_proxy?Boolean

Is this request using an authenticated proxy?

Returns:

  • (Boolean)


124
125
126
# File 'lib/http/request.rb', line 124

def using_authenticated_proxy?
  proxy && proxy.keys.size >= 4
end

#using_proxy?Boolean

Is this request using a proxy?

Returns:

  • (Boolean)


119
120
121
# File 'lib/http/request.rb', line 119

def using_proxy?
  proxy && proxy.keys.size >= 2
end