httparty 0.13.7 → 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} +220 -59
  7. data/Gemfile +8 -3
  8. data/README.md +8 -7
  9. data/bin/httparty +3 -1
  10. data/docs/README.md +171 -0
  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 +17 -6
  26. data/examples/twitter.rb +2 -2
  27. data/examples/whoismyrep.rb +1 -1
  28. data/httparty.gemspec +7 -5
  29. data/lib/httparty/connection_adapter.rb +86 -20
  30. data/lib/httparty/cookie_hash.rb +10 -8
  31. data/lib/httparty/decompressor.rb +92 -0
  32. data/lib/httparty/exceptions.rb +8 -2
  33. data/lib/httparty/hash_conversions.rb +30 -8
  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 +68 -23
  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 +23 -21
  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 +156 -106
  45. data/lib/httparty/response/headers.rb +23 -19
  46. data/lib/httparty/response.rb +92 -13
  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 +98 -34
  52. data/website/css/common.css +1 -1
  53. metadata +34 -113
  54. data/.travis.yml +0 -7
  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 -52
  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 -90
  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 -468
  86. data/spec/httparty/cookie_hash_spec.rb +0 -83
  87. data/spec/httparty/exception_spec.rb +0 -38
  88. data/spec/httparty/hash_conversions_spec.rb +0 -41
  89. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  90. data/spec/httparty/logger/curl_formatter_spec.rb +0 -18
  91. data/spec/httparty/logger/logger_spec.rb +0 -38
  92. data/spec/httparty/net_digest_auth_spec.rb +0 -230
  93. data/spec/httparty/parser_spec.rb +0 -173
  94. data/spec/httparty/request_spec.rb +0 -1073
  95. data/spec/httparty/response_spec.rb +0 -241
  96. data/spec/httparty/ssl_spec.rb +0 -74
  97. data/spec/httparty_spec.rb +0 -850
  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,850 +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 "with explicit override of automatic redirect handling" do
