httparty 0.13.0 → 0.14.0

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.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +92 -0
  4. data/.rubocop_todo.yml +124 -0
  5. data/.simplecov +1 -0
  6. data/.travis.yml +4 -2
  7. data/CONTRIBUTING.md +23 -0
  8. data/Gemfile +8 -3
  9. data/Guardfile +3 -3
  10. data/History +106 -11
  11. data/README.md +19 -20
  12. data/Rakefile +5 -7
  13. data/bin/httparty +18 -14
  14. data/docs/README.md +100 -0
  15. data/examples/README.md +67 -0
  16. data/examples/aaws.rb +5 -5
  17. data/examples/basic.rb +6 -10
  18. data/examples/crack.rb +2 -2
  19. data/examples/custom_parsers.rb +1 -4
  20. data/examples/delicious.rb +8 -8
  21. data/examples/google.rb +2 -2
  22. data/examples/headers_and_user_agents.rb +1 -1
  23. data/examples/logging.rb +36 -0
  24. data/examples/nokogiri_html_parser.rb +0 -3
  25. data/examples/rescue_json.rb +17 -0
  26. data/examples/rubyurl.rb +3 -3
  27. data/examples/stackexchange.rb +24 -0
  28. data/examples/tripit_sign_in.rb +20 -9
  29. data/examples/twitter.rb +7 -7
  30. data/examples/whoismyrep.rb +1 -1
  31. data/features/command_line.feature +90 -2
  32. data/features/digest_authentication.feature +10 -0
  33. data/features/steps/env.rb +16 -11
  34. data/features/steps/httparty_response_steps.rb +18 -14
  35. data/features/steps/httparty_steps.rb +10 -2
  36. data/features/steps/mongrel_helper.rb +35 -2
  37. data/features/steps/remote_service_steps.rb +26 -8
  38. data/features/supports_read_timeout_option.feature +13 -0
  39. data/httparty.gemspec +6 -5
  40. data/lib/httparty/connection_adapter.rb +36 -13
  41. data/lib/httparty/cookie_hash.rb +3 -4
  42. data/lib/httparty/exceptions.rb +4 -1
  43. data/lib/httparty/hash_conversions.rb +17 -15
  44. data/lib/httparty/logger/{apache_logger.rb → apache_formatter.rb} +3 -3
  45. data/lib/httparty/logger/curl_formatter.rb +91 -0
  46. data/lib/httparty/logger/logger.rb +18 -10
  47. data/lib/httparty/module_inheritable_attributes.rb +1 -1
  48. data/lib/httparty/net_digest_auth.rb +69 -18
  49. data/lib/httparty/parser.rb +4 -2
  50. data/lib/httparty/request.rb +105 -48
  51. data/lib/httparty/response.rb +31 -6
  52. data/lib/httparty/version.rb +1 -1
  53. data/lib/httparty.rb +132 -72
  54. data/spec/httparty/connection_adapter_spec.rb +285 -88
  55. data/spec/httparty/cookie_hash_spec.rb +46 -29
  56. data/spec/httparty/exception_spec.rb +29 -7
  57. data/spec/httparty/hash_conversions_spec.rb +49 -0
  58. data/spec/httparty/logger/apache_formatter_spec.rb +41 -0
  59. data/spec/httparty/logger/curl_formatter_spec.rb +119 -0
  60. data/spec/httparty/logger/logger_spec.rb +23 -7
  61. data/spec/httparty/net_digest_auth_spec.rb +118 -30
  62. data/spec/httparty/parser_spec.rb +43 -35
  63. data/spec/httparty/request_spec.rb +734 -182
  64. data/spec/httparty/response_spec.rb +139 -69
  65. data/spec/httparty/ssl_spec.rb +22 -22
  66. data/spec/httparty_spec.rb +307 -199
  67. data/spec/spec_helper.rb +34 -12
  68. data/spec/support/ssl_test_helper.rb +6 -6
  69. data/spec/support/ssl_test_server.rb +21 -21
  70. data/spec/support/stub_response.rb +20 -14
  71. data/website/index.html +3 -3
  72. metadata +30 -33
  73. data/lib/httparty/core_extensions.rb +0 -32
  74. data/lib/httparty/logger/curl_logger.rb +0 -48
  75. data/spec/httparty/logger/apache_logger_spec.rb +0 -26
  76. data/spec/httparty/logger/curl_logger_spec.rb +0 -18
  77. data/spec/spec.opts +0 -2
