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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a6b1d5f5b4dfe131cddcf36948fb9102b93f67d
4
- data.tar.gz: 10206b7de3285e93f767f7578a77600256892b82
3
+ metadata.gz: 7ff4fbf77e1502f71829faa6032ec50bce93aae6
4
+ data.tar.gz: bcd37d969fec45917adec0a7e6ac202308520601
5
5
  SHA512:
6
- metadata.gz: aa60eff289622231ce78d3ec3edcc1a6945deb42ede5ba814534117f57b768bcbcb64c2baae1bc1abe3918c15f9af3bc175789a6d63d940357630aed60809255
7
- data.tar.gz: 8e4240d4b726486e591c2dc33943aba90aafbc9bb26ba79417e0ce8481b30f97b34df171619b16229cd895565bbc180666cc5481597705a5a401ebef08c6ee81
6
+ metadata.gz: 0edda1d12877f8dbec768ef37934ad0853c7383dfbb1d0f1051de314b469dfe9eed8da318ea5cea3112c39d2dbe7edec5b00785834bfdf77ba75877a2163002a
7
+ data.tar.gz: a97e1c55e863564388944cb4acf5ae2a49942a4df79dc09834025e7346929e9bd5a40b1e29d3f3cbdff479a4318ce1f100203da3f90b6b29085c433f2898bb0d
@@ -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('https://api.stackexchange.com/2.2/questions?site=stackoverflow')
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
 
@@ -62,6 +62,11 @@ OptionParser.new do |o|
62
62
  puts o
63
63
  exit
64
64
  end
65
+
66
+ o.on("--version", "Show HTTParty version") do |ver|
67
+ puts "Version: #{HTTParty::VERSION}"
68
+ exit
69
+ end
65
70
  end.parse!
66
71
 
67
72
  if ARGV.empty?
@@ -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
@@ -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")
@@ -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
- raise ArgumentError, "uri must be a URI, not a #{uri.class}" unless uri.is_a? URI
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, uri.port, options[:http_proxyaddr], options[:http_proxyport], options[:http_proxyuser], options[:http_proxypass])
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, uri.port)
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.instance_of?(URI::HTTPS)
138
+ uri.port == 443 || uri.scheme == 'https'
137
139
  end
138
140
 
139
141
  def attach_ssl_certificates(http, options)
@@ -1,6 +1,6 @@
1
1
  module HTTParty
2
2
  module Logger
3
- class ApacheLogger #:nodoc:
3
+ class ApacheFormatter #:nodoc:
4
4
  TAG_NAME = HTTParty.name
5
5
 
6
6
  attr_accessor :level, :logger, :current_time
@@ -1,6 +1,6 @@
1
1
  module HTTParty
2
2
  module Logger
3
- class CurlLogger #:nodoc:
3
+ class CurlFormatter #:nodoc:
4
4
  TAG_NAME = HTTParty.name
5
5
  OUT = ">"
6
6
  IN = "<"
@@ -1,18 +1,26 @@
1
- require 'httparty/logger/apache_logger'
2
- require 'httparty/logger/curl_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
- case formatter
11
- when :curl
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
@@ -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? || body.strip.empty? || body == "null"
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.load(body, nil)
118
+ JSON.parse(body, :quirks_mode => true, :allow_nan => true)
117
119
  end
118
120
 
119
121
  def csv
@@ -12,7 +12,7 @@ module HTTParty
12
12
  Net::HTTP::Copy
13
13
  ]
14
14
 
15
- SupportedURISchemes = [URI::HTTP, URI::HTTPS, URI::Generic]
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
- @path = URI(uri)
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? ? URI.parse("#{base_uri}#{path}") : path.clone
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.class
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 ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
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
- else
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::HTTPMultipleChoice, # 300
299
- Net::HTTPMovedPermanently, # 301
300
- Net::HTTPFound, # 302
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
@@ -1,3 +1,3 @@
1
1
  module HTTParty
2
- VERSION = "0.13.5"
2
+ VERSION = "0.13.6"
3
3
  end
@@ -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::ApacheLogger do
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::CurlLogger do
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::ApacheLogger)
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::CurlLogger)
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(:load).with('body', nil)
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
- describe "a request that 302 redirects" do
532
- before(:each) do
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
- allow(@http).to receive(:request).and_return(@redirect, @ok)
542
- end
542
+ @redirect = stub_response("", code)
543
+ @redirect['location'] = '/foo'
543
544
 
544
- it "should be handled by GET transparently" do
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
- it "should be handled by POST transparently" do
549
- @request.http_method = Net::HTTP::Post
550
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
551
- end
548
+ describe "once" do
549
+ before(:each) do
550
+ allow(@http).to receive(:request).and_return(@redirect, @ok)
551
+ end
552
552
 
553
- it "should be handled by DELETE transparently" do
554
- @request.http_method = Net::HTTP::Delete
555
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
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
- it "should be handled by MOVE transparently" do
559
- @request.http_method = Net::HTTP::Move
560
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
561
- end
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
- it "should be handled by COPY transparently" do
564
- @request.http_method = Net::HTTP::Copy
565
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
566
- end
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
- it "should be handled by PATCH transparently" do
569
- @request.http_method = Net::HTTP::Patch
570
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
571
- end
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
- it "should be handled by PUT transparently" do
574
- @request.http_method = Net::HTTP::Put
575
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
576
- end
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
- it "should be handled by HEAD transparently" do
579
- @request.http_method = Net::HTTP::Head
580
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
581
- end
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
- it "should be handled by OPTIONS transparently" do
584
- @request.http_method = Net::HTTP::Options
585
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
586
- end
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
- it "should keep track of cookies between redirects" do
589
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
590
- @request.perform
591
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
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
- it 'should update cookies with rediects' do
596
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
597
- @redirect['Set-Cookie'] = 'foo=tar;'
598
- @request.perform
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
- it 'should keep cookies between rediects' do
603
- @request.options[:headers] = {'Cookie' => 'keep=me'}
604
- @redirect['Set-Cookie'] = 'foo=tar;'
605
- @request.perform
606
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
607
- end
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
- it "should handle multiple Set-Cookie headers between redirects" do
610
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
611
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
612
- @request.perform
613
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
614
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
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
- it 'should make resulting request a get request if it not already' do
620
- @request.http_method = Net::HTTP::Delete
621
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
622
- expect(@request.http_method).to eq(Net::HTTP::Get)
623
- end
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
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
626
- @request.options[:maintain_method_across_redirects] = true
627
- @request.http_method = Net::HTTP::Delete
628
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
629
- expect(@request.http_method).to eq(Net::HTTP::Delete)
630
- end
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
- it 'should log the redirection' do
633
- logger_double = double
634
- expect(logger_double).to receive(:info).twice
635
- @request.options[:logger] = logger_double
636
- @request.perform
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
- describe "infinitely" do
641
- before(:each) do
642
- allow(@http).to receive(:request).and_return(@redirect)
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
- it "should raise an exception" do
646
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
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
@@ -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
- stub_http_response_with('google.html')
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('webcal://google.com')
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
- response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new("1.1", code, body)
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.5
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-05-19 00:00:00.000000000 Z
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/apache_logger.rb
100
- - lib/httparty/logger/curl_logger.rb
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/apache_logger_spec.rb
131
- - spec/httparty/logger/curl_logger_spec.rb
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/apache_logger_spec.rb
205
- - spec/httparty/logger/curl_logger_spec.rb
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