httparty 0.15.6 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +26 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/Changelog.md +105 -0
  7. data/Gemfile +7 -0
  8. data/Guardfile +3 -2
  9. data/README.md +6 -6
  10. data/docs/README.md +90 -5
  11. data/examples/README.md +28 -11
  12. data/examples/aaws.rb +6 -2
  13. data/examples/body_stream.rb +14 -0
  14. data/examples/custom_parsers.rb +4 -0
  15. data/examples/headers_and_user_agents.rb +7 -3
  16. data/examples/idn.rb +10 -0
  17. data/examples/logging.rb +3 -3
  18. data/examples/microsoft_graph.rb +52 -0
  19. data/examples/multipart.rb +22 -0
  20. data/examples/peer_cert.rb +9 -0
  21. data/examples/stream_download.rb +8 -2
  22. data/httparty.gemspec +3 -3
  23. data/lib/httparty/connection_adapter.rb +59 -16
  24. data/lib/httparty/cookie_hash.rb +10 -8
  25. data/lib/httparty/decompressor.rb +102 -0
  26. data/lib/httparty/exceptions.rb +3 -1
  27. data/lib/httparty/hash_conversions.rb +28 -12
  28. data/lib/httparty/headers_processor.rb +32 -0
  29. data/lib/httparty/logger/apache_formatter.rb +31 -6
  30. data/lib/httparty/logger/curl_formatter.rb +9 -7
  31. data/lib/httparty/logger/logger.rb +5 -1
  32. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  33. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  34. data/lib/httparty/net_digest_auth.rb +15 -15
  35. data/lib/httparty/parser.rb +21 -15
  36. data/lib/httparty/request/body.rb +105 -0
  37. data/lib/httparty/request/multipart_boundary.rb +13 -0
  38. data/lib/httparty/request.rb +86 -94
  39. data/lib/httparty/response/headers.rb +4 -2
  40. data/lib/httparty/response.rb +59 -8
  41. data/lib/httparty/response_fragment.rb +21 -0
  42. data/lib/httparty/text_encoder.rb +72 -0
  43. data/lib/httparty/utils.rb +13 -0
  44. data/lib/httparty/version.rb +3 -1
  45. data/lib/httparty.rb +70 -25
  46. data/website/css/common.css +1 -1
  47. metadata +37 -103
  48. data/.simplecov +0 -1
  49. data/.travis.yml +0 -9
  50. data/features/basic_authentication.feature +0 -20
  51. data/features/command_line.feature +0 -95
  52. data/features/deals_with_http_error_codes.feature +0 -26
  53. data/features/digest_authentication.feature +0 -30
  54. data/features/handles_compressed_responses.feature +0 -27
  55. data/features/handles_multiple_formats.feature +0 -57
  56. data/features/steps/env.rb +0 -27
  57. data/features/steps/httparty_response_steps.rb +0 -56
  58. data/features/steps/httparty_steps.rb +0 -43
  59. data/features/steps/mongrel_helper.rb +0 -127
  60. data/features/steps/remote_service_steps.rb +0 -92
  61. data/features/supports_read_timeout_option.feature +0 -13
  62. data/features/supports_redirection.feature +0 -22
  63. data/features/supports_timeout_option.feature +0 -13
  64. data/spec/fixtures/delicious.xml +0 -23
  65. data/spec/fixtures/empty.xml +0 -0
  66. data/spec/fixtures/google.html +0 -3
  67. data/spec/fixtures/ssl/generate.sh +0 -29
  68. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  69. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  70. data/spec/fixtures/ssl/generated/ca.key +0 -15
  71. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  72. data/spec/fixtures/ssl/generated/server.crt +0 -13
  73. data/spec/fixtures/ssl/generated/server.key +0 -15
  74. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  75. data/spec/fixtures/twitter.csv +0 -2
  76. data/spec/fixtures/twitter.json +0 -1
  77. data/spec/fixtures/twitter.xml +0 -403
  78. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  79. data/spec/httparty/connection_adapter_spec.rb +0 -495
  80. data/spec/httparty/cookie_hash_spec.rb +0 -100
  81. data/spec/httparty/exception_spec.rb +0 -45
  82. data/spec/httparty/hash_conversions_spec.rb +0 -49
  83. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  84. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  85. data/spec/httparty/logger/logger_spec.rb +0 -38
  86. data/spec/httparty/net_digest_auth_spec.rb +0 -268
  87. data/spec/httparty/parser_spec.rb +0 -190
  88. data/spec/httparty/request_spec.rb +0 -1279
  89. data/spec/httparty/response_spec.rb +0 -347
  90. data/spec/httparty/ssl_spec.rb +0 -74
  91. data/spec/httparty_spec.rb +0 -878
  92. data/spec/spec_helper.rb +0 -51
  93. data/spec/support/ssl_test_helper.rb +0 -47
  94. data/spec/support/ssl_test_server.rb +0 -80
  95. data/spec/support/stub_response.rb +0 -49