data/lib/httparty.rb CHANGED
@@ -6,6 +6,7 @@ require 'zlib'
6
6
  require 'multi_xml'
7
7
  require 'json'
8
8
  require 'csv'
9
+ require 'erb'
9
10
 
10
11
  require 'httparty/module_inheritable_attributes'
11
12
  require 'httparty/cookie_hash'
@@ -16,22 +17,9 @@ require 'httparty/logger/logger'
16
17
 
17
18
  # @see HTTParty::ClassMethods
18
19
  module HTTParty
19
- module AllowedFormatsDeprecation
20
- def const_missing(const)
21
- if const.to_s =~ /AllowedFormats$/
22
- Kernel.warn("Deprecated: Use HTTParty::Parser::SupportedFormats")
23
- HTTParty::Parser::SupportedFormats
24
- else
25
- super
26
- end
27
- end
28
- end
29
-
30
- extend AllowedFormatsDeprecation
31
-
32
20
  def self.included(base)
33
21
  base.extend ClassMethods
34
- base.send :include, HTTParty::ModuleInheritableAttributes
22
+ base.send :include, ModuleInheritableAttributes
35
23
  base.send(:mattr_inheritable, :default_options)
36
24
  base.send(:mattr_inheritable, :default_cookies)
37
25
  base.instance_variable_set("@default_options", {})
@@ -41,16 +29,18 @@ module HTTParty
41
29
  # == Common Request Options
42
30
  # Request methods (get, post, patch, put, delete, head, options) all take a common set of options. These are:
43
31
  #
44
- # [:+body+:] Body of the request. If passed a Hash, will try to normalize it first, by default passing it to ActiveSupport::to_params. Any other kind of object will get used as-is.
32
+ # [:+body+:] Body of the request. If passed an object that responds to #to_hash, will try to normalize it first, by default passing it to ActiveSupport::to_params. Any other kind of object will get used as-is.
45
33
  # [:+http_proxyaddr+:] Address of proxy server to use.
46
34
  # [:+http_proxyport+:] Port of proxy server to use.
47
35
  # [:+http_proxyuser+:] User for proxy server authentication.
48
36
  # [:+http_proxypass+:] Password for proxy server authentication.
49
37
  # [:+limit+:] Maximum number of redirects to follow. Takes precedences over :+no_follow+.
50
- # [:+query+:] Query string, or a Hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use a Hash. See also HTTParty::ClassMethods.default_params.
38
+ # [:+query+:] Query string, or an object that responds to #to_hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use an object which responds to #to_hash. See also HTTParty::ClassMethods.default_params.
51
39
  # [:+timeout+:] Timeout for opening connection and reading data.
52
40
  # [:+local_host:] Local address to bind to before connecting.
53
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.
54
44
  #
55
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:
56
46
  # * :+base_uri+: see HTTParty::ClassMethods.base_uri.
@@ -58,10 +48,11 @@ module HTTParty
58
48
  # * :+debug_output+: see HTTParty::ClassMethods.debug_output.
59
49
  # * :+digest_auth+: see HTTParty::ClassMethods.digest_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError.
60
50
  # * :+format+: see HTTParty::ClassMethods.format.
61
- # * :+headers+: see HTTParty::ClassMethods.headers. Must be a Hash.
51
+ # * :+headers+: see HTTParty::ClassMethods.headers. Must be a an object which responds to #to_hash.
62
52
  # * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects.
63
53
  # * :+no_follow+: see HTTParty::ClassMethods.no_follow.
64
54
  # * :+parser+: see HTTParty::ClassMethods.parser.
55
+ # * :+uri_adapter+: see HTTParty::ClassMethods.uri_adapter
65
56
  # * :+connection_adapter+: see HTTParty::ClassMethods.connection_adapter.
66
57
  # * :+pem+: see HTTParty::ClassMethods.pem.
67
58
  # * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer
@@ -69,28 +60,35 @@ module HTTParty
69
60
  # * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path.
70
61
 
71
62
  module ClassMethods
72
-
73
- extend AllowedFormatsDeprecation
74
-
75
63
  # Turns on logging
76
64
  #
77
65
  # class Foo
78
66
  # include HTTParty
79
67
  # logger Logger.new('http_logger'), :info, :apache
80
68
  # end
81
- def logger(logger, level=:info, format=:apache)
69
+ def logger(logger, level = :info, format = :apache)
82
70
  default_options[:logger] = logger
83
71
  default_options[:log_level] = level
84
72
  default_options[:log_format] = format
