Class: HTTY::Rack::Request

Inherits:
Payload
  • Object
show all
Defined in:
lib/htty/rack/request.rb

Overview

Encapsulates an HTTP(S) request.

Constant Summary collapse

COOKIES_HEADER_NAME =
'Cookie'
METHODS_SENDING_BODY =
[:post, :put]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(address = "/") ⇒ Request

Initializes a new HTTY::Request with a #uri corresponding to the specified address.



124
125
126
127
128
# File 'lib/htty/rack/request.rb', line 124

def initialize(address = "/")
  super({:headers => [['User-Agent', "htty/#{HTTY::VERSION}"]]})
  @uri = self.class.parse_uri(address)
  establish_content_length
end

Instance Attribute Details

#appObject

Returns the value of attribute app.



11
12
13
# File 'lib/htty/rack/request.rb', line 11

def app
  @app
end

#app_fileObject

Returns the value of attribute app_file.



11
12
13
# File 'lib/htty/rack/request.rb', line 11

def app_file
  @app_file
end

#request_methodObject (readonly)

Returns the HTTP method of the request, if any.



114
115
116
# File 'lib/htty/rack/request.rb', line 114

def request_method
  @request_method
end

#responseObject

Returns the response received for the request, if any.



117
118
119
# File 'lib/htty/rack/request.rb', line 117

def response
  @response
end

#uriObject

Returns the URI of the request.



120
121
122
# File 'lib/htty/rack/request.rb', line 120

def uri
  @uri
end

Class Method Details

.build_authority(components) ⇒ Object

Returns a URI authority (a combination of userinfo, host, and port) corresponding to the specified components hash. Valid components keys include:

  • :userinfo

  • :host

  • :port



24
25
26
27
28
29
30
# File 'lib/htty/rack/request.rb', line 24

def self.build_authority(components)
  userinfo_and_host = [components[:userinfo],
                       components[:host]].compact.join('@')
  all               = [userinfo_and_host, components[:port]].compact.join(':')
  return nil if (all == '')
  all
end

.build_path_query_and_fragment(components) ⇒ Object

Returns a combination of a URI path, query, and fragment, corresponding to the specified components hash. Valid components keys include:

  • :path

  • :query

  • :fragment



38
39
40
41
42
43
44
45
# File 'lib/htty/rack/request.rb', line 38

def self.build_path_query_and_fragment(components)
  path     = components[:path]
  query    = components[:query]    ? "?#{components[:query]}"    : nil
  fragment = components[:fragment] ? "##{components[:fragment]}" : nil
  all      = [path, query, fragment].compact.join
  return nil if (all == '')
  all
end

.build_uri(components) ⇒ Object

Returns a URI corresponding to the specified components hash, or raises URI::InvalidURIError. Valid components keys include:

  • :scheme

  • :userinfo

  • :host

  • :port

  • :path

  • :query

  • :fragment



57
58
59
60
61
62
63
# File 'lib/htty/rack/request.rb', line 57

def self.build_uri(components)
  scheme                  = (components[:scheme] || 'http') + '://'
  authority               = build_authority(components)
  path_query_and_fragment = build_path_query_and_fragment(components)
  path_query_and_fragment ||= '/' if authority
  URI.parse([path_query_and_fragment].join)
end

.parse_uri(address) ⇒ Object

Returns a URI corresponding to the specified address, or raises URI::InvalidURIError.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/htty/rack/request.rb', line 67

