htty 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/.travis.yml +21 -3
- data/.yardopts +1 -1
- data/Gemfile +2 -2
- data/Guardfile +12 -10
- data/History.markdown +14 -0
- data/{MIT-LICENSE.markdown → License.markdown} +1 -1
- data/README.markdown +50 -65
- data/Rakefile +2 -2
- data/htty.gemspec +2 -2
- data/lib/htty/cli.rb +59 -74
- data/lib/htty/cli/command.rb +21 -20
- data/lib/htty/cli/commands/body_edit.rb +89 -0
- data/lib/htty/cli/commands/query_add.rb +3 -0
- data/lib/htty/cli/commands/query_set.rb +3 -0
- data/lib/htty/cli/commands/userinfo_set.rb +8 -14
- data/lib/htty/cli/display.rb +14 -12
- data/lib/htty/cli/input_device.rb +75 -0
- data/lib/htty/cli/url_escaping.rb +2 -2
- data/lib/htty/headers.rb +81 -0
- data/lib/htty/no_header_error.rb +10 -0
- data/lib/htty/payload.rb +22 -9
- data/lib/htty/request.rb +67 -43
- data/lib/htty/requests_util.rb +22 -8
- data/lib/htty/response.rb +20 -1
- data/lib/htty/uri.rb +16 -0
- data/lib/htty/version.rb +1 -1
- data/spec/integration/htty/cli/commands/query_add_spec.rb +7 -1
- data/spec/integration/htty/cli/commands/query_remove_spec.rb +19 -1
- data/spec/integration/htty/cli/commands/query_set_spec.rb +9 -3
- data/spec/integration/htty/cli/commands/query_unset_spec.rb +8 -2
- data/spec/spec_helper.rb +69 -0
- data/spec/unit/htty/cli/commands/address_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_edit_spec.rb +18 -0
- data/spec/unit/htty/cli/commands/body_request_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_response_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/body_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cd_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookie_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookie_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_remove_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/cookies_use_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/delete_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/exit_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/follow_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_remove_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/form_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/fragment_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/get_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/header_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/header_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_request_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_response_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_unset_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/headers_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/help_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/history_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/history_verbose_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/host_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_delete_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_get_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_head_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_options_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_patch_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_post_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_put_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/http_trace_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/patch_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/path_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/port_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/post_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/put_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_add_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_remove_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_unset_all_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/query_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/quit_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/reuse_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/scheme_set_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/shared_examples_for_commands.rb +55 -0
- data/spec/unit/htty/cli/commands/ssl_verification_off_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/ssl_verification_on_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/ssl_verification_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/status_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/undo_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/userinfo_clear_spec.rb +1 -1
- data/spec/unit/htty/cli/commands/userinfo_set_spec.rb +23 -1
- data/spec/unit/htty/cli/commands/userinfo_unset_spec.rb +1 -1
- data/spec/unit/htty/cli/display_spec.rb +84 -0
- data/spec/unit/htty/cli_spec.rb +1 -1
- data/spec/unit/htty/command.rb +47 -0
- data/spec/unit/htty/{ordered_hash_spec.rb → headers_spec.rb} +4 -4
- data/spec/unit/htty/payload_spec.rb +60 -0
- data/spec/unit/htty/preferences_spec.rb +1 -1
- data/spec/unit/htty/request_follow_spec.rb +94 -0
- data/spec/unit/htty/request_spec.rb +5 -187
- data/spec/unit/htty/request_userinfo_spec.rb +208 -0
- data/spec/unit/htty/session_spec.rb +1 -1
- data/spec/unit/htty/shared_examples_for_requests.rb +32 -0
- data/spec/unit/htty/url_escaping.rb +70 -0
- data/spec/unit/htty/version_spec.rb +1 -1
- metadata +43 -30
- data/lib/htty/ordered_hash.rb +0 -68
data/lib/htty/payload.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
require File.expand_path("#{File.dirname __FILE__}/
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/headers")
|
|
2
|
+
require File.expand_path("#{File.dirname __FILE__}/no_header_error")
|
|
3
|
+
require File.expand_path("#{File.dirname __FILE__}/cookies_util")
|
|
2
4
|
|
|
3
5
|
module HTTY; end
|
|
4
6
|
|
|
@@ -20,6 +22,24 @@ class HTTY::Payload
|
|
|
20
22
|
@headers.to_a
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
def headers_with_key(key)
|
|
26
|
+
headers.select do |header_key, header_value|
|
|
27
|
+
key.downcase == header_key.downcase
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def header(key, otherwise=:__no_default_value_given)
|
|
32
|
+
all_headers_with_key = headers_with_key(key)
|
|
33
|
+
return all_headers_with_key.last.last unless all_headers_with_key.empty?
|
|
34
|
+
raise otherwise if otherwise.is_a? Exception
|
|
35
|
+
return otherwise unless otherwise == :__no_default_value_given
|
|
36
|
+
raise HTTY::NoHeaderError.new(key)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def cookies_from(cookies_header_key)
|
|
40
|
+
HTTY::CookiesUtil.cookies_from_string header(cookies_header_key, nil)
|
|
41
|
+
end
|
|
42
|
+
|
|
23
43
|
protected
|
|
24
44
|
|
|
25
45
|
# Initializes a new HTTY::Payload with attribute values specified in the
|
|
@@ -31,17 +51,10 @@ protected
|
|
|
31
51
|
# * <tt>:headers</tt>
|
|
32
52
|
def initialize(attributes={})
|
|
33
53
|
@body = attributes[:body]
|
|
34
|
-
@headers = HTTY::
|
|
54
|
+
@headers = HTTY::Headers.new
|
|
35
55
|
Array(attributes[:headers]).each do |name, value|
|
|
36
56
|
@headers[name] = value
|
|
37
57
|
end
|
|
38
58
|
end
|
|
39
59
|
|
|
40
|
-
# @private
|
|
41
|
-
def initialize_copy(source)
|
|
42
|
-
super
|
|
43
|
-
@body = @body.dup if @body
|
|
44
|
-
@headers = @headers.dup
|
|
45
|
-
end
|
|
46
|
-
|
|
47
60
|
end
|
data/lib/htty/request.rb
CHANGED
|
@@ -6,6 +6,7 @@ require File.expand_path("#{File.dirname __FILE__}/cookies_util")
|
|
|
6
6
|
require File.expand_path("#{File.dirname __FILE__}/no_location_header_error")
|
|
7
7
|
require File.expand_path("#{File.dirname __FILE__}/no_response_error")
|
|
8
8
|
require File.expand_path("#{File.dirname __FILE__}/no_set_cookie_header_error")
|
|
9
|
+
require File.expand_path("#{File.dirname __FILE__}/uri")
|
|
9
10
|
require File.expand_path("#{File.dirname __FILE__}/payload")
|
|
10
11
|
require File.expand_path("#{File.dirname __FILE__}/requests_util")
|
|
11
12
|
require File.expand_path("#{File.dirname __FILE__}/response")
|
|
@@ -141,13 +142,6 @@ public
|
|
|
141
142
|
establish_content_length
|
|
142
143
|
end
|
|
143
144
|
|
|
144
|
-
# @private
|
|
145
|
-
def initialize_copy(source)
|
|
146
|
-
super
|
|
147
|
-
@response = @response.dup if @response
|
|
148
|
-
@uri = @uri.dup
|
|
149
|
-
end
|
|
150
|
-
|
|
151
145
|
# Returns +true+ if _other_request_ is equivalent to the request.
|
|
152
146
|
def ==(other_request)
|
|
153
147
|
return false unless super(other_request)
|
|
@@ -229,9 +223,14 @@ public
|
|
|
229
223
|
self
|
|
230
224
|
end
|
|
231
225
|
|
|
226
|
+
# Returns true if has some cookies.
|
|
227
|
+
def cookies?
|
|
228
|
+
not cookies.empty?
|
|
229
|
+
end
|
|
230
|
+
|
|
232
231
|
# Returns an array of the cookies belonging to the request.
|
|
233
232
|
def cookies
|
|
234
|
-
|
|
233
|
+
cookies_from(COOKIES_HEADER_NAME)
|
|
235
234
|
end
|
|
236
235
|
|
|
237
236
|
# Removes all #cookies.
|
|
@@ -267,14 +266,7 @@ public
|
|
|
267
266
|
# HTTY::NoLocationHeaderError.
|
|
268
267
|
def follow(response)
|
|
269
268
|
raise HTTY::NoResponseError unless response
|
|
270
|
-
|
|
271
|
-
location_header = response.headers.detect do |name, value|
|
|
272
|
-
name == HTTY::Response::LOCATION_HEADER_NAME
|
|
273
|
-
end
|
|
274
|
-
unless location_header && location_header.last
|
|
275
|
-
raise HTTY::NoLocationHeaderError
|
|
276
|
-
end
|
|
277
|
-
address location_header.last
|
|
269
|
+
response.follow_relative_to(self)
|
|
278
270
|
end
|
|
279
271
|
|
|
280
272
|
# Establishes a new #uri with the specified _fragment_.
|
|
@@ -302,13 +294,29 @@ public
|
|
|
302
294
|
def header_set(name, value)
|
|
303
295
|
return dup_without_response.header_set(name, value) if response
|
|
304
296
|
|
|
305
|
-
name = name.to_s
|
|
297
|
+
name = name && name.to_s
|
|
298
|
+
value = value && value.to_s
|
|
299
|
+
|
|
300
|
+
# to avoid recursion when rebuild_uri
|
|
301
|
+
return self if @headers[name] == value
|
|
302
|
+
|
|
306
303
|
if value.nil?
|
|
307
304
|
@headers.delete name
|
|
305
|
+
if name.downcase == AUTHORIZATION_HEADER_NAME.downcase
|
|
306
|
+
return rebuild_uri :userinfo => nil
|
|
307
|
+
end
|
|
308
308
|
return self
|
|
309
309
|
end
|
|
310
310
|
|
|
311
|
-
@headers[name] = value
|
|
311
|
+
@headers[name] = value
|
|
312
|
+
if name.downcase == AUTHORIZATION_HEADER_NAME.downcase
|
|
313
|
+
HTTY::Headers.credentials_from(value) do |username, password|
|
|
314
|
+
return rebuild_uri :userinfo => [
|
|
315
|
+
HTTY::URI.escape_component(username),
|
|
316
|
+
HTTY::URI.escape_component(password)
|
|
317
|
+
].compact.join(':')
|
|
318
|
+
end
|
|
319
|
+
end
|
|
312
320
|
self
|
|
313
321
|
end
|
|
314
322
|
|
|
@@ -317,6 +325,14 @@ public
|
|
|
317
325
|
header_set name, nil
|
|
318
326
|
end
|
|
319
327
|
|
|
328
|
+
# Removes all #headers.
|
|
329
|
+
def headers_unset_all
|
|
330
|
+
return dup_without_response.headers_unset_all if response
|
|
331
|
+
|
|
332
|
+
@headers.clear
|
|
333
|
+
rebuild_uri :userinfo => nil
|
|
334
|
+
end
|
|
335
|
+
|
|
320
336
|
# Returns an array of the headers belonging to the payload. If
|
|
321
337
|
# _include_content_length_ is +false+, then a 'Content Length' header will be
|
|
322
338
|
# omitted. If _include_content_length_ is not specified, then it will be
|
|
@@ -333,14 +349,6 @@ public
|
|
|
333
349
|
super()
|
|
334
350
|
end
|
|
335
351
|
|
|
336
|
-
# Removes all #headers.
|
|
337
|
-
def headers_unset_all
|
|
338
|
-
return dup_without_response.headers_unset_all if response
|
|
339
|
-
|
|
340
|
-
@headers.clear
|
|
341
|
-
self
|
|
342
|
-
end
|
|
343
|
-
|
|
344
352
|
# Establishes a new #uri with the specified _host_.
|
|
345
353
|
def host_set(host)
|
|
346
354
|
rebuild_uri :host => host
|
|
@@ -383,8 +391,34 @@ public
|
|
|
383
391
|
def query_add(name, value=nil)
|
|
384
392
|
entries = current_query_entries
|
|
385
393
|
entries << name + (value.nil? ? '' : "=#{value}")
|
|
386
|
-
|
|
387
|
-
|
|
394
|
+
query_set_all(entries)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Establishes a new #uri with the specified _value_ for the query-string
|
|
398
|
+
# parameter specified by _name_. The _value_ is optional.
|
|
399
|
+
#
|
|
400
|
+
# If there is more than one query-string parameter named _name_, they are
|
|
401
|
+
# replaced by a single one with the specified _value_.
|
|
402
|
+
def query_set(name, value=nil)
|
|
403
|
+
entries = current_query_entries
|
|
404
|
+
add_or_replace_field(entries, name, value)
|
|
405
|
+
query_set_all(entries)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# Establishes a new #uri with the query-string parameter specified by by
|
|
409
|
+
# _query_string_ parameter
|
|
410
|
+
def query_set_all(query_string)
|
|
411
|
+
# _query_string_ as an array of parameters is only for internal usage
|
|
412
|
+
query_string =
|
|
413
|
+
case query_string
|
|
414
|
+
when Array
|
|
415
|
+
query_string.empty? ? nil : query_string.join('&')
|
|
416
|
+
when String
|
|
417
|
+
query_string
|
|
418
|
+
else
|
|
419
|
+
nil
|
|
420
|
+
end
|
|
421
|
+
rebuild_uri :query => query_string
|
|
388
422
|
end
|
|
389
423
|
|
|
390
424
|
# Establishes a new #uri, removing the last query-string parameter specified
|
|
@@ -401,19 +435,7 @@ public
|
|
|
401
435
|
break
|
|
402
436
|
end
|
|
403
437
|
end
|
|
404
|
-
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
# Establishes a new #uri with the specified _value_ for the query-string
|
|
408
|
-
# parameter specified by _name_. The _value_ is optional.
|
|
409
|
-
#
|
|
410
|
-
# If there is more than one query-string parameter named _name_, they are
|
|
411
|
-
# replaced by a single one with the specified _value_.
|
|
412
|
-
def query_set(name, value=nil)
|
|
413
|
-
entries = current_query_entries
|
|
414
|
-
add_or_replace_field(entries, name, value)
|
|
415
|
-
new_query = entries.empty? ? nil : entries.join('&')
|
|
416
|
-
rebuild_uri :query => new_query
|
|
438
|
+
query_set_all(entries)
|
|
417
439
|
end
|
|
418
440
|
|
|
419
441
|
# Establishes a new #uri without the query-string parameter specified by
|
|
@@ -427,7 +449,7 @@ public
|
|
|
427
449
|
entries.delete_if do |entry|
|
|
428
450
|
entry =~ field_matcher(name)
|
|
429
451
|
end
|
|
430
|
-
|
|
452
|
+
query_set_all(entries)
|
|
431
453
|
end
|
|
432
454
|
|
|
433
455
|
# Establishes a new #uri without a query string.
|
|
@@ -484,8 +506,10 @@ protected
|
|
|
484
506
|
components = URI::HTTP::COMPONENT.inject({}) do |result, c|
|
|
485
507
|
result.merge c => uri.send(c)
|
|
486
508
|
end
|
|
509
|
+
components = components.merge(changed_components)
|
|
510
|
+
components[:query] = nil if components[:query] && components[:query].empty?
|
|
487
511
|
self.class.send(:set_up_cookies_and_authentication, self) do
|
|
488
|
-
@uri = self.class.build_uri(components
|
|
512
|
+
@uri = self.class.build_uri(components)
|
|
489
513
|
end
|
|
490
514
|
end
|
|
491
515
|
|
data/lib/htty/requests_util.rb
CHANGED
|
@@ -13,28 +13,28 @@ module HTTY::RequestsUtil
|
|
|
13
13
|
# Makes an HTTP DELETE request with the specified _request_.
|
|
14
14
|
def self.delete(request)
|
|
15
15
|
request(request) do |host|
|
|
16
|
-
host.delete request.send(:path_query_and_fragment), request
|
|
16
|
+
host.delete request.send(:path_query_and_fragment), headers_from(request)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# Makes an HTTP GET request with the specified _request_.
|
|
21
21
|
def self.get(request)
|
|
22
22
|
request(request) do |host|
|
|
23
|
-
host.request_get request.send(:path_query_and_fragment), request
|
|
23
|
+
host.request_get request.send(:path_query_and_fragment), headers_from(request)
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Makes an HTTP HEAD request with the specified _request_.
|
|
28
28
|
def self.head(request)
|
|
29
29
|
request(request) do |host|
|
|
30
|
-
host.head request.send(:path_query_and_fragment), request
|
|
30
|
+
host.head request.send(:path_query_and_fragment), headers_from(request)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Makes an HTTP OPTIONS request with the specified _request_.
|
|
35
35
|
def self.options(request)
|
|
36
36
|
request(request) do |host|
|
|
37
|
-
host.options request.send(:path_query_and_fragment), request
|
|
37
|
+
host.options request.send(:path_query_and_fragment), headers_from(request)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ module HTTY::RequestsUtil
|
|
|
43
43
|
request(request) do |host|
|
|
44
44
|
host.patch request.send(:path_query_and_fragment),
|
|
45
45
|
request.body,
|
|
46
|
-
request
|
|
46
|
+
headers_from(request)
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -52,7 +52,7 @@ module HTTY::RequestsUtil
|
|
|
52
52
|
request(request) do |host|
|
|
53
53
|
host.post request.send(:path_query_and_fragment),
|
|
54
54
|
request.body,
|
|
55
|
-
request
|
|
55
|
+
headers_from(request)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -61,14 +61,14 @@ module HTTY::RequestsUtil
|
|
|
61
61
|
request(request) do |host|
|
|
62
62
|
host.put request.send(:path_query_and_fragment),
|
|
63
63
|
request.body,
|
|
64
|
-
request
|
|
64
|
+
headers_from(request)
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Makes an HTTP TRACE request with the specified _request_.
|
|
69
69
|
def self.trace(request)
|
|
70
70
|
request(request) do |host|
|
|
71
|
-
host.trace request.send(:path_query_and_fragment), request
|
|
71
|
+
host.trace request.send(:path_query_and_fragment), headers_from(request)
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -106,4 +106,18 @@ private
|
|
|
106
106
|
request
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
+
def self.headers_from(request)
|
|
110
|
+
return request.headers unless HEADERS_MUST_BE_AN_HASH
|
|
111
|
+
return {} if request.headers.empty?
|
|
112
|
+
request.headers.flatten.each_slice(2).reduce({}) do |hash, pair|
|
|
113
|
+
hash[pair.first] = pair.last
|
|
114
|
+
hash
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# starting from 2.0.0 net/http requires headers to be hashes
|
|
119
|
+
require 'rubygems' # Not necessary under Ruby v2
|
|
120
|
+
HEADERS_MUST_BE_AN_HASH =
|
|
121
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0.0')
|
|
122
|
+
|
|
109
123
|
end
|
data/lib/htty/response.rb
CHANGED
|
@@ -23,11 +23,30 @@ class HTTY::Response < HTTY::Payload
|
|
|
23
23
|
def initialize(attributes={})
|
|
24
24
|
super attributes
|
|
25
25
|
@status = attributes[:status]
|
|
26
|
+
@already_followed = false
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
# Returns an array of the cookies belonging to the response.
|
|
29
30
|
def cookies
|
|
30
|
-
|
|
31
|
+
cookies_from(COOKIES_HEADER_NAME)
|
|
31
32
|
end
|
|
32
33
|
|
|
34
|
+
def follow_relative_to(request)
|
|
35
|
+
return request if @already_followed
|
|
36
|
+
location_uri = URI.parse(location_header = location)
|
|
37
|
+
if location_uri.absolute?
|
|
38
|
+
request.address location_header
|
|
39
|
+
else
|
|
40
|
+
request.
|
|
41
|
+
path_set(location_uri.path).
|
|
42
|
+
query_set_all(location_uri.query).
|
|
43
|
+
fragment_set(location_uri.fragment)
|
|
44
|
+
end
|
|
45
|
+
ensure
|
|
46
|
+
@already_followed = true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def location
|
|
50
|
+
header(LOCATION_HEADER_NAME, HTTY::NoLocationHeaderError.new)
|
|
51
|
+
end
|
|
33
52
|
end
|
data/lib/htty/uri.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module HTTY; end
|
|
4
|
+
|
|
5
|
+
class HTTY::URI
|
|
6
|
+
# There's a lot of confusion about this, the default implementation
|
|
7
|
+
# of URI.escape is marked as "obsolete", CGI.escape does another work,
|
|
8
|
+
# a safe solution seems to use https://github.com/sporkmonger/addressable
|
|
9
|
+
# without adding a new dependecy I found that encode all not unreserved
|
|
10
|
+
# characters (unfortunately that doesn't mean all reserved characters) it's
|
|
11
|
+
# a pretty safe solution, see http://tools.ietf.org/html/rfc3986#section-2.3
|
|
12
|
+
# URI.escape(a, /[^-_.~a-zA-Z0-9]/)
|
|
13
|
+
def self.escape_component(component)
|
|
14
|
+
URI.escape(component, /[^-_.~a-zA-Z0-9]/) unless component.nil?
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/htty/version.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/session")
|
|
3
3
|
require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/cli/commands/query_add")
|
|
4
4
|
|
|
@@ -15,6 +15,12 @@ describe HTTY::CLI::Commands::QueryAdd do
|
|
|
15
15
|
klass.new :session => session, :arguments => arguments
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
describe 'without an argument' do
|
|
19
|
+
it 'should raise an error' do
|
|
20
|
+
expect{instance.perform}.to raise_error(ArgumentError)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
18
24
|
describe 'with key argument only' do
|
|
19
25
|
describe 'without key already present' do
|
|
20
26
|
it 'should add key' do
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/session")
|
|
3
3
|
require File.expand_path("#{File.dirname __FILE__}/../../../../../lib/htty/cli/commands/query_remove")
|
|
4
4
|
|
|
@@ -15,6 +15,24 @@ describe HTTY::CLI::Commands::QueryRemove do
|
|
|
15
15
|
klass.new :session => session, :arguments => arguments
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
describe 'with existing query string with only one key and value' do
|
|
19
|
+
before :each do
|
|
20
|
+
session.requests.last.uri.query = 'test=true'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'with only key in query string' do
|
|
24
|
+
it 'should empty the query string' do
|
|
25
|
+
instance('test').perform
|
|
26
|
+
session.requests.last.uri.query.should be_nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should not leave a trailing question mark' do
|
|
30
|
+
instance('test').perform
|
|
31
|
+
session.requests.last.uri.to_s.should_not end_with('?')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
18
36
|
describe 'with existing query string with duplicate keys set' do
|
|
19
37
|
before :each do
|
|
20
38
|
session.requests.last.uri.query = 'test=true&test=false'
|