85
73
  end
86
74
 
75
+ # Raises HTTParty::ResponseError if response's code matches this statuses
76
+ #
77
+ # class Foo
78
+ # include HTTParty
79
+ # raise_on [404, 500]
80
+ # end
81
+ def raise_on(codes = [])
82
+ default_options[:raise_on] = *codes
83
+ end
84
+
87
85
  # Allows setting http proxy information to be used
88
86
  #
89
87
  # class Foo
90
88
  # include HTTParty
91
89
  # http_proxy 'http://foo.com', 80, 'user', 'pass'
92
90
  # end
93
- def http_proxy(addr=nil, port=nil, user=nil, pass=nil)
91
+ def http_proxy(addr = nil, port = nil, user = nil, pass = nil)
94
92
  default_options[:http_proxyaddr] = addr
95
93
  default_options[:http_proxyport] = port
96
94
  default_options[:http_proxyuser] = user
@@ -104,7 +102,7 @@ module HTTParty
104
102
  # include HTTParty
105
103
  # base_uri 'twitter.com'
106
104
  # end
107
- def base_uri(uri=nil)
105
+ def base_uri(uri = nil)
108
106
  return default_options[:base_uri] unless uri
109
107
  default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
110
108
  end
@@ -116,7 +114,7 @@ module HTTParty
116
114
  # basic_auth 'username', 'password'
117
115
  # end
118
116
  def basic_auth(u, p)
119
- default_options[:basic_auth] = {:username => u, :password => p}
117
+ default_options[:basic_auth] = {username: u, password: p}
120
118
  end
121
119
 
122
120
  # Allows setting digest authentication username and password.
@@ -126,14 +124,14 @@ module HTTParty
126
124
  # digest_auth 'username', 'password'
127
125
  # end
128
126
  def digest_auth(u, p)
129
- default_options[:digest_auth] = {:username => u, :password => p}
127
+ default_options[:digest_auth] = {username: u, password: p}
130
128
  end
131
129
 
132
130
  # Do not send rails style query strings.
133
131
  # Specically, don't use bracket notation when sending an array
134
132
  #
135
133
  # For a query:
136
- # get '/', :query => {:selected_ids => [1,2,3]}
134
+ # get '/', query: {selected_ids: [1,2,3]}
137
135
  #
138
136
  # The default query string looks like this:
139
137
  # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
@@ -156,10 +154,10 @@ module HTTParty
156
154
  #
157
155
  # class Foo
158
156
  # include HTTParty
159
- # default_params :api_key => 'secret', :another => 'foo'
157
+ # default_params api_key: 'secret', another: 'foo'
160
158
  # end
161
- def default_params(h={})
162
- raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
159
+ def default_params(h = {})
160
+ raise ArgumentError, 'Default params must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
163
161
  default_options[:default_params] ||= {}
164
162
  default_options[:default_params].merge!(h)
165
163
  end
@@ -176,6 +174,28 @@ module HTTParty
176
174
  default_options[:timeout] = t
177
175
  end
178
176
 
177
+ # Allows setting a default open_timeout for all HTTP calls in seconds
178
+ #
179
+ # class Foo
180
+ # include HTTParty
181
+ # open_timeout 10
182
+ # end
183
+ def open_timeout(t)
184
+ raise ArgumentError, 'open_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
185
+ default_options[:open_timeout] = t
186
+ end
187
+
188
+ # Allows setting a default read_timeout for all HTTP calls in seconds
189
+ #
190
+ # class Foo
191
+ # include HTTParty
192
+ # read_timeout 10
193
+ # end
194
+ def read_timeout(t)
195
+ raise ArgumentError, 'read_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float))
196
+ default_options[:read_timeout] = t
197
+ end
198
+
179
199
  # Set an output stream for debugging, defaults to $stderr.
180
200
  # The output stream is passed on to Net::HTTP#set_debug_output.
181
201
  #
@@ -193,14 +213,14 @@ module HTTParty
193
213
  # include HTTParty
194
214
  # headers 'Accept' => 'text/html'
195
215
  # end
196
- def headers(h={})
197
- raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
216
+ def headers(h = {})
217
+ raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
198
218
  default_options[:headers] ||= {}
199
- default_options[:headers].merge!(h)
219
+ default_options[:headers].merge!(h.to_hash)
200
220
  end
201
221
 
202
- def cookies(h={})
203
- raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash)
222
+ def cookies(h = {})
223
+ raise ArgumentError, 'Cookies must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
204
224
  default_cookies.add_cookies(h)