def self.parse_uri(address)
  address = '0.0.0.0' if address.nil? || (address == '')

  scheme_missing = false
  if (address !~ /^[a-z]+:\/\//) && (address !~ /^mailto:/)
    scheme_missing = true
    address = 'http://' + address
  end

  scheme,
  userinfo,
  host,
  port,
  registry, # Not used by HTTP
  path,
  opaque,   # Not used by HTTP
  query,
  fragment = URI.split(address)

  scheme = nil if scheme_missing
  path   = nil if (path == '')

  unless scheme
    scheme = (port.to_i == URI::HTTPS::DEFAULT_PORT) ? 'https' : 'http'
  end

  build_uri :scheme   => scheme,
            :userinfo => userinfo,
            :host     => host,
            :port     => port,
            :path     => path,
            :query    => query,
            :fragment => fragment
end

Instance Method Details

#==(other_request) ⇒ Object Also known as: eql?

Returns true if other_request is equivalent to the request.



137
138
139
140
141
# File 'lib/htty/rack/request.rb', line 137

def ==(other_request)
  return false unless super(other_request)
  return false unless other_request.kind_of?(self.class)
  (other_request.response == response) && (other_request.uri == uri)
end

#address(address) ⇒ Object

Establishes a new #uri corresponding to the specified address. If the host of the address is different from the host of #uri, then #cookies are cleared.



147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/htty/rack/request.rb', line 147

def address(address)
  uri = self.class.parse_uri(address)
  if response
    dup = dup_without_response
    return self.class.clear_cookies_if_host_changes(dup) do
      dup.uri = uri
    end
  end

  self.class.clear_cookies_if_host_changes self do
    @uri = uri
  end
end

#body_set(body) ⇒ Object

Sets the body of the request.



162
163
164
165
166
167
# File 'lib/htty/rack/request.rb', line 162

def body_set(body)
  return dup_without_response.body_set(body) if response

  @body = body ? body.to_s : nil
  establish_content_length
end

#body_unsetObject

Clears the body of the request.



170
171
172
# File 'lib/htty/rack/request.rb', line 170

def body_unset
  body_set nil
end

#connect!Object

Makes an HTTP CONNECT request using the path of #uri.



175
176
177
# File 'lib/htty/rack/request.rb', line 175

def connect!
  request! :connect
end

Appends to #cookies using the specified name (required) and value (optional).



181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/htty/rack/request.rb', line 181

def cookie_add(name, value=nil)
  return dup_without_response.cookie_add(name, value) if response

  cookies_string = HTTY::CookiesUtil.cookies_to_string(cookies +
                                                       [[name.to_s, value]])
  if cookies_string
    @headers[COOKIES_HEADER_NAME] = cookies_string
  else
    @headers.delete COOKIES_HEADER_NAME
  end
  self
end

Removes the last element of #cookies having the specified name.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/htty/rack/request.rb', line 195

def cookie_remove(name)
  return dup_without_response.cookie_remove(name) if response

  # Remove just one matching cookie from the end.
  rejected = false
  new_cookies = cookies.reverse.reject do |cookie_name, cookie_value|
    if !rejected && (cookie_name == name)
      rejected = true
    else
      false
    end
  end.reverse

  cookies_string = HTTY::CookiesUtil.cookies_to_string(new_cookies)
  if cookies_string
    @headers[COOKIES_HEADER_NAME] = cookies_string
  else
    @headers.delete COOKIES_HEADER_NAME
  end
  self
end

#cookiesObject

Returns an array of the cookies belonging to the request.



218
219
220
# File 'lib/htty/rack/request.rb', line 218

def cookies
  HTTY::CookiesUtil.cookies_from_string @headers[COOKIES_HEADER_NAME]
end

#cookies_remove_allObject

Removes all #cookies.



223
224
225
226
227
228
# File 'lib/htty/rack/request.rb', line 223

def cookies_remove_all
  return dup_without_response.cookies_remove_all if response

  @headers.delete COOKIES_HEADER_NAME
  self
end

#cookies_use(response) ⇒ Object

Sets #cookies according to the Set-Cookie header of the specified response, or raises either HTTY::NoResponseError or HTTY::NoSetCookieHeaderError.

Raises:

  • (HTTY::NoResponseError)


233
234
235
236
237
238
239
240
241
242
243
# File 'lib/htty/rack/request.rb', line 233

def cookies_use(response)
  raise HTTY::NoResponseError unless response

  cookies_header = response.headers.detect do |name, value|
    name == HTTY::Response::COOKIES_HEADER_NAME
  end
  unless cookies_header && cookies_header.last
    raise HTTY::NoSetCookieHeaderError
  end
  header_set COOKIES_HEADER_NAME, cookies_header.last
end

#delete!Object

Makes an HTTP DELETE request using the path of #uri.



246
247
248
# File 'lib/htty/rack/request.rb', line 246

def delete!
  request! :delete
end

#follow(response) ⇒ Object

Establishes a new #uri according to the Location header of the specified response, or raises either HTTY::NoResponseError or HTTY::NoLocationHeaderError.

Raises:

  • (HTTY::NoResponseError)


253
254
255
256
257
258
259
260
261
262
263
# File 'lib/htty/rack/request.rb', line 253

def follow(response)
  raise HTTY::NoResponseError unless response

  location_header = response.headers.detect do |name, value|
    name == 'Location'
  end
  unless location_header && location_header.last
    raise HTTY::NoLocationHeaderError
  end
  address location_header.last
end

#fragment_set(fragment) ⇒ Object

Establishes a new #uri with the specified fragment.



266
267
268
# File 'lib/htty/rack/request.rb', line 266

def fragment_set(fragment)
  rebuild_uri :fragment => fragment
end

#fragment_unsetObject

Establishes a new #uri without a fragment.



271
272
273
# File 'lib/htty/rack/request.rb', line 271

def fragment_unset
  fragment_set nil
end

#get!Object

Makes an HTTP GET request using the path of #uri.



276
277
278
# File 'lib/htty/rack/request.rb', line 276

def get!
  request! :get
end

#head!Object

Makes an HTTP HEAD request using the path of #uri.



281
282
283
# File 'lib/htty/rack/request.rb', line 281

def head!
  request! :head
end

#header_set(name, value) ⇒ Object

Appends to #headers or changes the element of #headers using the specified name and value.



287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/htty/rack/request.rb', line 287

def header_set(name, value)
  return dup_without_response.header_set(name, value) if response

  name = name.to_s
  if value.nil?
    @headers.delete name
    return self
  end

  @headers[name] = value.to_s
  self
end

#header_unset(name) ⇒ Object

Removes the element of #headers having the specified name.



301
302
303
# File 'lib/htty/rack/request.rb', line 301

def header_unset(name)
  header_set name, nil
end

#headers(include_content_length = METHODS_SENDING_BODY.include?(request_method)) ⇒ Object

Returns an array of the headers belonging to the payload. If include_content_length is false, then a ‘Content Length’ header will be omitted. If include_content_length is not specified, then it will be true if #request_method is an HTTP method for which body content is expected.



310
311
312
313
314
315
316
317
318
319
# File 'lib/htty/rack/request.rb', line 310

def headers(include_content_length=
            METHODS_SENDING_BODY.include?(request_method))
  unless include_content_length
    return super().reject do |name, value|
      name == 'Content-Length'
    end
  end

  super()
end

#headers_unset_allObject

Removes all #headers.



322
323
324
325
326
327
# File 'lib/htty/rack/request.rb', line 322

def headers_unset_all
  return dup_without_response.headers_unset_all if response

  @headers.clear
  self
end

#host_set(host) ⇒ Object

Establishes a new #uri with the specified host.



330
331
332
# File 'lib/htty/rack/request.rb', line 330

def host_set(host)
  rebuild_uri :host => host
end

#initialize_copy(source) ⇒ Object

:nodoc:



130
131
132
133
134
# File 'lib/htty/rack/request.rb', line 130

def initialize_copy(source) #:nodoc:
  super
  @response = @response.dup if @response
  @uri      = @uri.dup
end

#options!Object

Makes an HTTP OPTIONS request using the path of #uri.



335
336
337
# File 'lib/htty/rack/request.rb', line 335

def options!
  request! :options
end

#patch!Object

Makes an HTTP PATCH request using the path of #uri.



340
341
342
# File 'lib/htty/rack/request.rb', line 340

def patch!
  request! :patch
end

#path_set(path) ⇒ Object

Establishes a new #uri with the specified path which may be absolute or relative.



346
347
348
349
# File 'lib/htty/rack/request.rb', line 346

def path_set(path)
  absolute_path = (Pathname.new(uri.path) + path).to_s
  rebuild_uri :path => absolute_path
end

#port_set(port) ⇒ Object

Establishes a new #uri with the specified port.



352
353
354
# File 'lib/htty/rack/request.rb', line 352

def port_set(port)
  rebuild_uri :port => port
end

#post!Object

Makes an HTTP POST request using the path of #uri.



357
358
359
# File 'lib/htty/rack/request.rb', line 357

def post!
  request! :post
end

#put!Object

Makes an HTTP PUT request using the path of #uri.



362
363
364
# File 'lib/htty/rack/request.rb', line 362

def put!
  request! :put
end

#query_set(name, value) ⇒ Object

Establishes a new #uri, with the specified value for the query-string parameter specified by name.



368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/htty/rack/request.rb', line 368

def query_set(name, value)
  query     = uri.query ? "&#{uri.query}&" : ''
  parameter = Regexp.new("&#{Regexp.escape name}=.+?&")
  if query =~ parameter
    new_query = value.nil? ?
                query.gsub(parameter, '&') :
                query.gsub(parameter, "&#{name}=#{value}&")
  else
    new_query = value.nil? ? query : "#{query}#{name}=#{value}"
  end
  new_query = new_query.gsub(/^&/, '').gsub(/&$/, '')
  new_query = nil if (new_query == '')
  rebuild_uri :query => new_query
end

#query_unset(name) ⇒ Object

Establishes a new #uri, without the query-string parameter specified by name.



385
386
387
# File 'lib/htty/rack/request.rb', line 385

def query_unset(name)
  query_set name, nil
end

#query_unset_allObject

Establishes a new #uri without a query string.



390
391
392
# File 'lib/htty/rack/request.rb', line 390

def query_unset_all
  rebuild_uri :query => nil
end

#scheme_set(scheme) ⇒ Object

Establishes a new #uri with the specified scheme.



395
396
397
# File 'lib/htty/rack/request.rb', line 395

def scheme_set(scheme)
  rebuild_uri :scheme => scheme
end

#trace!Object

Makes an HTTP TRACE request using the path of #uri.



400
401
402
# File 'lib/htty/rack/request.rb', line 400

def trace!
  request! :trace
end

#userinfo_set(userinfo) ⇒ Object

Establishes a new #uri with the specified userinfo.



405
406
407
# File 'lib/htty/rack/request.rb', line 405

def userinfo_set(userinfo)
  rebuild_uri :userinfo => userinfo
end

#userinfo_unsetObject

Establishes a new #uri without userinfo.



410
411
412
# File 'lib/htty/rack/request.rb', line 410

def userinfo_unset
  userinfo_set nil
end