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