205
225
  end
206
226
 
@@ -258,7 +278,9 @@ module HTTParty
258
278
  end
259
279
 
260
280
  # Declare that you wish to maintain the chosen HTTP method across redirects.
261
- # The default behavior is to follow redirects via the GET method.
281
+ # The default behavior is to follow redirects via the GET method, except
282
+ # if you are making a HEAD request, in which case the default is to
283
+ # follow all redirects with HEAD requests.
262
284
  # If you wish to maintain the original method, you can set this option to true.
263
285
  #
264
286
  # @example
@@ -272,13 +294,31 @@ module HTTParty
272
294
  default_options[:maintain_method_across_redirects] = value
273
295
  end
274
296
 
297
+ # Declare that you wish to resend the full HTTP request across redirects,
298
+ # even on redirects that should logically become GET requests.
299
+ # A 303 redirect in HTTP signifies that the redirected url should normally
300
+ # retrieved using a GET request, for instance, it is the output of a previous
301
+ # POST. maintain_method_across_redirects respects this behavior, but you
302
+ # can force HTTParty to resend_on_redirect even on 303 responses.
303
+ #
304
+ # @example
305
+ # class Foo
306
+ # include HTTParty
307
+ # base_uri 'http://google.com'
308
+ # resend_on_redirect
309
+ # end
310
+
311
+ def resend_on_redirect(value = true)
312
+ default_options[:resend_on_redirect] = value
313
+ end
314
+
275
315
  # Allows setting a PEM file to be used
276
316
  #
277
317
  # class Foo
278
318
  # include HTTParty
279
319
  # pem File.read('/home/user/my.pem'), "optional password"
280
320
  # end
281
- def pem(pem_contents, password=nil)
321
+ def pem(pem_contents, password = nil)
282
322
  default_options[:pem] = pem_contents
283
323
  default_options[:pem_password] = password
284
324
  end
@@ -298,7 +338,7 @@ module HTTParty
298
338
  # Helpful for overriding the default rails normalization of Array queries.
299
339
  #
300
340
  # For a query:
301
- # get '/', :query => {:selected_ids => [1,2,3]}
341
+ # get '/', query: {selected_ids: [1,2,3]}
302
342
  #
303
343
  # The default query string normalizer returns:
304
344
  # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3
@@ -395,6 +435,17 @@ module HTTParty
395
435
  end
396
436
  end
397
437
 
438
+ # Allows setting a custom URI adapter.
439
+ #
440
+ # class Foo
441
+ # include HTTParty
442
+ # uri_adapter Addressable::URI
443
+ # end
444
+ def uri_adapter(uri_adapter)
445
+ raise ArgumentError, 'The URI adapter should respond to #parse' unless uri_adapter.respond_to?(:parse)
446
+ default_options[:uri_adapter] = uri_adapter
447
+ end
448
+
398
449
  # Allows setting a custom connection_adapter for the http connections
399
450
  #
400
451
  # @example
@@ -406,7 +457,7 @@ module HTTParty
406
457
  # @example provide optional configuration for your connection_adapter
407
458
  # class Foo
408
459
  # include HTTParty
409
- # connection_adapter Proc.new {|uri, options| ... }, {:foo => :bar}
460
+ # connection_adapter Proc.new {|uri, options| ... }, {foo: :bar}
410
461
  # end
411
462
  #
412
463
  # @see HTTParty::ConnectionAdapter
@@ -430,8 +481,8 @@ module HTTParty
430
481
  #
431
482
  # # Simple get with full url and query parameters
432
483
  # # ie: http://foo.com/resource.json?limit=10
433
- # Foo.get('http://foo.com/resource.json', :query => {:limit => 10})
434
- def get(path, options={}, &block)
484
+ # Foo.get('http://foo.com/resource.json', query: {limit: 10})
485
+ def get(path, options = {}, &block)
435
486
  perform_request Net::HTTP::Get, path, options, &block
436
487
  end
437
488
 
@@ -442,80 +493,90 @@ module HTTParty
442
493
  # end
443
494
  #
444
495
  # # Simple post with full url and setting the body
445
- # Foo.post('http://foo.com/resources', :body => {:bar => 'baz'})
496
+ # Foo.post('http://foo.com/resources', body: {bar: 'baz'})
446
497
  #
447
498
  # # Simple post with full url using :query option,
