httparty 0.14.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +26 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/{History → Changelog.md} +222 -63
  7. data/Gemfile +8 -1
  8. data/Guardfile +3 -2
  9. data/README.md +8 -8
  10. data/bin/httparty +3 -1
  11. data/docs/README.md +128 -37
  12. data/examples/README.md +34 -12
  13. data/examples/aaws.rb +7 -3
  14. data/examples/body_stream.rb +14 -0
  15. data/examples/crack.rb +1 -1
  16. data/examples/custom_parsers.rb +5 -1
  17. data/examples/delicious.rb +4 -4
  18. data/examples/headers_and_user_agents.rb +7 -3
  19. data/examples/idn.rb +10 -0
  20. data/examples/logging.rb +4 -4
  21. data/examples/microsoft_graph.rb +52 -0
  22. data/examples/multipart.rb +22 -0
  23. data/examples/peer_cert.rb +9 -0
  24. data/examples/stackexchange.rb +1 -1
  25. data/examples/stream_download.rb +26 -0
  26. data/examples/tripit_sign_in.rb +1 -1
  27. data/examples/twitter.rb +2 -2
  28. data/examples/whoismyrep.rb +1 -1
  29. data/httparty.gemspec +7 -4
  30. data/lib/httparty/connection_adapter.rb +73 -16
  31. data/lib/httparty/cookie_hash.rb +10 -8
  32. data/lib/httparty/decompressor.rb +102 -0
  33. data/lib/httparty/exceptions.rb +4 -1
  34. data/lib/httparty/hash_conversions.rb +30 -12
  35. data/lib/httparty/headers_processor.rb +32 -0
  36. data/lib/httparty/logger/apache_formatter.rb +31 -6
  37. data/lib/httparty/logger/curl_formatter.rb +9 -7
  38. data/lib/httparty/logger/logger.rb +5 -1
  39. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  40. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  41. data/lib/httparty/net_digest_auth.rb +19 -19
  42. data/lib/httparty/parser.rb +25 -14
  43. data/lib/httparty/request/body.rb +105 -0
  44. data/lib/httparty/request/multipart_boundary.rb +13 -0
  45. data/lib/httparty/request.rb +141 -110
  46. data/lib/httparty/response/headers.rb +23 -19
  47. data/lib/httparty/response.rb +81 -22
  48. data/lib/httparty/response_fragment.rb +21 -0
  49. data/lib/httparty/text_encoder.rb +72 -0
  50. data/lib/httparty/utils.rb +13 -0
  51. data/lib/httparty/version.rb +3 -1
  52. data/lib/httparty.rb +79 -31
  53. data/website/css/common.css +1 -1
  54. metadata +39 -106
  55. data/.simplecov +0 -1
  56. data/.travis.yml +0 -9
  57. data/features/basic_authentication.feature +0 -20
  58. data/features/command_line.feature +0 -95
  59. data/features/deals_with_http_error_codes.feature +0 -26
  60. data/features/digest_authentication.feature +0 -30
  61. data/features/handles_compressed_responses.feature +0 -27
  62. data/features/handles_multiple_formats.feature +0 -57
  63. data/features/steps/env.rb +0 -27
  64. data/features/steps/httparty_response_steps.rb +0 -56
  65. data/features/steps/httparty_steps.rb +0 -43
  66. data/features/steps/mongrel_helper.rb +0 -127
  67. data/features/steps/remote_service_steps.rb +0 -92
  68. data/features/supports_read_timeout_option.feature +0 -13
  69. data/features/supports_redirection.feature +0 -22
  70. data/features/supports_timeout_option.feature +0 -13
  71. data/spec/fixtures/delicious.xml +0 -23
  72. data/spec/fixtures/empty.xml +0 -0
  73. data/spec/fixtures/google.html +0 -3
  74. data/spec/fixtures/ssl/generate.sh +0 -29
  75. data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
  76. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  77. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  78. data/spec/fixtures/ssl/generated/ca.key +0 -15
  79. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  80. data/spec/fixtures/ssl/generated/server.crt +0 -13
  81. data/spec/fixtures/ssl/generated/server.key +0 -15
  82. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  83. data/spec/fixtures/twitter.csv +0 -2
  84. data/spec/fixtures/twitter.json +0 -1
  85. data/spec/fixtures/twitter.xml +0 -403
  86. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  87. data/spec/httparty/connection_adapter_spec.rb +0 -495
  88. data/spec/httparty/cookie_hash_spec.rb +0 -100
  89. data/spec/httparty/exception_spec.rb +0 -45
  90. data/spec/httparty/hash_conversions_spec.rb +0 -49
  91. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  92. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  93. data/spec/httparty/logger/logger_spec.rb +0 -38
  94. data/spec/httparty/net_digest_auth_spec.rb +0 -240
  95. data/spec/httparty/parser_spec.rb +0 -173
  96. data/spec/httparty/request_spec.rb +0 -1183
  97. data/spec/httparty/response_spec.rb +0 -291
  98. data/spec/httparty/ssl_spec.rb +0 -74
  99. data/spec/httparty_spec.rb +0 -872
  100. data/spec/spec_helper.rb +0 -59
  101. data/spec/support/ssl_test_helper.rb +0 -47
  102. data/spec/support/ssl_test_server.rb +0 -80
  103. 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