httparty 0.15.6 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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