529
- before do
530
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', format: :xml, no_follow: true)
531
- @redirect = stub_response 'first redirect', 302
532
- @redirect['location'] = 'http://foo.com/bar'
533
- allow(HTTParty::Request).to receive_messages(new: @request)
534
- end
535
-
536
- it "should fail with redirected GET" do
537
- expect do
538
- @error = @klass.get('/foo', no_follow: true)
539
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
540
- end
541
-
542
- it "should fail with redirected POST" do
543
- expect do
544
- @klass.post('/foo', no_follow: true)
545
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
546
- end
547
-
548
- it "should fail with redirected PATCH" do
549
- expect do
550
- @klass.patch('/foo', no_follow: true)
551
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
552
- end
553
-
554
- it "should fail with redirected DELETE" do
555
- expect do
556
- @klass.delete('/foo', no_follow: true)
557
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
558
- end
559
-
560
- it "should fail with redirected MOVE" do
561
- expect do
562
- @klass.move('/foo', no_follow: true)
563
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
564
- end
565
-
566
- it "should fail with redirected COPY" do
567
- expect do
568
- @klass.copy('/foo', no_follow: true)
569
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
570
- end
571
-
572
- it "should fail with redirected PUT" do
573
- expect do
574
- @klass.put('/foo', no_follow: true)
575
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
576
- end
577
-
578
- it "should fail with redirected HEAD" do
579
- expect do
580
- @klass.head('/foo', no_follow: true)
581
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
582
- end
583
-
584
- it "should fail with redirected OPTIONS" do
585
- expect do
586
- @klass.options('/foo', no_follow: true)
587
- end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')}
588
- end
589
- end
590
-
591
- describe "head requests should follow redirects requesting HEAD only" do
592
- before do
593
- allow(HTTParty::Request).to receive(:new).
594
- and_return(double("mock response", perform: nil))
595
- end
596
-
597
- it "should remain HEAD request across redirects, unless specified otherwise" do
598
- expect(@klass).to receive(:ensure_method_maintained_across_redirects).with({})
599
- @klass.head('/foo')
600
- end
601
-
602
- end
603
-
604
- describe "#ensure_method_maintained_across_redirects" do
605
- it "should set maintain_method_across_redirects option if unspecified" do
606
- options = {}
607
- @klass.send(:ensure_method_maintained_across_redirects, options)
608
- expect(options[:maintain_method_across_redirects]).to be_truthy
609
- end
610
-
611
- it "should not set maintain_method_across_redirects option if value is present" do
612
- options = { maintain_method_across_redirects: false }
613
- @klass.send(:ensure_method_maintained_across_redirects, options)
614
- expect(options[:maintain_method_across_redirects]).to be_falsey
615
- end
616
- end
617
-
618
- describe "with multiple class definitions" do
619
- before(:each) do
620
- @klass.instance_eval do
621
- base_uri "http://first.com"
622
- default_params one: 1
623
- end
624
-
625
- @additional_klass = Class.new
626
- @additional_klass.instance_eval do
627
- include HTTParty
628
- base_uri "http://second.com"
629
- default_params two: 2
630
- end
631
- end
632
-
633
- it "should not run over each others options" do
634
- expect(@klass.default_options).to eq({ base_uri: 'http://first.com', default_params: { one: 1 } })
635
- expect(@additional_klass.default_options).to eq({ base_uri: 'http://second.com', default_params: { two: 2 } })
636
- end
637
- end
638
-
639
- describe "two child classes inheriting from one parent" do
640
- before(:each) do
641
- @parent = Class.new do
642
- include HTTParty
643
- def self.name
644
- "Parent"
645
- end
646
- end
647
-
648
- @child1 = Class.new(@parent)
649
- @child2 = Class.new(@parent)
650
- end
651
-
652
- it "does not modify each others inherited attributes" do
653
- @child1.default_params joe: "alive"
654
- @child2.default_params joe: "dead"
655
-
656
- expect(@child1.default_options).to eq({ default_params: {joe: "alive"} })
657
- expect(@child2.default_options).to eq({ default_params: {joe: "dead"} })
658
-
659
- expect(@parent.default_options).to eq({ })
660
- end
661
-
662
- it "inherits default_options from the superclass" do
663
- @parent.basic_auth 'user', 'password'
664
- expect(@child1.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
665
- @child1.basic_auth 'u', 'p' # modifying child1 has no effect on child2
666
- expect(@child2.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
667
- end
668
-
669
- it "doesn't modify the parent's default options" do
670
- @parent.basic_auth 'user', 'password'
671
-
672
- @child1.basic_auth 'u', 'p'
673
- expect(@child1.default_options).to eq({basic_auth: {username: 'u', password: 'p'}})
674
-
675
- @child1.basic_auth 'email', 'token'
676
- expect(@child1.default_options).to eq({basic_auth: {username: 'email', password: 'token'}})
677
-
678
- expect(@parent.default_options).to eq({basic_auth: {username: 'user', password: 'password'}})
679
- end
680
-
681
- it "doesn't modify hashes in the parent's default options" do
682
- @parent.headers 'Accept' => 'application/json'
683
- @child1.headers 'Accept' => 'application/xml'
684
-
685
- expect(@parent.default_options[:headers]).to eq({'Accept' => 'application/json'})
686
- expect(@child1.default_options[:headers]).to eq({'Accept' => 'application/xml'})
687
- end
688
-
689
- it "works with lambda values" do
690
- @child1.default_options[:imaginary_option] = lambda { "This is a new lambda "}
691
- expect(@child1.default_options[:imaginary_option]).to be_a Proc
692
- end
693
-
694
- it 'should dup the proc on the child class' do
695
- imaginary_option = lambda { 2 * 3.14 }
696
- @parent.default_options[:imaginary_option] = imaginary_option
697
- expect(@parent.default_options[:imaginary_option].call).to eq(imaginary_option.call)
698
- @child1.default_options[:imaginary_option]
699
- expect(@child1.default_options[:imaginary_option].call).to eq(imaginary_option.call)
700
- expect(@child1.default_options[:imaginary_option]).not_to be_equal imaginary_option
701
- end
702
-
703
- it "inherits default_cookies from the parent class" do
704
- @parent.cookies 'type' => 'chocolate_chip'
705
- expect(@child1.default_cookies).to eq({"type" => "chocolate_chip"})
706
- @child1.cookies 'type' => 'snickerdoodle'
707
- expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"})
708
- expect(@child2.default_cookies).to eq({"type" => "chocolate_chip"})
709
- end
710
-
711
- it "doesn't modify the parent's default cookies" do
712
- @parent.cookies 'type' => 'chocolate_chip'
713
-
714
- @child1.cookies 'type' => 'snickerdoodle'
715
- expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"})
716
-
717
- expect(@parent.default_cookies).to eq({"type" => "chocolate_chip"})
718
- end
719
- end
720
-
721
- describe "grand parent with inherited callback" do
722
- before do
723
- @grand_parent = Class.new do
724
- def self.inherited(subclass)
725
- subclass.instance_variable_set(:@grand_parent, true)
726
- end
727
- end
728
- @parent = Class.new(@grand_parent) do
729
- include HTTParty
730
- end
731
- end
732
- it "continues running the #inherited on the parent" do
733
- child = Class.new(@parent)
734
- expect(child.instance_variable_get(:@grand_parent)).to be_truthy
735
- end
736
- end
737
-
738
- describe "#get" do
739
- it "should be able to get html" do
740
- stub_http_response_with('google.html')
741
- expect(HTTParty.get('http://www.google.com').parsed_response).to eq(file_fixture('google.html'))
742
- end
743
-
744
- it "should be able to get chunked html" do
745
- chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4)
746
- stub_chunked_http_response_with(chunks)
747
-
748
- expect(
749
- HTTParty.get('http://www.google.com') do |fragment|
750
- expect(chunks).to include(fragment)
751
- end.parsed_response
752
- ).to eq(chunks.join)
753
- end
754
-
755
- it "should return an empty body if stream_body option is turned on" do
756
- chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4)
757
- options = {stream_body: true, format: 'html'}
758
- stub_chunked_http_response_with(chunks, options)
759
-
760
- expect(
761
- HTTParty.get('http://www.google.com', options) do |fragment|
762
- expect(chunks).to include(fragment)
763
- end.parsed_response
764
- ).to eq(nil)
765
- end
766
-
767
- it "should be able parse response type json automatically" do
768
- stub_http_response_with('twitter.json')
769
- tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
770
- expect(tweets.size).to eq(20)
771
- expect(tweets.first['user']).to eq({
772
- "name" => "Pyk",
773
- "url" => nil,
774
- "id" => "7694602",
775
- "description" => nil,
776
- "protected" => false,
777
- "screen_name" => "Pyk",
778
- "followers_count" => 1,
779
- "location" => "Opera Plaza, California",
780
- "profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
781
- })
782
- end
783
-
784
- it "should be able parse response type xml automatically" do
785
- stub_http_response_with('twitter.xml')
786
- tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
787
- expect(tweets['statuses'].size).to eq(20)
788
- expect(tweets['statuses'].first['user']).to eq({
789
- "name" => "Magic 8 Bot",
790
- "url" => nil,
791
- "id" => "17656026",
792
- "description" => "ask me a question",
793
- "protected" => "false",
794
- "screen_name" => "magic8bot",
795
- "followers_count" => "90",
796
- "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
797
- "location" => nil
798
- })
799
- end
800
-
801
- it "should be able parse response type csv automatically" do
802
- stub_http_response_with('twitter.csv')
803
- profile = HTTParty.get('http://twitter.com/statuses/profile.csv')
804
- expect(profile.size).to eq(2)
805
- expect(profile[0]).to eq(%w(name url id description protected screen_name followers_count profile_image_url location))
806
- 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])
807
- end
808
-
809
- it "should not get undefined method add_node for nil class for the following xml" do
810
- stub_http_response_with('undefined_method_add_node_for_nil.xml')
811
- result = HTTParty.get('http://foobar.com')
812
- 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"}})
813
- end
814
-
815
- it "should parse empty response fine" do
816
- stub_http_response_with('empty.xml')
817
- result = HTTParty.get('http://foobar.com')
818
- expect(result).to be_nil
819
- end
820
-
821
- it "should accept http URIs" do
822
- stub_http_response_with('google.html')
823
- expect do
824
- HTTParty.get('http://google.com')
825
- end.not_to raise_error
826
- end
827
-
828
- it "should accept https URIs" do
829
- stub_http_response_with('google.html')
830
- expect do
831
- HTTParty.get('https://google.com')
832
- end.not_to raise_error
833
- end
834
-
835
- it "should accept webcal URIs" do
836
- uri = 'http://google.com/'
837
- FakeWeb.register_uri(:get, uri, body: 'stuff')
838
- uri = 'webcal://google.com/'
839
- expect do
840
- HTTParty.get(uri)
841
- end.not_to raise_error
842
- end
843
-
844
- it "should raise an InvalidURIError on URIs that can't be parsed at all" do
845
- expect do
846
- HTTParty.get("It's the one that says 'Bad URI'")
847
- end.to raise_error(URI::InvalidURIError)
848
- end
849
- end
850
- end