httparty 0.13.5 → 0.13.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of httparty might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +23 -0
- data/History +17 -0
- data/README.md +1 -1
- data/bin/httparty +5 -0
- data/features/command_line.feature +6 -1
- data/features/digest_authentication.feature +10 -0
- data/features/steps/mongrel_helper.rb +33 -0
- data/features/steps/remote_service_steps.rb +4 -0
- data/httparty.gemspec +1 -1
- data/lib/httparty.rb +24 -1
- data/lib/httparty/connection_adapter.rb +6 -4
- data/lib/httparty/logger/{apache_logger.rb → apache_formatter.rb} +1 -1
- data/lib/httparty/logger/{curl_logger.rb → curl_formatter.rb} +1 -1
- data/lib/httparty/logger/logger.rb +16 -8
- data/lib/httparty/net_digest_auth.rb +18 -2
- data/lib/httparty/parser.rb +4 -2
- data/lib/httparty/request.rb +26 -13
- data/lib/httparty/version.rb +1 -1
- data/spec/httparty/connection_adapter_spec.rb +14 -0
- data/spec/httparty/logger/{apache_logger_spec.rb → apache_formatter_spec.rb} +1 -1
- data/spec/httparty/logger/{curl_logger_spec.rb → curl_formatter_spec.rb} +1 -1
- data/spec/httparty/logger/logger_spec.rb +18 -2
- data/spec/httparty/net_digest_auth_spec.rb +39 -0
- data/spec/httparty/parser_spec.rb +7 -1
- data/spec/httparty/request_spec.rb +296 -95
- data/spec/httparty_spec.rb +70 -2
- data/spec/support/stub_response.rb +8 -2
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ff4fbf77e1502f71829faa6032ec50bce93aae6
|
4
|
+
data.tar.gz: bcd37d969fec45917adec0a7e6ac202308520601
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0edda1d12877f8dbec768ef37934ad0853c7383dfbb1d0f1051de314b469dfe9eed8da318ea5cea3112c39d2dbe7edec5b00785834bfdf77ba75877a2163002a
|
7
|
+
data.tar.gz: a97e1c55e863564388944cb4acf5ae2a49942a4df79dc09834025e7346929e9bd5a40b1e29d3f3cbdff479a4318ce1f100203da3f90b6b29085c433f2898bb0d
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
* Contributions will not be accepted without tests.
|
4
|
+
* Please post unconfirmed bugs to the mailing list first: https://groups.google.com/forum/#!forum/httparty-gem
|
5
|
+
* Don't change the version. The maintainers will handle that when they release.
|
6
|
+
* Always provide as much information and reproducibility as possible when filing an issue or submitting a pull request.
|
7
|
+
|
8
|
+
## Workflow
|
9
|
+
|
10
|
+
* Fork the project.
|
11
|
+
* Run `bundle`
|
12
|
+
* Run `bundle exec rake`
|
13
|
+
* Make your feature addition or bug fix.
|
14
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
15
|
+
* Run `bundle exec rake` (No, REALLY :))
|
16
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
|
17
|
+
* Send me a pull request. Bonus points for topic branches.
|
18
|
+
|
19
|
+
## Help and Docs
|
20
|
+
|
21
|
+
* https://groups.google.com/forum/#!forum/httparty-gem
|
22
|
+
* http://stackoverflow.com/questions/tagged/httparty
|
23
|
+
* http://rdoc.info/projects/jnunemaker/httparty
|
data/History
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
== 0.13.6
|
2
|
+
* avoid calling String#strip on invalid Strings
|
3
|
+
* preserve request method on 307 and 308 redirects
|
4
|
+
* output version with --version for command line bin
|
5
|
+
* maintain head request method across redirects by default
|
6
|
+
* add support for RFC2617 MD5-sess algorithm type
|
7
|
+
* add party popper emoji to post install message
|
8
|
+
|
9
|
+
== 0.13.5
|
10
|
+
* allow setting a custom URI adapter
|
11
|
+
|
12
|
+
== 0.13.4
|
13
|
+
* correct redirect url for redirect paths without leading slash
|
14
|
+
* remove core_extensions.rb as backwards compat for ruby 1.8 not needed
|
15
|
+
* replace URI.encode with ERB::Util.url_encode
|
16
|
+
* allow the response to be tapped
|
17
|
+
|
1
18
|
== 0.13.3
|
2
19
|
* minor improvement
|
3
20
|
* added option to allow for streaming large files without loading them into memory (672cdae)
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ gem install httparty
|
|
18
18
|
|
19
19
|
```ruby
|
20
20
|
# Use the class methods to get down to business quickly
|
21
|
-
response = HTTParty.get('
|
21
|
+
response = HTTParty.get('http://api.stackexchange.com/2.2/questions?site=stackoverflow')
|
22
22
|
|
23
23
|
puts response.body, response.code, response.message, response.headers.inspect
|
24
24
|
|
data/bin/httparty
CHANGED
@@ -9,6 +9,11 @@ Feature: Command Line
|
|
9
9
|
When I run `httparty --help`
|
10
10
|
Then the output should contain "-f, --format [FORMAT]"
|
11
11
|
|
12
|
+
Scenario: Show current version
|
13
|
+
When I run `httparty --version`
|
14
|
+
Then the output should contain "Version:"
|
15
|
+
And the output should not contain "You need to provide a URL"
|
16
|
+
|
12
17
|
Scenario: Make a get request
|
13
18
|
Given a remote deflate service on port '4001'
|
14
19
|
And the response from the service has a body of 'GET request'
|
@@ -87,4 +92,4 @@ Feature: Command Line
|
|
87
92
|
And that service is accessed at the path '/service.csv'
|
88
93
|
And the response from the service has a Content-Type of 'application/csv'
|
89
94
|
When I run `httparty http://0.0.0.0:4010/service.csv --format csv`
|
90
|
-
Then the output should contain '["Last Name", "Name"]'
|
95
|
+
Then the output should contain '["Last Name", "Name"]'
|
@@ -18,3 +18,13 @@ Feature: Digest Authentication
|
|
18
18
|
| username | password |
|
19
19
|
| jcash | maninblack |
|
20
20
|
Then the return value should match 'Digest Authenticated Page'
|
21
|
+
|
22
|
+
Scenario: Passing proper credentials to a page requiring Digest Authentication using md5-sess algorithm
|
23
|
+
Given a remote service that returns 'Digest Authenticated Page Using MD5-sess'
|
24
|
+
And that service is accessed at the path '/digest_auth.html'
|
25
|
+
And that service is protected by MD5-sess Digest Authentication
|
26
|
+
And that service requires the username 'jcash' with the password 'maninblack'
|
27
|
+
When I call HTTParty#get with '/digest_auth.html' and a digest_auth hash:
|
28
|
+
| username | password |
|
29
|
+
| jcash | maninblack |
|
30
|
+
Then the return value should match 'Digest Authenticated Page Using MD5-sess'
|
@@ -88,6 +88,39 @@ module DigestAuthentication
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
module DigestAuthenticationUsingMD5Sess
|
92
|
+
NONCE = 'nonce'
|
93
|
+
REALM = 'testrealm@host.com'
|
94
|
+
QOP = 'auth,auth-int'
|
95
|
+
def self.extended(base)
|
96
|
+
base.custom_headers["WWW-Authenticate"] = %(Digest realm="#{REALM}",qop="#{QOP}",algorithm="MD5-sess",nonce="#{NONCE}",opaque="opaque"')
|
97
|
+
end
|
98
|
+
|
99
|
+
def process(request, response)
|
100
|
+
if authorized?(request)
|
101
|
+
super
|
102
|
+
else
|
103
|
+
reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def md5(str)
|
108
|
+
Digest::MD5.hexdigest(str)
|
109
|
+
end
|
110
|
+
|
111
|
+
def authorized?(request)
|
112
|
+
auth = request.params["HTTP_AUTHORIZATION"]
|
113
|
+
params = {}
|
114
|
+
auth.to_s.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 }
|
115
|
+
a1a = [@username,REALM,@password].join(':')
|
116
|
+
a1 = [md5(a1a),NONCE,params['cnonce'] ].join(':')
|
117
|
+
a2 = [ request.params["REQUEST_METHOD"], request.params["REQUEST_URI"] ] .join(':')
|
118
|
+
expected_response = md5( [md5(a1), NONCE, params['nc'], params['cnonce'], QOP, md5(a2)].join(':') )
|
119
|
+
expected_response == params['response']
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
91
124
|
def new_mongrel_redirector(target_url, relative_path = false)
|
92
125
|
target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
|
93
126
|
Mongrel::RedirectHandler.new(target_url)
|
@@ -55,6 +55,10 @@ Given /that service is protected by Digest Authentication/ do
|
|
55
55
|
@handler.extend DigestAuthentication
|
56
56
|
end
|
57
57
|
|
58
|
+
Given /that service is protected by MD5-sess Digest Authentication/ do
|
59
|
+
@handler.extend DigestAuthenticationUsingMD5Sess
|
60
|
+
end
|
61
|
+
|
58
62
|
Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
|
59
63
|
@handler.username = username
|
60
64
|
@handler.password = password
|
data/httparty.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency 'multi_xml', ">= 0.5.2"
|
20
20
|
|
21
21
|
# If this line is removed, all hard partying will cease.
|
22
|
-
s.post_install_message = "When you HTTParty, you must party hard!"
|
22
|
+
s.post_install_message = "When you HTTParty, you must party hard! 🎉"
|
23
23
|
|
24
24
|
s.files = `git ls-files`.split("\n")
|
25
25
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/httparty.rb
CHANGED
@@ -39,6 +39,8 @@ module HTTParty
|
|
39
39
|
# [:+timeout+:] Timeout for opening connection and reading data.
|
40
40
|
# [:+local_host:] Local address to bind to before connecting.
|
41
41
|
# [:+local_port:] Local port to bind to before connecting.
|
42
|
+
# [:+body_steam:] Allow streaming to a REST server to specify a body_stream.
|
43
|
+
# [:+stream_body:] Allow for streaming large files without loading them into memory.
|
42
44
|
#
|
43
45
|
# There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are:
|
44
46
|
# * :+base_uri+: see HTTParty::ClassMethods.base_uri.
|
@@ -50,6 +52,7 @@ module HTTParty
|
|
50
52
|
# * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects.
|
51
53
|
# * :+no_follow+: see HTTParty::ClassMethods.no_follow.
|
52
54
|
# * :+parser+: see HTTParty::ClassMethods.parser.
|
55
|
+
# * :+uri_adapter+: see HTTParty::ClassMethods.uri_adapter
|
53
56
|
# * :+connection_adapter+: see HTTParty::ClassMethods.connection_adapter.
|
54
57
|
# * :+pem+: see HTTParty::ClassMethods.pem.
|
55
58
|
# * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer
|
@@ -265,7 +268,9 @@ module HTTParty
|
|
265
268
|
end
|
266
269
|
|
267
270
|
# Declare that you wish to maintain the chosen HTTP method across redirects.
|
268
|
-
# The default behavior is to follow redirects via the GET method
|
271
|
+
# The default behavior is to follow redirects via the GET method, except
|
272
|
+
# if you are making a HEAD request, in which case the default is to
|
273
|
+
# follow all redirects with HEAD requests.
|
269
274
|
# If you wish to maintain the original method, you can set this option to true.
|
270
275
|
#
|
271
276
|
# @example
|
@@ -420,6 +425,17 @@ module HTTParty
|
|
420
425
|
end
|
421
426
|
end
|
422
427
|
|
428
|
+
# Allows setting a custom URI adapter.
|
429
|
+
#
|
430
|
+
# class Foo
|
431
|
+
# include HTTParty
|
432
|
+
# uri_adapter Addressable::URI
|
433
|
+
# end
|
434
|
+
def uri_adapter(uri_adapter)
|
435
|
+
raise ArgumentError, 'The URI adapter should respond to #parse' unless uri_adapter.respond_to?(:parse)
|
436
|
+
default_options[:uri_adapter] = uri_adapter
|
437
|
+
end
|
438
|
+
|
423
439
|
# Allows setting a custom connection_adapter for the http connections
|
424
440
|
#
|
425
441
|
# @example
|
@@ -503,6 +519,7 @@ module HTTParty
|
|
503
519
|
|
504
520
|
# Perform a HEAD request to a path
|
505
521
|
def head(path, options = {}, &block)
|
522
|
+
ensure_method_maintained_across_redirects options
|
506
523
|
perform_request Net::HTTP::Head, path, options, &block
|
507
524
|
end
|
508
525
|
|
@@ -515,6 +532,12 @@ module HTTParty
|
|
515
532
|
|
516
533
|
private
|
517
534
|
|
535
|
+
def ensure_method_maintained_across_redirects(options)
|
536
|
+
unless options.has_key? :maintain_method_across_redirects
|
537
|
+
options[:maintain_method_across_redirects] = true
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
518
541
|
def perform_request(http_method, path, options, &block) #:nodoc:
|
519
542
|
options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
|
520
543
|
process_headers(options)
|
@@ -61,7 +61,8 @@ module HTTParty
|
|
61
61
|
attr_reader :uri, :options
|
62
62
|
|
63
63
|
def initialize(uri, options = {})
|
64
|
-
|
64
|
+
uri_adapter = options[:uri_adapter] || URI
|
65
|
+
raise ArgumentError, "uri must be a #{uri_adapter}, not a #{uri.class}" unless uri.is_a? uri_adapter
|
65
66
|
|
66
67
|
@uri = uri
|
67
68
|
@options = options
|
@@ -69,10 +70,11 @@ module HTTParty
|
|
69
70
|
|
70
71
|
def connection
|
71
72
|
host = clean_host(uri.host)
|
73
|
+
port = uri.port || (uri.scheme == 'https' ? 443 : 80)
|
72
74
|
if options[:http_proxyaddr]
|
73
|
-
http = Net::HTTP.new(host,
|
75
|
+
http = Net::HTTP.new(host, port, options[:http_proxyaddr], options[:http_proxyport], options[:http_proxyuser], options[:http_proxypass])
|
74
76
|
else
|
75
|
-
http = Net::HTTP.new(host,
|
77
|
+
http = Net::HTTP.new(host, port)
|
76
78
|
end
|
77
79
|
|
78
80
|
http.use_ssl = ssl_implied?(uri)
|
@@ -133,7 +135,7 @@ module HTTParty
|
|
133
135
|
end
|
134
136
|
|
135
137
|
def ssl_implied?(uri)
|
136
|
-
uri.port == 443 || uri.
|
138
|
+
uri.port == 443 || uri.scheme == 'https'
|
137
139
|
end
|
138
140
|
|
139
141
|
def attach_ssl_certificates(http, options)
|
@@ -1,18 +1,26 @@
|
|
1
|
-
require 'httparty/logger/
|
2
|
-
require 'httparty/logger/
|
1
|
+
require 'httparty/logger/apache_formatter'
|
2
|
+
require 'httparty/logger/curl_formatter'
|
3
3
|
|
4
4
|
module HTTParty
|
5
5
|
module Logger
|
6
|
+
def self.formatters
|
7
|
+
@formatters ||= {
|
8
|
+
:curl => Logger::CurlFormatter,
|
9
|
+
:apache => Logger::ApacheFormatter
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.add_formatter(name, formatter)
|
14
|
+
raise HTTParty::Error.new("Log Formatter with name #{name} already exists") if formatters.include?(name)
|
15
|
+
formatters.merge!(name.to_sym => formatter)
|
16
|
+
end
|
17
|
+
|
6
18
|
def self.build(logger, level, formatter)
|
7
19
|
level ||= :info
|
8
20
|
formatter ||= :apache
|
9
21
|
|
10
|
-
|
11
|
-
|
12
|
-
Logger::CurlLogger.new(logger, level)
|
13
|
-
else
|
14
|
-
Logger::ApacheLogger.new(logger, level)
|
15
|
-
end
|
22
|
+
logger_klass = formatters[formatter] || Logger::ApacheFormatter
|
23
|
+
logger_klass.new(logger, level)
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
@@ -41,6 +41,8 @@ module Net
|
|
41
41
|
%(response="#{request_digest}")
|
42
42
|
]
|
43
43
|
|
44
|
+
header << %(algorithm="#{@response['algorithm']}") if algorithm_present?
|
45
|
+
|
44
46
|
if qop_present?
|
45
47
|
fields = [
|
46
48
|
%(cnonce="#{@cnonce}"),
|
@@ -66,7 +68,8 @@ module Net
|
|
66
68
|
|
67
69
|
header =~ /Digest (.*)/
|
68
70
|
params = {}
|
69
|
-
$1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
71
|
+
non_quoted = $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
72
|
+
non_quoted.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 }
|
70
73
|
params
|
71
74
|
end
|
72
75
|
|
@@ -105,8 +108,21 @@ module Net
|
|
105
108
|
Digest::MD5.hexdigest(str)
|
106
109
|
end
|
107
110
|
|
111
|
+
def algorithm_present?
|
112
|
+
@response.key?('algorithm') && !@response['algorithm'].empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
def use_md5_sess?
|
116
|
+
algorithm_present? && @response['algorithm'] == 'MD5-sess'
|
117
|
+
end
|
118
|
+
|
108
119
|
def a1
|
109
|
-
[@username, @response['realm'], @password].join(
|
120
|
+
a1_user_realm_pwd = [@username, @response['realm'], @password].join(':')
|
121
|
+
if use_md5_sess?
|
122
|
+
[ md5(a1_user_realm_pwd), @response['nonce'], @cnonce ].join(':')
|
123
|
+
else
|
124
|
+
a1_user_realm_pwd
|
125
|
+
end
|
110
126
|
end
|
111
127
|
|
112
128
|
def a2
|
data/lib/httparty/parser.rb
CHANGED
@@ -98,7 +98,9 @@ module HTTParty
|
|
98
98
|
# @return [Object] the parsed body
|
99
99
|
# @return [nil] when the response body is nil, an empty string, spaces only or "null"
|
100
100
|
def parse
|
101
|
-
return nil if body.nil?
|
101
|
+
return nil if body.nil?
|
102
|
+
return nil if body == "null"
|
103
|
+
return nil if body.valid_encoding? && body.strip.empty?
|
102
104
|
if supports_format?
|
103
105
|
parse_supported_format
|
104
106
|
else
|
@@ -113,7 +115,7 @@ module HTTParty
|
|
113
115
|
end
|
114
116
|
|
115
117
|
def json
|
116
|
-
JSON.
|
118
|
+
JSON.parse(body, :quirks_mode => true, :allow_nan => true)
|
117
119
|
end
|
118
120
|
|
119
121
|
def csv
|
data/lib/httparty/request.rb
CHANGED
@@ -12,7 +12,7 @@ module HTTParty
|
|
12
12
|
Net::HTTP::Copy
|
13
13
|
]
|
14
14
|
|
15
|
-
SupportedURISchemes = [
|
15
|
+
SupportedURISchemes = ['http', 'https', 'webcal', nil]
|
16
16
|
|
17
17
|
NON_RAILS_QUERY_STRING_NORMALIZER = proc do |query|
|
18
18
|
Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
|
@@ -31,20 +31,30 @@ module HTTParty
|
|
31
31
|
|
32
32
|
def initialize(http_method, path, o = {})
|
33
33
|
self.http_method = http_method
|
34
|
-
self.path = path
|
35
34
|
self.options = {
|
36
35
|
limit: o.delete(:no_follow) ? 1 : 5,
|
37
36
|
assume_utf16_is_big_endian: true,
|
38
37
|
default_params: {},
|
39
38
|
follow_redirects: true,
|
40
39
|
parser: Parser,
|
40
|
+
uri_adapter: URI,
|
41
41
|
connection_adapter: ConnectionAdapter
|
42
42
|
}.merge(o)
|
43
|
+
self.path = path
|
43
44
|
set_basic_auth_from_uri
|
44
45
|
end
|
45
46
|
|
46
47
|
def path=(uri)
|
47
|
-
|
48
|
+
uri_adapter = options[:uri_adapter]
|
49
|
+
|
50
|
+
@path = if uri.is_a?(uri_adapter)
|
51
|
+
uri
|
52
|
+
elsif String.try_convert(uri)
|
53
|
+
uri_adapter.parse uri
|
54
|
+
else
|
55
|
+
raise ArgumentError,
|
56
|
+
"bad argument (expected #{uri_adapter} object or URI string)"
|
57
|
+
end
|
48
58
|
end
|
49
59
|
|
50
60
|
def request_uri(uri)
|
@@ -63,14 +73,14 @@ module HTTParty
|
|
63
73
|
path.path = last_uri_host + path.path
|
64
74
|
end
|
65
75
|
|
66
|
-
new_uri = path.relative? ?
|
76
|
+
new_uri = path.relative? ? options[:uri_adapter].parse("#{base_uri}#{path}") : path.clone
|
67
77
|
|
68
78
|
# avoid double query string on redirects [#12]
|
69
79
|
unless redirect
|
70
80
|
new_uri.query = query_string(new_uri)
|
71
81
|
end
|
72
82
|
|
73
|
-
unless SupportedURISchemes.include? new_uri.
|
83
|
+
unless SupportedURISchemes.include? new_uri.scheme
|
74
84
|
raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic"
|
75
85
|
end
|
76
86
|
|
@@ -78,7 +88,13 @@ module HTTParty
|
|
78
88
|
end
|
79
89
|
|
80
90
|
def base_uri
|
81
|
-
redirect
|
91
|
+
if redirect
|
92
|
+
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
93
|
+
base_uri += ":#{@last_uri.port}" if @last_uri.port != 80
|
94
|
+
base_uri
|
95
|
+
else
|
96
|
+
options[:base_uri]
|
97
|
+
end
|
82
98
|
end
|
83
99
|
|
84
100
|
def format
|
@@ -266,7 +282,7 @@ module HTTParty
|
|
266
282
|
unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
|
267
283
|
self.http_method = Net::HTTP::Get
|
268
284
|
end
|
269
|
-
|
285
|
+
elsif last_response.code != '307' && last_response.code != '308'
|
270
286
|
unless options[:maintain_method_across_redirects]
|
271
287
|
self.http_method = Net::HTTP::Get
|
272
288
|
end
|
@@ -295,12 +311,9 @@ module HTTParty
|
|
295
311
|
|
296
312
|
def response_redirects?
|
297
313
|
case last_response
|
298
|
-
when Net::
|
299
|
-
|
300
|
-
|
301
|
-
Net::HTTPSeeOther, # 303
|
302
|
-
Net::HTTPUseProxy, # 305
|
303
|
-
Net::HTTPTemporaryRedirect
|
314
|
+
when Net::HTTPNotModified # 304
|
315
|
+
false
|
316
|
+
when Net::HTTPRedirection
|
304
317
|
options[:follow_redirects] && last_response.key?('location')
|
305
318
|
end
|
306
319
|
end
|
data/lib/httparty/version.rb
CHANGED
@@ -449,6 +449,20 @@ RSpec.describe HTTParty::ConnectionAdapter do
|
|
449
449
|
end
|
450
450
|
end
|
451
451
|
end
|
452
|
+
|
453
|
+
context "when uri port is not defined" do
|
454
|
+
context "falls back to 80 port on http" do
|
455
|
+
let(:uri) { URI 'http://foobar.com' }
|
456
|
+
before { allow(uri).to receive(:port).and_return(nil) }
|
457
|
+
it { expect(subject.port).to be 80 }
|
458
|
+
end
|
459
|
+
|
460
|
+
context "falls back to 443 port on https" do
|
461
|
+
let(:uri) { URI 'https://foobar.com' }
|
462
|
+
before { allow(uri).to receive(:port).and_return(nil) }
|
463
|
+
it { expect(subject.port).to be 443 }
|
464
|
+
end
|
465
|
+
end
|
452
466
|
end
|
453
467
|
end
|
454
468
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
2
|
|
3
|
-
RSpec.describe HTTParty::Logger::
|
3
|
+
RSpec.describe HTTParty::Logger::ApacheFormatter do
|
4
4
|
let(:subject) { described_class.new(logger_double, :info) }
|
5
5
|
let(:logger_double) { double('Logger') }
|
6
6
|
let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "http://my.domain.com/my_path") }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
2
|
|
3
|
-
RSpec.describe HTTParty::Logger::
|
3
|
+
RSpec.describe HTTParty::Logger::CurlFormatter do
|
4
4
|
describe "#format" do
|
5
5
|
it "formats a response in a style that resembles a -v curl" do
|
6
6
|
logger_double = double
|
@@ -11,12 +11,28 @@ RSpec.describe HTTParty::Logger do
|
|
11
11
|
|
12
12
|
it "defaults format to :apache" do
|
13
13
|
logger_double = double
|
14
|
-
expect(subject.build(logger_double, nil, nil)).to be_an_instance_of(HTTParty::Logger::
|
14
|
+
expect(subject.build(logger_double, nil, nil)).to be_an_instance_of(HTTParty::Logger::ApacheFormatter)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "builds :curl style logger" do
|
18
18
|
logger_double = double
|
19
|
-
expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::
|
19
|
+
expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::CurlFormatter)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "builds :custom style logger" do
|
23
|
+
CustomFormatter = Class.new(HTTParty::Logger::CurlFormatter)
|
24
|
+
HTTParty::Logger.add_formatter(:custom, CustomFormatter)
|
25
|
+
|
26
|
+
logger_double = double
|
27
|
+
expect(subject.build(logger_double, nil, :custom)).
|
28
|
+
to be_an_instance_of(CustomFormatter)
|
29
|
+
end
|
30
|
+
it "raises error when formatter exists" do
|
31
|
+
CustomFormatter2= Class.new(HTTParty::Logger::CurlFormatter)
|
32
|
+
HTTParty::Logger.add_formatter(:custom2, CustomFormatter2)
|
33
|
+
|
34
|
+
expect{ HTTParty::Logger.add_formatter(:custom2, CustomFormatter2) }.
|
35
|
+
to raise_error HTTParty::Error
|
20
36
|
end
|
21
37
|
end
|
22
38
|
end
|
@@ -188,4 +188,43 @@ RSpec.describe Net::HTTPHeader::DigestAuthenticator do
|
|
188
188
|
expect(authorization_header).to include(%(response="#{request_digest}"))
|
189
189
|
end
|
190
190
|
end
|
191
|
+
|
192
|
+
context "with algorithm specified" do
|
193
|
+
before do
|
194
|
+
@digest = setup_digest({
|
195
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5'
|
196
|
+
})
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should recognise algorithm was specified" do
|
200
|
+
expect( @digest.send :algorithm_present? ).to be(true)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should set the algorithm header" do
|
204
|
+
expect(authorization_header).to include('algorithm="MD5"')
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with md5-sess algorithm specified" do
|
209
|
+
before do
|
210
|
+
@digest = setup_digest({
|
211
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5-sess'
|
212
|
+
})
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should recognise algorithm was specified" do
|
216
|
+
expect( @digest.send :algorithm_present? ).to be(true)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should set the algorithm header" do
|
220
|
+
expect(authorization_header).to include('algorithm="MD5-sess"')
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should set response using md5-sess algorithm" do
|
224
|
+
request_digest = "md5(md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(deadbeef)):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
|
225
|
+
expect(authorization_header).to include(%(response="#{request_digest}"))
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
191
230
|
end
|
@@ -97,6 +97,12 @@ RSpec.describe HTTParty::Parser do
|
|
97
97
|
allow(@parser).to receive_messages(body: " ")
|
98
98
|
expect(@parser.parse).to be_nil
|
99
99
|
end
|
100
|
+
|
101
|
+
it "does not raise exceptions for bodies with invalid encodings" do
|
102
|
+
allow(@parser).to receive_messages(body: "\x80")
|
103
|
+
allow(@parser).to receive_messages(supports_format?: false)
|
104
|
+
expect(@parser.parse).to_not be_nil
|
105
|
+
end
|
100
106
|
end
|
101
107
|
|
102
108
|
describe "#supports_format?" do
|
@@ -147,7 +153,7 @@ RSpec.describe HTTParty::Parser do
|
|
147
153
|
end
|
148
154
|
|
149
155
|
it "parses json with JSON" do
|
150
|
-
expect(JSON).to receive(:
|
156
|
+
expect(JSON).to receive(:parse).with('body', :quirks_mode => true, :allow_nan => true)
|
151
157
|
subject.send(:json)
|
152
158
|
end
|
153
159
|
|
@@ -483,6 +483,14 @@ RSpec.describe HTTParty::Request do
|
|
483
483
|
stub_response '', 300
|
484
484
|
expect(HTTParty::Response).to be === @request.perform
|
485
485
|
end
|
486
|
+
|
487
|
+
it "redirects including port" do
|
488
|
+
FakeWeb.register_uri(:get, "http://withport.com:3000/v1", status: [301, "Moved Permanently"], location: "http://withport.com:3000/v2")
|
489
|
+
FakeWeb.register_uri(:get, "http://withport.com:3000/v2", status: 200)
|
490
|
+
request = HTTParty::Request.new(Net::HTTP::Get, 'http://withport.com:3000/v1')
|
491
|
+
response = request.perform
|
492
|
+
expect(response.request.base_uri.to_s).to eq("http://withport.com:3000")
|
493
|
+
end
|
486
494
|
end
|
487
495
|
|
488
496
|
it 'should return a valid object for 4xx response' do
|
@@ -528,122 +536,124 @@ RSpec.describe HTTParty::Request do
|
|
528
536
|
expect(@request.perform.parsed_response).to eq('Content for you')
|
529
537
|
end
|
530
538
|
|
531
|
-
|
532
|
-
|
533
|
-
@redirect = stub_response("", 302)
|
534
|
-
@redirect['location'] = '/foo'
|
535
|
-
|
536
|
-
@ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
537
|
-
end
|
538
|
-
|
539
|
-
describe "once" do
|
539
|
+
[300, 301, 302, 305].each do |code|
|
540
|
+
describe "a request that #{code} redirects" do
|
540
541
|
before(:each) do
|
541
|
-
|
542
|
-
|
542
|
+
@redirect = stub_response("", code)
|
543
|
+
@redirect['location'] = '/foo'
|
543
544
|
|
544
|
-
|
545
|
-
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
545
|
+
@ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
546
546
|
end
|
547
547
|
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
548
|
+
describe "once" do
|
549
|
+
before(:each) do
|
550
|
+
allow(@http).to receive(:request).and_return(@redirect, @ok)
|
551
|
+
end
|
552
552
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
end
|
553
|
+
it "should be handled by GET transparently" do
|
554
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
555
|
+
end
|
557
556
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
557
|
+
it "should be handled by POST transparently" do
|
558
|
+
@request.http_method = Net::HTTP::Post
|
559
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
560
|
+
end
|
562
561
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
562
|
+
it "should be handled by DELETE transparently" do
|
563
|
+
@request.http_method = Net::HTTP::Delete
|
564
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
565
|
+
end
|
567
566
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
567
|
+
it "should be handled by MOVE transparently" do
|
568
|
+
@request.http_method = Net::HTTP::Move
|
569
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
570
|
+
end
|
572
571
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
572
|
+
it "should be handled by COPY transparently" do
|
573
|
+
@request.http_method = Net::HTTP::Copy
|
574
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
575
|
+
end
|
577
576
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
577
|
+
it "should be handled by PATCH transparently" do
|
578
|
+
@request.http_method = Net::HTTP::Patch
|
579
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
580
|
+
end
|
582
581
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
582
|
+
it "should be handled by PUT transparently" do
|
583
|
+
@request.http_method = Net::HTTP::Put
|
584
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
585
|
+
end
|
587
586
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
expect(@request.options[:headers]['Cookie']).to match(/name=value/)
|
593
|
-
end
|
587
|
+
it "should be handled by HEAD transparently" do
|
588
|
+
@request.http_method = Net::HTTP::Head
|
589
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
590
|
+
end
|
594
591
|
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
|
600
|
-
end
|
592
|
+
it "should be handled by OPTIONS transparently" do
|
593
|
+
@request.http_method = Net::HTTP::Options
|
594
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
595
|
+
end
|
601
596
|
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
597
|
+
it "should keep track of cookies between redirects" do
|
598
|
+
@redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
|
599
|
+
@request.perform
|
600
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
|
601
|
+
expect(@request.options[:headers]['Cookie']).to match(/name=value/)
|
602
|
+
end
|
608
603
|
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
expect(@request.options[:headers]['Cookie']).to match(/one=1/)
|
616
|
-
expect(@request.options[:headers]['Cookie']).to match(/two=2/)
|
617
|
-
end
|
604
|
+
it 'should update cookies with rediects' do
|
605
|
+
@request.options[:headers] = {'Cookie' => 'foo=bar;'}
|
606
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
607
|
+
@request.perform
|
608
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
|
609
|
+
end
|
618
610
|
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
611
|
+
it 'should keep cookies between rediects' do
|
612
|
+
@request.options[:headers] = {'Cookie' => 'keep=me'}
|
613
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
614
|
+
@request.perform
|
615
|
+
expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
|
616
|
+
end
|
624
617
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
618
|
+
it "should handle multiple Set-Cookie headers between redirects" do
|
619
|
+
@redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
|
620
|
+
@redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
|
621
|
+
@request.perform
|
622
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
|
623
|
+
expect(@request.options[:headers]['Cookie']).to match(/name=value/)
|
624
|
+
expect(@request.options[:headers]['Cookie']).to match(/one=1/)
|
625
|
+
expect(@request.options[:headers]['Cookie']).to match(/two=2/)
|
626
|
+
end
|
631
627
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
end
|
638
|
-
end
|
628
|
+
it 'should make resulting request a get request if it not already' do
|
629
|
+
@request.http_method = Net::HTTP::Delete
|
630
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
631
|
+
expect(@request.http_method).to eq(Net::HTTP::Get)
|
632
|
+
end
|
639
633
|
|
640
|
-
|
641
|
-
|
642
|
-
|
634
|
+
it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
|
635
|
+
@request.options[:maintain_method_across_redirects] = true
|
636
|
+
@request.http_method = Net::HTTP::Delete
|
637
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
638
|
+
expect(@request.http_method).to eq(Net::HTTP::Delete)
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'should log the redirection' do
|
642
|
+
logger_double = double
|
643
|
+
expect(logger_double).to receive(:info).twice
|
644
|
+
@request.options[:logger] = logger_double
|
645
|
+
@request.perform
|
646
|
+
end
|
643
647
|
end
|
644
648
|
|
645
|
-
|
646
|
-
|
649
|
+
describe "infinitely" do
|
650
|
+
before(:each) do
|
651
|
+
allow(@http).to receive(:request).and_return(@redirect)
|
652
|
+
end
|
653
|
+
|
654
|
+
it "should raise an exception" do
|
655
|
+
expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
|
656
|
+
end
|
647
657
|
end
|
648
658
|
end
|
649
659
|
end
|
@@ -784,6 +794,197 @@ RSpec.describe HTTParty::Request do
|
|
784
794
|
end
|
785
795
|
end
|
786
796
|
|
797
|
+
describe "a request that returns 304" do
|
798
|
+
before(:each) do
|
799
|
+
@redirect = stub_response("", 304)
|
800
|
+
@redirect['location'] = '/foo'
|
801
|
+
end
|
802
|
+
|
803
|
+
before(:each) do
|
804
|
+
allow(@http).to receive(:request).and_return(@redirect)
|
805
|
+
end
|
806
|
+
|
807
|
+
it "should report 304 with a GET request" do
|
808
|
+
expect(@request.perform.code).to eq(304)
|
809
|
+
end
|
810
|
+
|
811
|
+
it "should report 304 with a POST request" do
|
812
|
+
@request.http_method = Net::HTTP::Post
|
813
|
+
expect(@request.perform.code).to eq(304)
|
814
|
+
end
|
815
|
+
|
816
|
+
it "should report 304 with a DELETE request" do
|
817
|
+
@request.http_method = Net::HTTP::Delete
|
818
|
+
expect(@request.perform.code).to eq(304)
|
819
|
+
end
|
820
|
+
|
821
|
+
it "should report 304 with a MOVE request" do
|
822
|
+
@request.http_method = Net::HTTP::Move
|
823
|
+
expect(@request.perform.code).to eq(304)
|
824
|
+
end
|
825
|
+
|
826
|
+
it "should report 304 with a COPY request" do
|
827
|
+
@request.http_method = Net::HTTP::Copy
|
828
|
+
expect(@request.perform.code).to eq(304)
|
829
|
+
end
|
830
|
+
|
831
|
+
it "should report 304 with a PATCH request" do
|
832
|
+
@request.http_method = Net::HTTP::Patch
|
833
|
+
expect(@request.perform.code).to eq(304)
|
834
|
+
end
|
835
|
+
|
836
|
+
it "should report 304 with a PUT request" do
|
837
|
+
@request.http_method = Net::HTTP::Put
|
838
|
+
expect(@request.perform.code).to eq(304)
|
839
|
+
end
|
840
|
+
|
841
|
+
it "should report 304 with a HEAD request" do
|
842
|
+
@request.http_method = Net::HTTP::Head
|
843
|
+
expect(@request.perform.code).to eq(304)
|
844
|
+
end
|
845
|
+
|
846
|
+
it "should report 304 with a OPTIONS request" do
|
847
|
+
@request.http_method = Net::HTTP::Options
|
848
|
+
expect(@request.perform.code).to eq(304)
|
849
|
+
end
|
850
|
+
|
851
|
+
it 'should not log the redirection' do
|
852
|
+
logger_double = double
|
853
|
+
expect(logger_double).to receive(:info).once
|
854
|
+
@request.options[:logger] = logger_double
|
855
|
+
@request.perform
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
[307, 308].each do |code|
|
860
|
+
describe "a request that #{code} redirects" do
|
861
|
+
before(:each) do
|
862
|
+
@redirect = stub_response("", code)
|
863
|
+
@redirect['location'] = '/foo'
|
864
|
+
|
865
|
+
@ok = stub_response('<hash><foo>bar</foo></hash>', 200)
|
866
|
+
end
|
867
|
+
|
868
|
+
describe "once" do
|
869
|
+
before(:each) do
|
870
|
+
allow(@http).to receive(:request).and_return(@redirect, @ok)
|
871
|
+
end
|
872
|
+
|
873
|
+
it "should be handled by GET transparently" do
|
874
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
875
|
+
end
|
876
|
+
|
877
|
+
it "should be handled by POST transparently" do
|
878
|
+
@request.http_method = Net::HTTP::Post
|
879
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
880
|
+
end
|
881
|
+
|
882
|
+
it "should be handled by DELETE transparently" do
|
883
|
+
@request.http_method = Net::HTTP::Delete
|
884
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
885
|
+
end
|
886
|
+
|
887
|
+
it "should be handled by MOVE transparently" do
|
888
|
+
@request.http_method = Net::HTTP::Move
|
889
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
890
|
+
end
|
891
|
+
|
892
|
+
it "should be handled by COPY transparently" do
|
893
|
+
@request.http_method = Net::HTTP::Copy
|
894
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
895
|
+
end
|
896
|
+
|
897
|
+
it "should be handled by PATCH transparently" do
|
898
|
+
@request.http_method = Net::HTTP::Patch
|
899
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
900
|
+
end
|
901
|
+
|
902
|
+
it "should be handled by PUT transparently" do
|
903
|
+
@request.http_method = Net::HTTP::Put
|
904
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
905
|
+
end
|
906
|
+
|
907
|
+
it "should be handled by HEAD transparently" do
|
908
|
+
@request.http_method = Net::HTTP::Head
|
909
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
910
|
+
end
|
911
|
+
|
912
|
+
it "should be handled by OPTIONS transparently" do
|
913
|
+
@request.http_method = Net::HTTP::Options
|
914
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
915
|
+
end
|
916
|
+
|
917
|
+
it "should keep track of cookies between redirects" do
|
918
|
+
@redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
|
919
|
+
@request.perform
|
920
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
|
921
|
+
expect(@request.options[:headers]['Cookie']).to match(/name=value/)
|
922
|
+
end
|
923
|
+
|
924
|
+
it 'should update cookies with rediects' do
|
925
|
+
@request.options[:headers] = {'Cookie' => 'foo=bar;'}
|
926
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
927
|
+
@request.perform
|
928
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
|
929
|
+
end
|
930
|
+
|
931
|
+
it 'should keep cookies between rediects' do
|
932
|
+
@request.options[:headers] = {'Cookie' => 'keep=me'}
|
933
|
+
@redirect['Set-Cookie'] = 'foo=tar;'
|
934
|
+
@request.perform
|
935
|
+
expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
|
936
|
+
end
|
937
|
+
|
938
|
+
it "should handle multiple Set-Cookie headers between redirects" do
|
939
|
+
@redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
|
940
|
+
@redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
|
941
|
+
@request.perform
|
942
|
+
expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
|
943
|
+
expect(@request.options[:headers]['Cookie']).to match(/name=value/)
|
944
|
+
expect(@request.options[:headers]['Cookie']).to match(/one=1/)
|
945
|
+
expect(@request.options[:headers]['Cookie']).to match(/two=2/)
|
946
|
+
end
|
947
|
+
|
948
|
+
it 'should maintain method in resulting request' do
|
949
|
+
@request.http_method = Net::HTTP::Delete
|
950
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
951
|
+
expect(@request.http_method).to eq(Net::HTTP::Delete)
|
952
|
+
end
|
953
|
+
|
954
|
+
it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is false' do
|
955
|
+
@request.options[:maintain_method_across_redirects] = false
|
956
|
+
@request.http_method = Net::HTTP::Delete
|
957
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
958
|
+
expect(@request.http_method).to eq(Net::HTTP::Delete)
|
959
|
+
end
|
960
|
+
|
961
|
+
it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is true' do
|
962
|
+
@request.options[:maintain_method_across_redirects] = true
|
963
|
+
@request.http_method = Net::HTTP::Delete
|
964
|
+
expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
|
965
|
+
expect(@request.http_method).to eq(Net::HTTP::Delete)
|
966
|
+
end
|
967
|
+
|
968
|
+
it 'should log the redirection' do
|
969
|
+
logger_double = double
|
970
|
+
expect(logger_double).to receive(:info).twice
|
971
|
+
@request.options[:logger] = logger_double
|
972
|
+
@request.perform
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
describe "infinitely" do
|
977
|
+
before(:each) do
|
978
|
+
allow(@http).to receive(:request).and_return(@redirect)
|
979
|
+
end
|
980
|
+
|
981
|
+
it "should raise an exception" do
|
982
|
+
expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
|
983
|
+
end
|
984
|
+
end
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
787
988
|
describe "#handle_deflation" do
|
788
989
|
context "context-encoding" do
|
789
990
|
before do
|
data/spec/httparty_spec.rb
CHANGED
@@ -351,6 +351,45 @@ RSpec.describe HTTParty do
|
|
351
351
|
end
|
352
352
|
end
|
353
353
|
|
354
|
+
describe "uri_adapter" do
|
355
|
+
|
356
|
+
require 'forwardable'
|
357
|
+
class CustomURIAdaptor
|
358
|
+
extend Forwardable
|
359
|
+
def_delegators :@uri, :userinfo, :relative?, :query, :query=, :scheme, :path, :host, :port
|
360
|
+
|
361
|
+
def initialize uri
|
362
|
+
@uri = uri
|
363
|
+
end
|
364
|
+
|
365
|
+
def self.parse uri
|
366
|
+
new URI.parse uri
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
let(:uri_adapter) { CustomURIAdaptor }
|
371
|
+
|
372
|
+
it "should set the uri_adapter" do
|
373
|
+
@klass.uri_adapter uri_adapter
|
374
|
+
expect(@klass.default_options[:uri_adapter]).to be uri_adapter
|
375
|
+
end
|
376
|
+
|
377
|
+
it "should raise an ArgumentError if uri_adapter doesn't implement parse method" do
|
378
|
+
expect do
|
379
|
+
@klass.uri_adapter double()
|
380
|
+
end.to raise_error(ArgumentError)
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
it "should process a request with a uri instance parsed from the uri_adapter" do
|
385
|
+
uri = 'http://foo.com/bar'
|
386
|
+
FakeWeb.register_uri(:get, uri, body: 'stuff')
|
387
|
+
@klass.uri_adapter uri_adapter
|
388
|
+
expect(@klass.get(uri).parsed_response).to eq('stuff')
|
389
|
+
end
|
390
|
+
|
391
|
+
end
|
392
|
+
|
354
393
|
describe "connection_adapter" do
|
355
394
|
let(:uri) { 'http://google.com/api.json' }
|
356
395
|
let(:connection_adapter) { double('CustomConnectionAdapter') }
|
@@ -549,6 +588,33 @@ RSpec.describe HTTParty do
|
|
549
588
|
end
|
550
589
|
end
|
551
590
|
|
591
|
+
describe "head requests should follow redirects requesting HEAD only" do
|
592
|
+
before do
|
593
|
+
allow(HTTParty::Request).to receive(:new).
|
594
|
+
and_return(double("mock response", perform: nil))
|
595
|
+
end
|
596
|
+
|
597
|
+
it "should remain HEAD request across redirects, unless specified otherwise" do
|
598
|
+
expect(@klass).to receive(:ensure_method_maintained_across_redirects).with({})
|
599
|
+
@klass.head('/foo')
|
600
|
+
end
|
601
|
+
|
602
|
+
end
|
603
|
+
|
604
|
+
describe "#ensure_method_maintained_across_redirects" do
|
605
|
+
it "should set maintain_method_across_redirects option if unspecified" do
|
606
|
+
options = {}
|
607
|
+
@klass.send(:ensure_method_maintained_across_redirects, options)
|
608
|
+
expect(options[:maintain_method_across_redirects]).to be_truthy
|
609
|
+
end
|
610
|
+
|
611
|
+
it "should not set maintain_method_across_redirects option if value is present" do
|
612
|
+
options = { maintain_method_across_redirects: false }
|
613
|
+
@klass.send(:ensure_method_maintained_across_redirects, options)
|
614
|
+
expect(options[:maintain_method_across_redirects]).to be_falsey
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
552
618
|
describe "with multiple class definitions" do
|
553
619
|
before(:each) do
|
554
620
|
@klass.instance_eval do
|
@@ -767,9 +833,11 @@ RSpec.describe HTTParty do
|
|
767
833
|
end
|
768
834
|
|
769
835
|
it "should accept webcal URIs" do
|
770
|
-
|
836
|
+
uri = 'http://google.com/'
|
837
|
+
FakeWeb.register_uri(:get, uri, body: 'stuff')
|
838
|
+
uri = 'webcal://google.com/'
|
771
839
|
expect do
|
772
|
-
HTTParty.get(
|
840
|
+
HTTParty.get(uri)
|
773
841
|
end.not_to raise_error
|
774
842
|
end
|
775
843
|
|
@@ -26,14 +26,20 @@ module HTTParty
|
|
26
26
|
expect(HTTParty::Request).to receive(:new).and_return(http_request)
|
27
27
|
end
|
28
28
|
|
29
|
-
def stub_response(body, code = 200)
|
29
|
+
def stub_response(body, code = '200')
|
30
|
+
code = code.to_s
|
30
31
|
@request.options[:base_uri] ||= 'http://localhost'
|
31
32
|
unless defined?(@http) && @http
|
32
33
|
@http = Net::HTTP.new('localhost', 80)
|
33
34
|
allow(@request).to receive(:http).and_return(@http)
|
34
35
|
end
|
35
36
|
|
36
|
-
|
37
|
+
# CODE_TO_OBJ currently missing 308
|
38
|
+
if code == '308'
|
39
|
+
response = Net::HTTPRedirection.new("1.1", code, body)
|
40
|
+
else
|
41
|
+
response = Net::HTTPResponse::CODE_TO_OBJ[code].new("1.1", code, body)
|
42
|
+
end
|
37
43
|
allow(response).to receive(:body).and_return(body)
|
38
44
|
|
39
45
|
allow(@http).to receive(:request).and_return(response)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httparty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.13.
|
4
|
+
version: 0.13.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-09-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- ".rubocop_todo.yml"
|
53
53
|
- ".simplecov"
|
54
54
|
- ".travis.yml"
|
55
|
+
- CONTRIBUTING.md
|
55
56
|
- Gemfile
|
56
57
|
- Guardfile
|
57
58
|
- History
|
@@ -96,8 +97,8 @@ files:
|
|
96
97
|
- lib/httparty/cookie_hash.rb
|
97
98
|
- lib/httparty/exceptions.rb
|
98
99
|
- lib/httparty/hash_conversions.rb
|
99
|
-
- lib/httparty/logger/
|
100
|
-
- lib/httparty/logger/
|
100
|
+
- lib/httparty/logger/apache_formatter.rb
|
101
|
+
- lib/httparty/logger/curl_formatter.rb
|
101
102
|
- lib/httparty/logger/logger.rb
|
102
103
|
- lib/httparty/module_inheritable_attributes.rb
|
103
104
|
- lib/httparty/net_digest_auth.rb
|
@@ -127,8 +128,8 @@ files:
|
|
127
128
|
- spec/httparty/cookie_hash_spec.rb
|
128
129
|
- spec/httparty/exception_spec.rb
|
129
130
|
- spec/httparty/hash_conversions_spec.rb
|
130
|
-
- spec/httparty/logger/
|
131
|
-
- spec/httparty/logger/
|
131
|
+
- spec/httparty/logger/apache_formatter_spec.rb
|
132
|
+
- spec/httparty/logger/curl_formatter_spec.rb
|
132
133
|
- spec/httparty/logger/logger_spec.rb
|
133
134
|
- spec/httparty/net_digest_auth_spec.rb
|
134
135
|
- spec/httparty/parser_spec.rb
|
@@ -146,7 +147,7 @@ homepage: http://jnunemaker.github.com/httparty
|
|
146
147
|
licenses:
|
147
148
|
- MIT
|
148
149
|
metadata: {}
|
149
|
-
post_install_message: When you HTTParty, you must party hard!
|
150
|
+
post_install_message: "When you HTTParty, you must party hard! \U0001F389"
|
150
151
|
rdoc_options: []
|
151
152
|
require_paths:
|
152
153
|
- lib
|
@@ -201,8 +202,8 @@ test_files:
|
|
201
202
|
- spec/httparty/cookie_hash_spec.rb
|
202
203
|
- spec/httparty/exception_spec.rb
|
203
204
|
- spec/httparty/hash_conversions_spec.rb
|
204
|
-
- spec/httparty/logger/
|
205
|
-
- spec/httparty/logger/
|
205
|
+
- spec/httparty/logger/apache_formatter_spec.rb
|
206
|
+
- spec/httparty/logger/curl_formatter_spec.rb
|
206
207
|
- spec/httparty/logger/logger_spec.rb
|
207
208
|
- spec/httparty/net_digest_auth_spec.rb
|
208
209
|
- spec/httparty/parser_spec.rb
|