httparty 0.16.2 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

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