@@ -1,878 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- RSpec.describe HTTParty do
4
- before(:each) do
5
- @klass = Class.new
6
- @klass.instance_eval { include HTTParty }
7
- end
8
-
9
- describe "pem" do
10
- it 'should set the pem content' do
11
- @klass.pem 'PEM-CONTENT'
12
- expect(@klass.default_options[:pem]).to eq('PEM-CONTENT')
13
- end
14
-
15
- it "should set the password to nil if it's not provided" do
16
- @klass.pem 'PEM-CONTENT'
17
- expect(@klass.default_options[:pem_password]).to be_nil
18
- end
19
-
20
- it 'should set the password' do
21
- @klass.pem 'PEM-CONTENT', 'PASSWORD'
22
- expect(@klass.default_options[:pem_password]).to eq('PASSWORD')
23
- end
24
- end
25
-
26
- describe "pkcs12" do
27
- it 'should set the p12 content' do
28
- @klass.pkcs12 'P12-CONTENT', 'PASSWORD'
29
- expect(@klass.default_options[:p12]).to eq('P12-CONTENT')
30
- end
31
-
32
- it 'should set the password' do
33
- @klass.pkcs12 'P12-CONTENT', 'PASSWORD'
34
- expect(@klass.default_options[:p12_password]).to eq('PASSWORD')
35
- end
36
- end
37
-
38
- describe 'ssl_version' do
39
- it 'should set the ssl_version content' do
40
- @klass.ssl_version :SSLv3
41
- expect(@klass.default_options[:ssl_version]).to eq(:SSLv3)
42
- end
43
- end
44
-
45
- describe 'ciphers' do
46
- it 'should set the ciphers content' do
47
- expect(@klass.default_options[:ciphers]).to be_nil
48
- @klass.ciphers 'RC4-SHA'
49
- expect(@klass.default_options[:ciphers]).to eq('RC4-SHA')
50
- end
51
- end
52
-
53
- describe 'http_proxy' do
54
- it 'should set the address' do
55
- @klass.http_proxy 'proxy.foo.com', 80
56
- options = @klass.default_options
57
- expect(options[:http_proxyaddr]).to eq('proxy.foo.com')
58
- expect(options[:http_proxyport]).to eq(80)
59
- end
60
-
61
- it 'should set the proxy user and pass when they are provided' do
62
- @klass.http_proxy 'proxy.foo.com', 80, 'user', 'pass'
63
- options = @klass.default_options
64
- expect(options[:http_proxyuser]).to eq('user')
65
- expect(options[:http_proxypass]).to eq('pass')
66
- end
67
- end
68
-
69
- describe "base uri" do
70
- before(:each) do
71
- @klass.base_uri('api.foo.com/v1')
72
- end
73
-
74
- it "should have reader" do
75
- expect(@klass.base_uri).to eq('http://api.foo.com/v1')
76
- end
77
-
78
- it 'should have writer' do
79
- @klass.base_uri('http://api.foobar.com')
80
- expect(@klass.base_uri).to eq('http://api.foobar.com')
81
- end
82
-
83
- it 'should not modify the parameter during assignment' do
84
- uri = 'http://api.foobar.com'
85
- @klass.base_uri(uri)
86
- expect(uri).to eq('http://api.foobar.com')
87
- end
88
- end
89
-
90
- describe ".disable_rails_query_string_format" do
91
- it "sets the query string normalizer to HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER" do
92
- @klass.disable_rails_query_string_format
93
- expect(@klass.default_options[:query_string_normalizer]).to eq(HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER)
94
- end
95
- end
96
-
97
- describe ".normalize_base_uri" do
98
- it "should add http if not present for non ssl requests" do
99
- uri = HTTParty.normalize_base_uri('api.foobar.com')
100
- expect(uri).to eq('http://api.foobar.com')
101
- end
102
-
103
- it "should add https if not present for ssl requests" do
104
- uri = HTTParty.normalize_base_uri('api.foo.com/v1:443')
105
- expect(uri).to eq('https://api.foo.com/v1:443')
106
- end
107
-
108
- it "should not remove https for ssl requests" do
109
- uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443')
110
- expect(uri).to eq('https://api.foo.com/v1:443')
111
- end
112
-
113
- it 'should not modify the parameter' do
114
- uri = 'http://api.foobar.com'
115
- HTTParty.normalize_base_uri(uri)
116
- expect(uri).to eq('http://api.foobar.com')
117
- end
118
-
119
- it "should not treat uri's with a port of 4430 as ssl" do
120
- uri = HTTParty.normalize_base_uri('http://api.foo.com:4430/v1')
121
- expect(uri).to eq('http://api.foo.com:4430/v1')
122
- end
123
- end
124
-
125
- describe "headers" do
126
- def expect_headers(header = {})
127
- expect(HTTParty::Request).to receive(:new) \
128
- .with(anything, anything, hash_including({ headers: header })) \
129
- .and_return(double("mock response", perform: nil))
130
- end
131
-
132
- it "does not modify default_options when no arguments are passed" do
133
- @klass.headers
134
- expect(@klass.default_options[:headers]).to eq(nil)
135
- end
136
-
137
- it "should default to empty hash" do
138
- expect(@klass.headers).to eq({})
139
- end
140
-
141
- it "should be able to be updated" do
142
- init_headers = {foo: 'bar', baz: 'spax'}
143
- @klass.headers init_headers
144
- expect(@klass.headers).to eq(init_headers)
145
- end
146
-
147
- it "uses the class headers when sending a request" do
148
- expect_headers(foo: 'bar')
149
- @klass.headers(foo: 'bar')
150
- @klass.get('')
151
- end
152
-
153
- it "merges class headers with request headers" do
154
- expect_headers(baz: 'spax', foo: 'bar')
155
- @klass.headers(foo: 'bar')
156
- @klass.get('', headers: {baz: 'spax'})
157
- end
158
-
159
- it 'overrides class headers with request headers' do
160
- expect_headers(baz: 'spax', foo: 'baz')
161
- @klass.headers(foo: 'bar')
162
- @klass.get('', headers: {baz: 'spax', foo: 'baz'})
163
- end
164
-
165
- context "with cookies" do
166
- it 'utilizes the class-level cookies' do
167
- expect_headers(foo: 'bar', 'cookie' => 'type=snickerdoodle')
168
- @klass.headers(foo: 'bar')
169
- @klass.cookies(type: 'snickerdoodle')
170
- @klass.get('')
171
- end
172
-
173
- it 'adds cookies to the headers' do
174
- expect_headers(foo: 'bar', 'cookie' => 'type=snickerdoodle')
175
- @klass.headers(foo: 'bar')
176
- @klass.get('', cookies: {type: 'snickerdoodle'})
177
- end
178
-
179
- it 'doesnt modify default headers' do
180
- expect(@klass.headers).to eq({})
181
- expect_headers('cookie' => 'type=snickerdoodle')
182
- @klass.get('', cookies: {type: 'snickerdoodle'})
183
- expect(@klass.headers).to eq({})
184
- end
185
-
186
- it 'adds optional cookies to the optional headers' do
187
- expect_headers(baz: 'spax', 'cookie' => 'type=snickerdoodle')
188
- @klass.get('', cookies: {type: 'snickerdoodle'}, headers: {baz: 'spax'})
189
- end
190
- end
191
- end
192
-
193
- describe "cookies" do
194
- def expect_cookie_header(s)
195
- expect(HTTParty::Request).to receive(:new) \
196
- .with(anything, anything, hash_including({ headers: { "cookie" => s } })) \
197
- .and_return(double("mock response", perform: nil))
198
- end
199
-
200
- it "should not be in the headers by default" do
201
- allow(HTTParty::Request).to receive(:new).and_return(double(nil, perform: nil))
202
- @klass.get("")
203
- expect(@klass.headers.keys).not_to include("cookie")
204
- end
205
-
206
- it "should raise an ArgumentError if passed a non-Hash" do
207
- expect do
208
- @klass.cookies("nonsense")
209
- end.to raise_error(ArgumentError)
210
- end
211
-
212
- it "should allow a cookie to be specified with a one-off request" do
213
- expect_cookie_header "type=snickerdoodle"
214
- @klass.get("", cookies: { type: "snickerdoodle" })
215
- end
216
-
217
- describe "when a cookie is set at the class level" do
218
- before(:each) do
219
- @klass.cookies({ type: "snickerdoodle" })
220
- end
221
-
222
- it "should include that cookie in the request" do
223
- expect_cookie_header "type=snickerdoodle"
224
- @klass.get("")
225
- end
226
-
227
- it "should pass the proper cookies when requested multiple times" do
228
- 2.times do
229
- expect_cookie_header "type=snickerdoodle"
230
- @klass.get("")
231
- end
232
- end
233
-
234
- it "should allow the class defaults to be overridden" do
235
- expect_cookie_header "type=chocolate_chip"
236
-
237
- @klass.get("", cookies: { type: "chocolate_chip" })
238
- end
239
- end
240
-
241
- describe "in a class with multiple methods that use different cookies" do
242
- before(:each) do
243
- @klass.instance_eval do
244
- def first_method
245
- get("first_method", cookies: { first_method_cookie: "foo" })
246
- end
247
-
248
- def second_method
249
- get("second_method", cookies: { second_method_cookie: "foo" })
250
- end
251
- end
252
- end
253
-
254
- it "should not allow cookies used in one method to carry over into other methods" do
255
- expect_cookie_header "first_method_cookie=foo"
256
- @klass.first_method
257
-
258
- expect_cookie_header "second_method_cookie=foo"
259
- @klass.second_method
260
- end
261
- end
262
- end
263
-
264
- describe "default params" do
265
- it "should default to empty hash" do
266
- expect(@klass.default_params).to eq({})
267
- end
268
-
269
- it "should be able to be updated" do
270
- new_defaults = {foo: 'bar', baz: 'spax'}
271
- @klass.default_params new_defaults
272
- expect(@klass.default_params).to eq(new_defaults)
273
- end
274
- end
275
-
276
- describe "default timeout" do
277
- it "should default to nil" do
278
- expect(@klass.default_options[:timeout]).to eq(nil)
279
- end
280
-
281
- it "should support updating" do
282
- @klass.default_timeout 10
283
- expect(@klass.default_options[:timeout]).to eq(10)
284
- end
285
-
286
- it "should support floats" do
287
- @klass.default_timeout 0.5
288
- expect(@klass.default_options[:timeout]).to eq(0.5)
289
- end
290
- end
291
-
292
- describe "debug_output" do
293
- it "stores the given stream as a default_option" do
294
- @klass.debug_output $stdout
295
- expect(@klass.default_options[:debug_output]).to eq($stdout)
296
- end
297
-
298
- it "stores the $stderr stream by default" do
299
- @klass.debug_output
300
- expect(@klass.default_options[:debug_output]).to eq($stderr)
301
- end
302
- end
303
-
304
- describe "basic http authentication" do
305
- it "should work" do
306
- @klass.basic_auth 'foobar', 'secret'
307
- expect(@klass.default_options[:basic_auth]).to eq({username: 'foobar', password: 'secret'})
308
- end
309
- end
310
-
311
- describe "digest http authentication" do
312
- it "should work" do
313
- @klass.digest_auth 'foobar', 'secret'
314
- expect(@klass.default_options[:digest_auth]).to eq({username: 'foobar', password: 'secret'})
315
- end
316
- end
317
-
318
- describe "parser" do
319
- class CustomParser
320
- def self.parse(body)
321
- {sexy: true}
322
- end
323
- end
324
-
325
- let(:parser) do
326
- proc { |data, format| CustomParser.parse(data) }
327
- end
328
-
329
- it "should set parser options" do
330
- @klass.parser parser
331
- expect(@klass.default_options[:parser]).to eq(parser)
332
- end
333
-
334
- it "should be able parse response with custom parser" do
335
- @klass.parser parser
336
- stub_request(:get, 'http://twitter.com/statuses/public_timeline.xml')
337
- .to_return(body: 'tweets')
338
- custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml')
339
- expect(custom_parsed_response[:sexy]).to eq(true)
340
- end
341
-
342
- it "raises UnsupportedFormat when the parser cannot handle the format" do
343
- @klass.format :json
344
- class MyParser < HTTParty::Parser
345
- SupportedFormats = {}
346
- end unless defined?(MyParser)
347
- expect do
348
- @klass.parser MyParser
349
- end.to raise_error(HTTParty::UnsupportedFormat)
350
- end
351
-
352
- it 'does not validate format whe custom parser is a proc' do
353
- expect do
354
- @klass.format :json
355
- @klass.parser lambda {|body, format|}
356
- end.to_not raise_error
357
- end
358
- end
359
-
360
- describe "uri_adapter" do
361
-
362
- require 'forwardable'
363
- class CustomURIAdaptor
364
- extend Forwardable
365
- def_delegators :@uri, :userinfo, :relative?, :query, :query=, :scheme, :path, :host, :port
366
-
367
- def initialize uri
368
- @uri = uri
369
- end
370
-
371
- def self.parse uri
372
- new URI.parse uri
373
- end
374
- end
375
-
376
- let(:uri_adapter) { CustomURIAdaptor }
377
-
378
- it "should set the uri_adapter" do
379
- @klass.uri_adapter uri_adapter
380
- expect(@klass.default_options[:uri_adapter]).to be uri_adapter
381
- end
382
-
383
- it "should raise an ArgumentError if uri_adapter doesn't implement parse method" do
384
- expect do
385
- @klass.uri_adapter double()
386
- end.to raise_error(ArgumentError)
387
- end
388
-
389
-
390
- it "should process a request with a uri instance parsed from the uri_adapter" do
391
- uri = 'http://foo.com/bar'
392
- stub_request(:get, uri).to_return(body: 'stuff')
393
- @klass.uri_adapter uri_adapter
394
- expect(@klass.get(uri).parsed_response).to eq('stuff')
395
- end
396
-
397
- end
398
-
399
- describe "connection_adapter" do
400
- let(:uri) { 'http://google.com/api.json' }
401
- let(:connection_adapter) { double('CustomConnectionAdapter') }
402
-
403
- it "should set the connection_adapter" do
404
- @klass.connection_adapter connection_adapter
405
- expect(@klass.default_options[:connection_adapter]).to be connection_adapter
406
- end
407
-
408
- it "should set the connection_adapter_options when provided" do
409
- options = {foo: :bar}
410
- @klass.connection_adapter connection_adapter, options
411
- expect(@klass.default_options[:connection_adapter_options]).to be options
412
- end
413
-
414
- it "should not set the connection_adapter_options when not provided" do
415
- @klass.connection_adapter connection_adapter
416
- expect(@klass.default_options[:connection_adapter_options]).to be_nil
417
- end
418
-
419
- it "should process a request with a connection from the adapter" do
420
- connection_adapter_options = {foo: :bar}
421
- expect(connection_adapter).to receive(:call) { |u, o|
422
- expect(o[:connection_adapter_options]).to eq(connection_adapter_options)
423
- HTTParty::ConnectionAdapter.call(u, o)
424
- }.with(URI.parse(uri), kind_of(Hash))
425
- stub_request(:get, uri).to_return(body: 'stuff')
426
- @klass.connection_adapter connection_adapter, connection_adapter_options
427
- expect(@klass.get(uri).parsed_response).to eq('stuff')
428
- end
429
- end
430
-
431
- describe "format" do
432
- it "should allow xml" do
433
- @klass.format :xml
434
- expect(@klass.default_options[:format]).to eq(:xml)
435
- end
436
-
437
- it "should allow csv" do
438
- @klass.format :csv
439
- expect(@klass.default_options[:format]).to eq(:csv)
440
- end
441
-
442
- it "should allow json" do
443
- @klass.format :json
444
- expect(@klass.default_options[:format]).to eq(:json)
445
- end
446
-
447
- it "should allow plain" do
448
- @klass.format :plain
449
- expect(@klass.default_options[:format]).to eq(:plain)
450
- end
451
-
452
- it 'should not allow funky format' do
453
- expect do
454
- @klass.format :foobar
455
- end.to raise_error(HTTParty::UnsupportedFormat)
456
- end
457
-
458
- it 'should only print each format once with an exception' do
459
- expect do
460
- @klass.format :foobar
461
- end.to raise_error(HTTParty::UnsupportedFormat, "':foobar' Must be one of: csv, html, json, plain, xml")
462
- end
463
-
464
- it 'sets the default parser' do
465
- expect(@klass.default_options[:parser]).to be_nil
466
- @klass.format :json
467
- expect(@klass.default_options[:parser]).to eq(HTTParty::Parser)
468
- end
469
-
470
- it 'does not reset parser to the default parser' do
471
- my_parser = lambda {}
472
- @klass.parser my_parser
473
- @klass.format :json
474
- expect(@klass.parser).to eq(my_parser)
475
- end
476
- end
477
-
478
- describe "#no_follow" do
479
- it "sets no_follow to false by default" do
480
- @klass.no_follow
481
- expect(@klass.default_options[:no_follow]).to be_falsey
482
- end
483
-
484
- it "sets the no_follow option to true" do
485
- @klass.no_follow true
486
- expect(@klass.default_options[:no_follow]).to be_truthy
487
- end
488
- end
489
-
490
- describe "#maintain_method_across_redirects" do
491
- it "sets maintain_method_across_redirects to true by default" do
492
- @klass.maintain_method_across_redirects
493
- expect(@klass.default_options[:maintain_method_across_redirects]).to be_truthy
494
- end
495
-
496
- it "sets the maintain_method_across_redirects option to false" do
497
- @klass.maintain_method_across_redirects false
498
- expect(@klass.default_options[:maintain_method_across_redirects]).to be_falsey
499
- end
500
- end
501
-
502
- describe "#resend_on_redirect" do
503
- it "sets resend_on_redirect to true by default" do
504
- @klass.resend_on_redirect
505
- expect(@klass.default_options[:resend_on_redirect]).to be_truthy
506
- end
507
-
508
- it "sets resend_on_redirect option to false" do
509
- @klass.resend_on_redirect false
510
- expect(@klass.default_options[:resend_on_redirect]).to be_falsey
511
- end
512
- end
513
-
514
- describe ".follow_redirects" do
515
- it "sets follow redirects to true by default" do
516
- @klass.follow_redirects
517
- expect(@klass.default_options[:follow_redirects]).to be_truthy
518
- end
519
-
520
- it "sets the follow_redirects option to false" do
521
- @klass.follow_redirects false
522
- expect(@klass.default_options[:follow_redirects]).to be_falsey
523
- end
524
- end
525
-
526
- describe ".query_string_normalizer" do
527
- it "sets the query_string_normalizer option" do
528
- normalizer = proc {}
529
- @klass.query_string_normalizer normalizer
530
- expect(@klass.default_options[:query_string_normalizer]).to eq(normalizer)
531
- end
532
- end
533
-
534
- describe ".raise_on" do
535
- context 'when parameters is an array' do
536
- it 'sets raise_on option' do
537
- @klass.raise_on [500, 404]
538
- expect(@klass.default_options[:raise_on]).to contain_exactly(404, 500)
539
- end
540
- end
541
-
542
- context 'when parameters is a fixnum' do
543
- it 'sets raise_on option' do
544
- @klass.raise_on 404
545
- expect(@klass.default_options[:raise_on]).to contain_exactly(404)
546
- end
547
- end
548
- end
549
-
550
- describe "with explicit override of automatic redirect handling" do
551
- before do
552
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', format: :xml, no_follow: true)
553
- @redirect = stub_response 'first redirect', 302
554
- @redirect['location'] = 'http://foo.com/bar'
555
- allow(HTTParty::Request).to receive_messages(new: @request)
556
- end
557
-
558
- it "should fail with redirected GET" do
559
- expect do
560
- @error = @klass.get('/foo', no_follow: true)
561
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
562
- end
563
-
564
- it "should fail with redirected POST" do
565
- expect do
566
- @klass.post('/foo', no_follow: true)
567
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
568
- end
569
-
570
- it "should fail with redirected PATCH" do
571
- expect do
572
- @klass.patch('/foo', no_follow: true)
573
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
574
- end
575
-
576
- it "should fail with redirected DELETE" do
577
- expect do
578
- @klass.delete('/foo', no_follow: true)
579
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
580
- end
581
-
582
- it "should fail with redirected MOVE" do
583
- expect do
584
- @klass.move('/foo', no_follow: true)
585
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
586
- end
587
-
588
- it "should fail with redirected COPY" do
589
- expect do
590
- @klass.copy('/foo', no_follow: true)
591
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
592
- end
593
-
594
- it "should fail with redirected PUT" do
595
- expect do
596
- @klass.put('/foo', no_follow: true)
597
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
598
- end
599
-
600
- it "should fail with redirected HEAD" do
601
- expect do
602
- @klass.head('/foo', no_follow: true)
603
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
604
- end
605
-
606
- it "should fail with redirected OPTIONS" do
607
- expect do
608
- @klass.options('/foo', no_follow: true)
609
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
610
- end
611
-
612
- it "should fail with redirected MKCOL" do
613
- expect do
614
- @klass.mkcol('/foo', no_follow: true)
615
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
616
- end
617
- end
618
-
619
- describe "head requests should follow redirects requesting HEAD only" do
620
- before do
621
- allow(HTTParty::Request).to receive(:new).
622
- and_return(double("mock response", perform: nil))
623
- end
624
-
625
- it "should remain HEAD request across redirects, unless specified otherwise" do
626
- expect(@klass).to receive(:ensure_method_maintained_across_redirects).with({})
627
- @klass.head('/foo')
628
- end
629
-
630
- end
631
-
632
- describe "#ensure_method_maintained_across_redirects" do
633
- it "should set maintain_method_across_redirects option if unspecified" do
634
- options = {}
635
- @klass.send(:ensure_method_maintained_across_redirects, options)
636
- expect(options[:maintain_method_across_redirects]).to be_truthy
637
- end
638
-
639
- it "should not set maintain_method_across_redirects option if value is present" do
640
- options = { maintain_method_across_redirects: false }
641
- @klass.send(:ensure_method_maintained_across_redirects, options)
642
- expect(options[:maintain_method_across_redirects]).to be_falsey
643
- end
644
- end
645
-
646
- describe "with multiple class definitions" do
647
- before(:each) do
648
- @klass.instance_eval do
649
- base_uri "http://first.com"
650
- default_params one: 1
651
- end
652
-
653
- @additional_klass = Class.new
654
- @additional_klass.instance_eval do
655
- include HTTParty
656
- base_uri "http://second.com"
657
- default_params two: 2
658
- end
659
- end
660
-
661
- it "should not run over each others options" do
662
- expect(@klass.default_options).to eq({ base_uri: 'http://first.com', default_params: { one: 1 } })
663
- expect(@additional_klass.default_options).to eq({ base_uri: 'http://second.com', default_params: { two: 2 } })
664
- end
665
- end
666
-
667
- describe "two child classes inheriting from one parent" do
668
- before(:each) do
669
- @parent = Class.new do
670
- include HTTParty
671
- def self.name
672
- "Parent"
673
- end
674
- end
675
-
676
- @child1 = Class.new(@parent)
677
- @child2 = Class.new(@parent)
678
- end
679
-
680
- it "does not modify each others inherited attributes" do
681
- @child1.default_params joe: "alive"
682
- @child2.default_params joe: "dead"
683
-
684
- expect(@child1.default_options).to eq({ default_params: {joe: "alive"} })
685
- expect(@child2.default_options).to eq({ default_params: {joe: "dead"} })
686
-
687
- expect(@parent.default_options).to eq({ })
688
- end
689
-
690
- it "inherits default_options from the superclass" do
691
- @parent.basic_auth 'user', 'password'
692
- expect(@child1.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
693
- @child1.basic_auth 'u', 'p' # modifying child1 has no effect on child2
694
- expect(@child2.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
695
- end
696
-
697
- it "doesn't modify the parent's default options" do
698
- @parent.basic_auth 'user', 'password'
699
-
700
- @child1.basic_auth 'u', 'p'
701
- expect(@child1.default_options).to eq({basic_auth: {username: 'u', password: 'p'}})
702
-
703
- @child1.basic_auth 'email', 'token'
704
- expect(@child1.default_options).to eq({basic_auth: {username: 'email', password: 'token'}})
705
-
706
- expect(@parent.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
707
- end
708
-
709
- it "doesn't modify hashes in the parent's default options" do
710
- @parent.headers 'Accept' => 'application/json'
711
- @child1.headers 'Accept' => 'application/xml'
712
-
713
- expect(@parent.default_options[:headers]).to eq({'Accept' => 'application/json'})
714
- expect(@child1.default_options[:headers]).to eq({'Accept' => 'application/xml'})
715
- end
716
-
717
- it "works with lambda values" do
718
- @child1.default_options[:imaginary_option] = lambda { "This is a new lambda "}
719
- expect(@child1.default_options[:imaginary_option]).to be_a Proc
720
- end
721
-
722
- it 'should dup the proc on the child class' do
723
- imaginary_option = lambda { 2 * 3.14 }
724
- @parent.default_options[:imaginary_option] = imaginary_option
725
- expect(@parent.default_options[:imaginary_option].call).to eq(imaginary_option.call)
726
- @child1.default_options[:imaginary_option]
727
- expect(@child1.default_options[:imaginary_option].call).to eq(imaginary_option.call)
728
- expect(@child1.default_options[:imaginary_option]).not_to be_equal imaginary_option
729
- end
730
-
731
- it "inherits default_cookies from the parent class" do
732
- @parent.cookies 'type' => 'chocolate_chip'
733
- expect(@child1.default_cookies).to eq({"type" => "chocolate_chip"})
734
- @child1.cookies 'type' => 'snickerdoodle'
735
- expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"})
736
- expect(@child2.default_cookies).to eq({"type" => "chocolate_chip"})
737
- end
738
-
739
- it "doesn't modify the parent's default cookies" do
740
- @parent.cookies 'type' => 'chocolate_chip'
741
-
742
- @child1.cookies 'type' => 'snickerdoodle'
743
- expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"})
744
-
745
- expect(@parent.default_cookies).to eq({"type" => "chocolate_chip"})
746
- end
747
- end
748
-
749
- describe "grand parent with inherited callback" do
750
- before do
751
- @grand_parent = Class.new do
752
- def self.inherited(subclass)
753
- subclass.instance_variable_set(:@grand_parent, true)
754
- end
755
- end
756
- @parent = Class.new(@grand_parent) do
757
- include HTTParty
758
- end
759
- end
760
- it "continues running the #inherited on the parent" do
761
- child = Class.new(@parent)
762
- expect(child.instance_variable_get(:@grand_parent)).to be_truthy
763
- end
764
- end
765
-
766
- describe "#get" do
767
- it "should be able to get html" do
768
- stub_http_response_with('google.html')
769
- expect(HTTParty.get('http://www.google.com').parsed_response).to eq(file_fixture('google.html'))
770
- end
771
-
772
- it "should be able to get chunked html" do
773
- chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4)
774
- stub_chunked_http_response_with(chunks)
775
-
776
- expect(
777
- HTTParty.get('http://www.google.com') do |fragment|
778
- expect(chunks).to include(fragment)
779
- end.parsed_response
780
- ).to eq(chunks.join)
781
- end
782
-
783
- it "should return an empty body if stream_body option is turned on" do
784
- chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4)
785
- options = {stream_body: true, format: 'html'}
786
- stub_chunked_http_response_with(chunks, options)
787
-
788
- expect(
789
- HTTParty.get('http://www.google.com', options) do |fragment|
790
- expect(chunks).to include(fragment)
791
- end.parsed_response
792
- ).to eq(nil)
793
- end
794
-
795
- it "should be able parse response type json automatically" do
796
- stub_http_response_with('twitter.json')
797
- tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
798
- expect(tweets.size).to eq(20)
799
- expect(tweets.first['user']).to eq({
800
- "name" => "Pyk",
801
- "url" => nil,
802
- "id" => "7694602",
803
- "description" => nil,
804
- "protected" => false,
805
- "screen_name" => "Pyk",
806
- "followers_count" => 1,
807
- "location" => "Opera Plaza, California",
808
- "profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
809
- })
810
- end
811
-
812
- it "should be able parse response type xml automatically" do
813
- stub_http_response_with('twitter.xml')
814
- tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
815
- expect(tweets['statuses'].size).to eq(20)
816
- expect(tweets['statuses'].first['user']).to eq({
817
- "name" => "Magic 8 Bot",
818
- "url" => nil,
819
- "id" => "17656026",
820
- "description" => "ask me a question",
821
- "protected" => "false",
822
- "screen_name" => "magic8bot",
823
- "followers_count" => "90",
824
- "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
825
- "location" => nil
826
- })
827
- end
828
-
829
- it "should be able parse response type csv automatically" do
830
- stub_http_response_with('twitter.csv')
831
- profile = HTTParty.get('http://twitter.com/statuses/profile.csv')
832
- expect(profile.size).to eq(2)
833
- expect(profile[0]).to eq(%w(name url id description protected screen_name followers_count profile_image_url location))
834
- expect(profile[1]).to eq(["Magic 8 Bot", nil, "17656026", "ask me a question", "false", "magic8bot", "90", "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg", nil])
835
- end
836
-
837
- it "should not get undefined method add_node for nil class for the following xml" do
838
- stub_http_response_with('undefined_method_add_node_for_nil.xml')
839
- result = HTTParty.get('http://foobar.com')
840
- expect(result.parsed_response).to eq({"Entities" => {"href" => "https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results" => "0", "total" => "0", "page_size" => "25", "page" => "1"}})
841
- end
842
-
843
- it "should parse empty response fine" do
844
- stub_http_response_with('empty.xml')
845
- result = HTTParty.get('http://foobar.com')
846
- expect(result).to be_nil
847
- end
848
-
849
- it "should accept http URIs" do
850
- stub_http_response_with('google.html')
851
- expect do
852
- HTTParty.get('http://google.com')
853
- end.not_to raise_error
854
- end
855
-
856
- it "should accept https URIs" do
857
- stub_http_response_with('google.html')
858
- expect do
859
- HTTParty.get('https://google.com')
860
- end.not_to raise_error
861
- end
862
-
863
- it "should accept webcal URIs" do
864
- uri = 'http://google.com/'
865
- stub_request(:get, uri).to_return(body: 'stuff')
866
- uri = 'webcal://google.com/'
867
- expect do
868
- HTTParty.get(uri)
869
- end.not_to raise_error
870
- end
871
-
872
- it "should raise an InvalidURIError on URIs that can't be parsed at all" do
873
- expect do
874
- HTTParty.get("It's the one that says 'Bad URI'")
875
- end.to raise_error(URI::InvalidURIError)
876
- end
877
- end
878
- end