httparty 0.16.4 → 0.20.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.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

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