448
- # # which gets set as form data on the request.
449
- # Foo.post('http://foo.com/resources', :query => {:bar => 'baz'})
450
- def post(path, options={}, &block)
499
+ # # which appends the parameters to the URI.
500
+ # Foo.post('http://foo.com/resources', query: {bar: 'baz'})
501
+ def post(path, options = {}, &block)
451
502
  perform_request Net::HTTP::Post, path, options, &block
452
503
  end
453
504
 
454
505
  # Perform a PATCH request to a path
455
- def patch(path, options={}, &block)
506
+ def patch(path, options = {}, &block)
456
507
  perform_request Net::HTTP::Patch, path, options, &block
457
508
  end
458
509
 
459
510
  # Perform a PUT request to a path
460
- def put(path, options={}, &block)
511
+ def put(path, options = {}, &block)
461
512
  perform_request Net::HTTP::Put, path, options, &block
462
513
  end
463
514
 
464
515
  # Perform a DELETE request to a path
465
- def delete(path, options={}, &block)
516
+ def delete(path, options = {}, &block)
466
517
  perform_request Net::HTTP::Delete, path, options, &block
467
518
  end
468
519
 
469
520
  # Perform a MOVE request to a path
470
- def move(path, options={}, &block)
521
+ def move(path, options = {}, &block)
471
522
  perform_request Net::HTTP::Move, path, options, &block
472
523
  end
473
524
 
474
525
  # Perform a COPY request to a path
475
- def copy(path, options={}, &block)
526
+ def copy(path, options = {}, &block)
476
527
  perform_request Net::HTTP::Copy, path, options, &block
477
528
  end
478
529
 
479
530
  # Perform a HEAD request to a path
480
- def head(path, options={}, &block)
531
+ def head(path, options = {}, &block)
532
+ ensure_method_maintained_across_redirects options
481
533
  perform_request Net::HTTP::Head, path, options, &block
482
534
  end
483
535
 
484
536
  # Perform an OPTIONS request to a path
485
- def options(path, options={}, &block)
537
+ def options(path, options = {}, &block)
486
538
  perform_request Net::HTTP::Options, path, options, &block
487
539
  end
488
540
 
489
- def default_options #:nodoc:
490
- @default_options
541
+ # Perform a MKCOL request to a path
542
+ def mkcol(path, options = {}, &block)
543
+ perform_request Net::HTTP::Mkcol, path, options, &block
491
544
  end
492
545
 
546
+ attr_reader :default_options
547
+
493
548
  private
494
549
 
495
- def perform_request(http_method, path, options, &block) #:nodoc:
496
- options = default_options.merge(options)
497
- process_headers(options)
498
- process_cookies(options)
499
- Request.new(http_method, path, options).perform(&block)
550
+ def ensure_method_maintained_across_redirects(options)
551
+ unless options.key?(:maintain_method_across_redirects)
552
+ options[:maintain_method_across_redirects] = true
500
553
  end
554
+ end
501
555
 
502
- def process_headers(options)
503
- if options[:headers] && headers.any?
504
- options[:headers] = headers.merge(options[:headers])
505
- end
506
- end
556
+ def perform_request(http_method, path, options, &block) #:nodoc:
557
+ options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
558
+ process_headers(options)
559
+ process_cookies(options)
560
+ Request.new(http_method, path, options).perform(&block)
561
+ end
507
562
 
508
- def process_cookies(options) #:nodoc:
509
- return unless options[:cookies] || default_cookies.any?
510
- options[:headers] ||= headers.dup
511
- options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
563
+ def process_headers(options)
564
+ if options[:headers] && headers.any?
565
+ options[:headers] = headers.merge(options[:headers])
512
566
  end
567
+ end
513
568
 
514
- def validate_format
515
- if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
516
- raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map{|f| f.to_s}.sort.join(', ')}"
517
- end
569
+ def process_cookies(options) #:nodoc:
570
+ return unless options[:cookies] || default_cookies.any?
571
+ options[:headers] ||= headers.dup
572
+ options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string
573
+ end
574
+
575
+ def validate_format
576
+ if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format)
577
+ raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map(&:to_s).sort.join(', ')}"
518
578
  end
579
+ end
519
580
  end
520
581
 
521
582
  def self.normalize_base_uri(url) #:nodoc:
@@ -570,7 +631,6 @@ module HTTParty
570
631
  end
571
632
  end
572
633
 
573
- require 'httparty/core_extensions'
574
634
  require 'httparty/hash_conversions'
575
635
  require 'httparty/exceptions'
576
636
  require 'httparty/parser'