httparty 0.16.4 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/.rubocop_todo.yml +1 -1
  4. data/Changelog.md +55 -0
  5. data/Gemfile +5 -0
  6. data/README.md +4 -4
  7. data/docs/README.md +70 -5
  8. data/examples/README.md +6 -0
  9. data/examples/aaws.rb +6 -2
  10. data/examples/idn.rb +10 -0
  11. data/examples/peer_cert.rb +9 -0
  12. data/httparty.gemspec +1 -2
  13. data/lib/httparty/connection_adapter.rb +41 -10
  14. data/lib/httparty/cookie_hash.rb +10 -8
  15. data/lib/httparty/decompressor.rb +92 -0
  16. data/lib/httparty/exceptions.rb +3 -1
  17. data/lib/httparty/hash_conversions.rb +4 -2
  18. data/lib/httparty/headers_processor.rb +32 -0
  19. data/lib/httparty/logger/apache_formatter.rb +4 -2
  20. data/lib/httparty/logger/curl_formatter.rb +6 -4
  21. data/lib/httparty/logger/logger.rb +2 -0
  22. data/lib/httparty/logger/logstash_formatter.rb +4 -2
  23. data/lib/httparty/module_inheritable_attributes.rb +3 -1
  24. data/lib/httparty/net_digest_auth.rb +9 -10
  25. data/lib/httparty/parser.rb +9 -5
  26. data/lib/httparty/request/body.rb +24 -10
  27. data/lib/httparty/request/multipart_boundary.rb +2 -0
  28. data/lib/httparty/request.rb +67 -96
  29. data/lib/httparty/response/headers.rb +2 -0
  30. data/lib/httparty/response.rb +24 -4
  31. data/lib/httparty/{fragment_with_response.rb → response_fragment.rb} +6 -5
  32. data/lib/httparty/text_encoder.rb +72 -0
  33. data/lib/httparty/utils.rb +2 -0
  34. data/lib/httparty/version.rb +3 -1
  35. data/lib/httparty.rb +58 -35
  36. metadata +12 -108
  37. data/.travis.yml +0 -11
  38. data/features/basic_authentication.feature +0 -20
  39. data/features/command_line.feature +0 -95
  40. data/features/deals_with_http_error_codes.feature +0 -26
  41. data/features/digest_authentication.feature +0 -30
  42. data/features/handles_compressed_responses.feature +0 -27
  43. data/features/handles_multiple_formats.feature +0 -57
  44. data/features/steps/env.rb +0 -27
  45. data/features/steps/httparty_response_steps.rb +0 -56
  46. data/features/steps/httparty_steps.rb +0 -43
  47. data/features/steps/mongrel_helper.rb +0 -127
  48. data/features/steps/remote_service_steps.rb +0 -92
  49. data/features/supports_read_timeout_option.feature +0 -13
  50. data/features/supports_redirection.feature +0 -22
  51. data/features/supports_timeout_option.feature +0 -13
  52. data/spec/fixtures/delicious.xml +0 -23
  53. data/spec/fixtures/empty.xml +0 -0
  54. data/spec/fixtures/example.html +0 -10
  55. data/spec/fixtures/ssl/generate.sh +0 -29
  56. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  57. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  58. data/spec/fixtures/ssl/generated/ca.key +0 -15
  59. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  60. data/spec/fixtures/ssl/generated/server.crt +0 -13
  61. data/spec/fixtures/ssl/generated/server.key +0 -15
  62. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  63. data/spec/fixtures/tiny.gif +0 -0
  64. data/spec/fixtures/twitter.csv +0 -2
  65. data/spec/fixtures/twitter.json +0 -1
  66. data/spec/fixtures/twitter.xml +0 -403
  67. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  68. data/spec/httparty/connection_adapter_spec.rb +0 -502
  69. data/spec/httparty/cookie_hash_spec.rb +0 -100
  70. data/spec/httparty/exception_spec.rb +0 -45
  71. data/spec/httparty/fragment_with_response_spec.rb +0 -14
  72. data/spec/httparty/hash_conversions_spec.rb +0 -58
  73. data/spec/httparty/logger/apache_formatter_spec.rb +0 -40
  74. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  75. data/spec/httparty/logger/logger_spec.rb +0 -43
  76. data/spec/httparty/logger/logstash_formatter_spec.rb +0 -44
  77. data/spec/httparty/net_digest_auth_spec.rb +0 -270
  78. data/spec/httparty/parser_spec.rb +0 -190
  79. data/spec/httparty/request/body_spec.rb +0 -165
  80. data/spec/httparty/request_spec.rb +0 -1367
  81. data/spec/httparty/response_spec.rb +0 -368
  82. data/spec/httparty/ssl_spec.rb +0 -74
  83. data/spec/httparty_spec.rb +0 -923
  84. data/spec/spec_helper.rb +0 -56
  85. data/spec/support/ssl_test_helper.rb +0 -47
  86. data/spec/support/ssl_test_server.rb +0 -80
  87. data/spec/support/stub_response.rb +0 -49
@@ -1,1367 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe HTTParty::Request do
4
- before do
5
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', format: :xml)
6
- end
7
-
8
- describe "::NON_RAILS_QUERY_STRING_NORMALIZER" do
9
- let(:normalizer) { HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER }
10
-
11
- it "doesn't modify strings" do
12
- query_string = normalizer["foo=bar&foo=baz"]
13
- expect(CGI.unescape(query_string)).to eq("foo=bar&foo=baz")
14
- end
15
-
16
- context "when the query is an array" do
17
- it "doesn't include brackets" do
18
- query_string = normalizer[{page: 1, foo: %w(bar baz)}]
19
- expect(CGI.unescape(query_string)).to eq("foo=bar&foo=baz&page=1")
20
- end
21
-
22
- it "URI encodes array values" do
23
- query_string = normalizer[{people: ["Otis Redding", "Bob Marley", "Tim & Jon"], page: 1, xyzzy: 3}]
24
- expect(query_string).to eq("page=1&people=Otis%20Redding&people=Bob%20Marley&people=Tim%20%26%20Jon&xyzzy=3")
25
- end
26
- end
27
-
28
- context "when the query is a hash" do
29
- it "correctly handles nil values" do
30
- query_string = normalizer[{page: 1, per_page: nil}]
31
- expect(query_string).to eq("page=1&per_page")
32
- end
33
- end
34
- end
35
-
36
- describe "::JSON_API_QUERY_STRING_NORMALIZER" do
37
- let(:normalizer) { HTTParty::Request::JSON_API_QUERY_STRING_NORMALIZER }
38
-
39
- it "doesn't modify strings" do
40
- query_string = normalizer["foo=bar&foo=baz"]
41
- expect(CGI.unescape(query_string)).to eq("foo=bar&foo=baz")
42
- end
43
-
44
- context "when the query is an array" do
45
- it "doesn't include brackets" do
46
- query_string = normalizer[{page: 1, foo: %w(bar baz)}]
47
- expect(CGI.unescape(query_string)).to eq("foo=bar,baz&page=1")
48
- end
49
-
50
- it "URI encodes array values" do
51
- query_string = normalizer[{people: ["Otis Redding", "Bob Marley", "Tim & Jon"], page: 1, xyzzy: 3}]
52
- expect(query_string).to eq("page=1&people=Otis%20Redding,Bob%20Marley,Tim%20%26%20Jon&xyzzy=3")
53
- end
54
- end
55
-
56
- context "when the query is a hash" do
57
- it "correctly handles nil values" do
58
- query_string = normalizer[{page: 1, per_page: nil}]
59
- expect(query_string).to eq('page=1&per_page')
60
- end
61
- end
62
- end
63
-
64
- describe "initialization" do
65
- it "sets parser to HTTParty::Parser" do
66
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
67
- expect(request.parser).to eq(HTTParty::Parser)
68
- end
69
-
70
- it "sets parser to the optional parser" do
71
- my_parser = lambda {}
72
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', parser: my_parser)
73
- expect(request.parser).to eq(my_parser)
74
- end
75
-
76
- it "sets connection_adapter to HTTParty::ConnectionAdapter" do
77
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
78
- expect(request.connection_adapter).to eq(HTTParty::ConnectionAdapter)
79
- end
80
-
81
- it "sets connection_adapter to the optional connection_adapter" do
82
- my_adapter = lambda {}
83
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', connection_adapter: my_adapter)
84
- expect(request.connection_adapter).to eq(my_adapter)
85
- end
86
-
87
- context "when using a query string" do
88
- context "and it has an empty array" do
89
- it "sets correct query string" do
90
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', query: { fake_array: [] })
91
-
92
- expect(request.uri).to eq(URI.parse("http://google.com/?fake_array[]="))
93
- end
94
- end
95
-
96
- context "when sending an array with only one element" do
97
- it "sets correct query" do
98
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', query: { fake_array: [1] })
99
-
100
- expect(request.uri).to eq(URI.parse("http://google.com/?fake_array[]=1"))
101
- end
102
- end
103
- end
104
-
105
- context "when basic authentication credentials provided in uri" do
106
- context "when basic auth options wasn't set explicitly" do
107
- it "sets basic auth from uri" do
108
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://user1:pass1@example.com')
109
- expect(request.options[:basic_auth]).to eq({username: 'user1', password: 'pass1'})
110
- end
111
- end
112
-
113
- context "when basic auth options was set explicitly" do
114
- it "uses basic auth from url anyway" do
115
- basic_auth = {username: 'user2', password: 'pass2'}
116
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://user1:pass1@example.com', basic_auth: basic_auth)
117
- expect(request.options[:basic_auth]).to eq({username: 'user1', password: 'pass1'})
118
- end
119
- end
120
- end
121
- end
122
-
123
- describe "#format" do
124
- context "request yet to be made" do
125
- it "returns format option" do
126
- request = HTTParty::Request.new 'get', '/', format: :xml
127
- expect(request.format).to eq(:xml)
128
- end
129
-
130
- it "returns nil format" do
131
- request = HTTParty::Request.new 'get', '/'
132
- expect(request.format).to be_nil
133
- end
134
- end
135
-
136
- context "request has been made" do
137
- it "returns format option" do
138
- request = HTTParty::Request.new 'get', '/', format: :xml
139
- request.last_response = double
140
- expect(request.format).to eq(:xml)
141
- end
142
-
143
- it "returns the content-type from the last response when the option is not set" do
144
- request = HTTParty::Request.new 'get', '/'
145
- response = double
146
- expect(response).to receive(:[]).with('content-type').and_return('text/json')
147
- request.last_response = response
148
- expect(request.format).to eq(:json)
149
- end
150
- end
151
- end
152
-
153
- context "options" do
154
- it "should use basic auth when configured" do
155
- @request.options[:basic_auth] = {username: 'foobar', password: 'secret'}
156
- @request.send(:setup_raw_request)
157
- expect(@request.instance_variable_get(:@raw_request)['authorization']).not_to be_nil
158
- end
159
-
160
- context 'digest_auth' do
161
- before do
162
- response_sequence = [
163
- {
164
- status: ['401', 'Unauthorized' ], headers: {
165
- www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false',
166
- set_cookie: 'custom-cookie=1234567'
167
- }
168
- },
169
- { status: ['200', 'OK'] }
170
- ]
171
- stub_request(:get, 'http://api.foo.com/v1').to_return(response_sequence)
172
- end
173
-
174
- it 'should not send credentials more than once' do
175
- response_sequence = [
176
- {
177
- status: ['401', 'Unauthorized' ], headers: {
178
- www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false',
179
- set_cookie: 'custom-cookie=1234567'
180
- }
181
- },
182
- {
183
- status: ['401', 'Unauthorized' ], headers: {
184
- www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false',
185
- set_cookie: 'custom-cookie=1234567'
186
- }
187
- },
188
- { status: ['404', 'Not found'] }
189
- ]
190
- stub_request(:get, 'http://api.foo.com/v1').to_return(response_sequence)
191
-
192
- @request.options[:digest_auth] = {username: 'foobar', password: 'secret'}
193
- response = @request.perform { |v| }
194
- expect(response.code).to eq(401)
195
-
196
- raw_request = @request.instance_variable_get(:@raw_request)
197
- expect(raw_request['Authorization']).not_to be_nil
198
- end
199
-
200
- it 'should not be used when configured and the response is 200' do
201
- stub_request(:get, 'http://api.foo.com/v1').to_return(status: 200)
202
- @request.options[:digest_auth] = {username: 'foobar', password: 'secret'}
203
- response = @request.perform { |v| }
204
- expect(response.code).to eq(200)
205
-
206
-
207
- raw_request = @request.instance_variable_get(:@raw_request)
208
- expect(raw_request['Authorization']).to be_nil
209
- end
210
-
211
- it "should be used when configured and the response is 401" do
212
- @request.options[:digest_auth] = {username: 'foobar', password: 'secret'}
213
- response = @request.perform { |v| }
214
- expect(response.code).to eq(200)
215
-
216
- raw_request = @request.instance_variable_get(:@raw_request)
217
- expect(raw_request['Authorization']).not_to be_nil
218
- end
219
-
220
- it 'should maintain cookies returned from a 401 response' do
221
- @request.options[:digest_auth] = {username: 'foobar', password: 'secret'}
222
- response = @request.perform {|v|}
223
- expect(response.code).to eq(200)
224
-
225
- raw_request = @request.instance_variable_get(:@raw_request)
226
- expect(raw_request.get_fields('cookie')).to eql ["custom-cookie=1234567"]
227
- end
228
-
229
- it 'should merge cookies from request and a 401 response' do
230
-
231
- @request.options[:digest_auth] = {username: 'foobar', password: 'secret'}
232
- @request.options[:headers] = {'cookie' => 'request-cookie=test'}
233
- response = @request.perform {|v|}
234
- expect(response.code).to eq(200)
235
-
236
- raw_request = @request.instance_variable_get(:@raw_request)
237
- expect(raw_request.get_fields('cookie')).to eql ['request-cookie=test', 'custom-cookie=1234567']
238
- end
239
- end
240
-
241
- it 'should use body_stream when configured' do
242
- stream = StringIO.new('foo')
243
- request = HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', body_stream: stream)
244
- request.send(:setup_raw_request)
245
- expect(request.instance_variable_get(:@raw_request).body_stream).to eq(stream)
246
- end
247
-
248
- it 'should normalize base uri when specified as request option' do
249
- stub_request(:get, 'http://foo.com/resource').to_return(body: 'Bar')
250
- response = HTTParty.get('/resource', {
251
- base_uri: 'foo.com'
252
- })
253
- expect(response.code).to eq(200)
254
- end
255
- end
256
-
257
- describe "#uri" do
258
- context "redirects" do
259
- it "returns correct path when the server sets the location header to a filename" do
260
- @request.last_uri = URI.parse("http://example.com/foo/bar")
261
- @request.path = URI.parse("bar?foo=bar")
262
- @request.redirect = true
263
-
264
- expect(@request.uri).to eq(URI.parse("http://example.com/foo/bar?foo=bar"))
265
- end
266
-
267
- context "location header is an absolute path" do
268
- it "returns correct path when location has leading slash" do
269
- @request.last_uri = URI.parse("http://example.com/foo/bar")
270
- @request.path = URI.parse("/bar?foo=bar")
271
- @request.redirect = true
272
-
273
- expect(@request.uri).to eq(URI.parse("http://example.com/bar?foo=bar"))
274
- end
275
-
276
- it "returns the correct path when location has no leading slash" do
277
- @request.last_uri = URI.parse("http://example.com")
278
- @request.path = URI.parse("bar/")
279
- @request.redirect = true
280
-
281
- expect(@request.uri).to eq(URI.parse("http://example.com/bar/"))
282
- end
283
- end
284
- it "returns correct path when the server sets the location header to a full uri" do
285
- @request.last_uri = URI.parse("http://example.com/foo/bar")
286
- @request.path = URI.parse("http://example.com/bar?foo=bar")
287
- @request.redirect = true
288
-
289
- expect(@request.uri).to eq(URI.parse("http://example.com/bar?foo=bar"))
290
- end
291
-
292
- it "returns correct path when the server sets the location header to a network-path reference" do
293
- @request.last_uri = URI.parse("https://example.com")
294
- @request.path = URI.parse("//www.example.com")
295
- @request.redirect = true
296
-
297
- expect(@request.uri).to eq(URI.parse("https://www.example.com"))
298
- end
299
- end
300
-
301
- context "query strings" do
302
- it "does not add an empty query string when default_params are blank" do
303
- @request.options[:default_params] = {}
304
- expect(@request.uri.query).to be_nil
305
- end
306
-
307
- it "respects the query string normalization proc" do
308
- empty_proc = lambda {|qs| "I"}
309
- @request.options[:query_string_normalizer] = empty_proc
310
- @request.options[:query] = {foo: :bar}
311
- expect(CGI.unescape(@request.uri.query)).to eq("I")
312
- end
313
-
314
- it "does not append an ampersand when queries are embedded in paths" do
315
- @request.path = "/path?a=1"
316
- @request.options[:query] = {}
317
- expect(@request.uri.query).to eq("a=1")
318
- end
319
-
320
- it "does not duplicate query string parameters when uri is called twice" do
321
- @request.options[:query] = {foo: :bar}
322
- @request.uri
323
- expect(@request.uri.query).to eq("foo=bar")
324
- end
325
-
326
- context "when representing an array" do
327
- it "returns a Rails style query string" do
328
- @request.options[:query] = {foo: %w(bar baz)}
329
- expect(CGI.unescape(@request.uri.query)).to eq("foo[]=bar&foo[]=baz")
330
- end
331
- end
332
- end
333
- end
334
-
335
- describe "#setup_raw_request" do
336
- context "when query_string_normalizer is set" do
337
- it "sets the body to the return value of the proc" do
338
- @request.options[:query_string_normalizer] = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER
339
- @request.options[:body] = {page: 1, foo: %w(bar baz)}
340
- @request.send(:setup_raw_request)
341
- body = @request.instance_variable_get(:@raw_request).body
342
- expect(CGI.unescape(body)).to eq("foo=bar&foo=baz&page=1")
343
- end
344
- end
345
-
346
- context "when mulipart" do
347
- subject(:headers) do
348
- @request.send(:setup_raw_request)
349
- headers = @request.instance_variable_get(:@raw_request).each_header.to_a
350
- Hash[*headers.flatten] # Ruby 2.0 doesn't have Array#to_h
351
- end
352
-
353
- context "when body contains file" do
354
- it "sets header Content-Type: multipart/form-data; boundary=" do
355
- @request.options[:body] = {file: File.open(File::NULL, 'r')}
356
-
357
- expect(headers['content-type']).to match(%r{^multipart/form-data; boundary=---})
358
- end
359
-
360
- context "and header Content-Type is provided" do
361
- it "overwrites the header to: multipart/form-data; boundary=" do
362
- @request.options[:body] = {file: File.open(File::NULL, 'r')}
363
- @request.options[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
364
-
365
- expect(headers['content-type']).to match(%r{^multipart/form-data; boundary=---})
366
- end
367
- end
368
- end
369
-
370
- context 'when mulipart option is provided' do
371
- it "sets header Content-Type: multipart/form-data; boundary=" do
372
- @request.options[:body] = { text: 'something' }
373
- @request.options[:multipart] = true
374
-
375
- expect(headers['content-type']).to match(%r{^multipart/form-data; boundary=---})
376
- end
377
- end
378
- end
379
- end
380
-
381
- describe 'http' do
382
- it "should get a connection from the connection_adapter" do
383
- http = Net::HTTP.new('google.com')
384
- adapter = double('adapter')
385
- request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', connection_adapter: adapter)
386
- expect(adapter).to receive(:call).with(request.uri, request.options).and_return(http)
387
- expect(request.send(:http)).to be http
388
- end
389
- end
390
-
391
- describe '#format_from_mimetype' do
392
- it 'should handle text/xml' do
393
- ["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
394
- expect(@request.send(:format_from_mimetype, ct)).to eq(:xml)
395
- end
396
- end
397
-
398
- it 'should handle application/xml' do
399
- ["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
400
- expect(@request.send(:format_from_mimetype, ct)).to eq(:xml)
401
- end
402
- end
403
-
404
- it 'should handle text/json' do
405
- ["text/json", "text/json; charset=iso8859-1"].each do |ct|
406
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
407
- end
408
- end
409
-
410
- it 'should handle application/vnd.api+json' do
411
- ["application/vnd.api+json", "application/vnd.api+json; charset=iso8859-1"].each do |ct|
412
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
413
- end
414
- end
415
-
416
- it 'should handle application/hal+json' do
417
- ["application/hal+json", "application/hal+json; charset=iso8859-1"].each do |ct|
418
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
419
- end
420
- end
421
-
422
- it 'should handle application/json' do
423
- ["application/json", "application/json; charset=iso8859-1"].each do |ct|
424
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
425
- end
426
- end
427
-
428
- it 'should handle text/csv' do
429
- ["text/csv", "text/csv; charset=iso8859-1"].each do |ct|
430
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
431
- end
432
- end
433
-
434
- it 'should handle application/csv' do
435
- ["application/csv", "application/csv; charset=iso8859-1"].each do |ct|
436
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
437
- end
438
- end
439
-
440
- it 'should handle text/comma-separated-values' do
441
- ["text/comma-separated-values", "text/comma-separated-values; charset=iso8859-1"].each do |ct|
442
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
443
- end
444
- end
445
-
446
- it 'should handle text/javascript' do
447
- ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
448
- expect(@request.send(:format_from_mimetype, ct)).to eq(:plain)
449
- end
450
- end
451
-
452
- it 'should handle application/javascript' do
453
- ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
454
- expect(@request.send(:format_from_mimetype, ct)).to eq(:plain)
455
- end
456
- end
457
-
458
- it "returns nil for an unrecognized mimetype" do
459
- expect(@request.send(:format_from_mimetype, "application/atom+xml")).to be_nil
460
- end
461
-
462
- it "returns nil when using a default parser" do
463
- @request.options[:parser] = lambda {}
464
- expect(@request.send(:format_from_mimetype, "text/json")).to be_nil
465
- end
466
- end
467
-
468
- describe 'parsing responses' do
469
- it 'should handle xml automatically' do
470
- xml = '<books><book><id>1234</id><name>Foo Bar!</name></book></books>'
471
- @request.options[:format] = :xml
472
- expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
473
- end
474
-
475
- it 'should handle utf-8 bom in xml' do
476
- xml = "\xEF\xBB\xBF<books><book><id>1234</id><name>Foo Bar!</name></book></books>"
477
- @request.options[:format] = :xml
478
- expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
479
- end
480
-
481
- it 'should handle csv automatically' do
482
- csv = ['"id","Name"', '"1234","Foo Bar!"'].join("\n")
483
- @request.options[:format] = :csv
484
- expect(@request.send(:parse_response, csv)).to eq([%w(id Name), ["1234", "Foo Bar!"]])
485
- end
486
-
487
- it 'should handle json automatically' do
488
- json = '{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}'
489
- @request.options[:format] = :json
490
- expect(@request.send(:parse_response, json)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
491
- end
492
-
493
- it 'should handle utf-8 bom in json' do
494
- json = "\xEF\xBB\xBF{\"books\": {\"book\": {\"name\": \"Foo Bar!\", \"id\": \"1234\"}}}"
495
- @request.options[:format] = :json
496
- expect(@request.send(:parse_response, json)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
497
- end
498
-
499
- it "should include any HTTP headers in the returned response" do
500
- @request.options[:format] = :html
501
- response = stub_response "Content"
502
- response.initialize_http_header("key" => "value")
503
-
504
- expect(@request.perform.headers).to eq({ "key" => ["value"] })
505
- end
506
-
507
- if "".respond_to?(:encoding)
508
-
509
- let(:response_charset) {
510
- @request.send(:get_charset)
511
- }
512
-
513
- it "should process charset in content type properly" do
514
- response = stub_response "Content".force_encoding('ascii-8bit')
515
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-8")
516
- resp = @request.perform
517
- expect(response_charset).to_not be_empty
518
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
519
- end
520
-
521
- it "should process charset in content type properly if it has a different case" do
522
- response = stub_response "Content".force_encoding('ascii-8bit')
523
- response.initialize_http_header("Content-Type" => "text/plain;CHARSET = utf-8")
524
- resp = @request.perform
525
- expect(response_charset).to_not be_empty
526
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
527
- end
528
-
529
- it "should process quoted charset in content type properly" do
530
- response = stub_response "Content".force_encoding('ascii-8bit')
531
- response.initialize_http_header("Content-Type" => "text/plain;charset = \"utf-8\"")
532
- resp = @request.perform
533
- expect(response_charset).to_not be_empty
534
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
535
- end
536
-
537
- it "should process response with a nil body" do
538
- response = stub_response nil
539
- response.initialize_http_header("Content-Type" => "text/html;charset=UTF-8")
540
- resp = @request.perform
541
- expect(resp.body).to be_nil
542
- end
543
-
544
- it "should process utf-16 charset with little endian bom correctly" do
545
- @request.options[:assume_utf16_is_big_endian] = true
546
-
547
- response = stub_response "\xFF\xFEC\x00o\x00n\x00t\x00e\x00n\x00t\x00"
548
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
549
- resp = @request.perform
550
- expect(response_charset).to_not be_empty
551
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16LE"))
552
- end
553
-
554
- it "should process utf-16 charset with big endian bom correctly" do
555
- @request.options[:assume_utf16_is_big_endian] = false
556
-
557
- response = stub_response "\xFE\xFF\x00C\x00o\x00n\x00t\x00e\x00n\x00t"
558
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
559
- resp = @request.perform
560
- expect(response_charset).to_not be_empty
561
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16BE"))
562
- end
563
-
564
- it "should assume utf-16 little endian if options has been chosen" do
565
- @request.options[:assume_utf16_is_big_endian] = false
566
-
567
- response = stub_response "C\x00o\x00n\x00t\x00e\x00n\x00t\x00"
568
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
569
- resp = @request.perform
570
- expect(response_charset).to_not be_empty
571
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16LE"))
572
- end
573
-
574
- it "should perform no encoding if the charset is not available" do
575
- response = stub_response "Content"
576
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-lols")
577
- resp = @request.perform
578
- expect(response_charset).to_not be_empty
579
- # This encoding does not exist, thus the string should not be encodd with it
580
- expect(resp.body.encoding).to_not eq(response_charset)
581
- expect(resp.body).to eq("Content")
582
- expect(resp.body.encoding).to eq("Content".encoding)
583
- end
584
-
585
- it "should perform no encoding if the content type is specified but no charset is specified" do
586
- response = stub_response "Content"
587
- response.initialize_http_header("Content-Type" => "text/plain")
588
- resp = @request.perform
589
- expect(response_charset).to be_nil
590
- expect(resp.body).to eq("Content")
591
- expect(resp.body.encoding).to eq("Content".encoding)
592
- end
593
- end
594
-
595
- describe 'with non-200 responses' do
596
- context "3xx responses" do
597
- it 'returns a valid object for 304 not modified' do
598
- stub_response '', 304
599
- resp = @request.perform
600
- expect(resp.code).to eq(304)
601
- expect(resp.body).to eq('')
602
- expect(resp).to be_nil
603
- end
604
-
605
- it "redirects if a 300 contains a location header" do
606
- redirect = stub_response '', 300
607
- redirect['location'] = 'http://foo.com/foo'
608
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
609
- allow(@http).to receive(:request).and_return(redirect, ok)
610
- response = @request.perform
611
- expect(response.request.base_uri.to_s).to eq("http://foo.com")
612
- expect(response.request.path.to_s).to eq("http://foo.com/foo")
613
- expect(response.request.uri.request_uri).to eq("/foo")
614
- expect(response.request.uri.to_s).to eq("http://foo.com/foo")
615
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
616
- end
617
-
618
- it "calls block given to perform with each redirect" do
619
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
620
- stub_request(:get, 'http://test.com/redirect')
621
- .to_return(
622
- status: [300, 'REDIRECT'],
623
- headers: { location: 'http://api.foo.com/v2' }
624
- )
625
- stub_request(:get, 'http://api.foo.com/v2')
626
- .to_return(body: '<hash><foo>bar</foo></hash>')
627
- body = ""
628
- @request.perform { |chunk| body += chunk }
629
- expect(body.length).to eq(27)
630
- end
631
-
632
- it "redirects if a 300 contains a relative location header" do
633
- redirect = stub_response '', 300
634
- redirect['location'] = '/foo/bar'
635
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
636
- allow(@http).to receive(:request).and_return(redirect, ok)
637
- response = @request.perform
638
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
639
- expect(response.request.path.to_s).to eq("/foo/bar")
640
- expect(response.request.uri.request_uri).to eq("/foo/bar")
641
- expect(response.request.uri.to_s).to eq("http://api.foo.com/foo/bar")
642
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
643
- end
644
-
645
- it "handles multiple redirects and relative location headers on different hosts" do
646
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
647
- stub_request(:get, 'http://test.com/redirect')
648
- .to_return(
649
- status: [300, 'REDIRECT'],
650
- headers: { location: "http://api.foo.com/v2" }
651
- )
652
- stub_request(:get, 'http://api.foo.com/v2')
653
- .to_return(
654
- status: [300, 'REDIRECT'],
655
- headers: { location: '/v3' }
656
- )
657
- stub_request(:get, 'http://api.foo.com/v3')
658
- .to_return(body: '<hash><foo>bar</foo></hash>')
659
- response = @request.perform
660
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
661
- expect(response.request.path.to_s).to eq("/v3")
662
- expect(response.request.uri.request_uri).to eq("/v3")
663
- expect(response.request.uri.to_s).to eq("http://api.foo.com/v3")
664
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
665
- end
666
-
667
- it "raises an error if redirect has duplicate location header" do
668
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
669
- stub_request(:get, 'http://test.com/redirect')
670
- .to_return(
671
- status: [300, 'REDIRECT'],
672
- headers: {
673
- location: ['http://api.foo.com/v2', 'http://api.foo.com/v2']
674
- }
675
- )
676
- expect {@request.perform}.to raise_error(HTTParty::DuplicateLocationHeader)
677
- end
678
-
679
- it "returns the HTTParty::Response when the 300 does not contain a location header" do
680
- stub_response '', 300
681
- expect(HTTParty::Response).to be === @request.perform
682
- end
683
-
684
- it "redirects including port" do
685
- stub_request(:get, 'http://withport.com:3000/v1')
686
- .to_return(
687
- status: [301, 'Moved Permanently'],
688
- headers: { location: 'http://withport.com:3000/v2' }
689
- )
690
- stub_request(:get, 'http://withport.com:3000/v2')
691
- .to_return(status: 200)
692
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://withport.com:3000/v1')
693
- response = request.perform
694
- expect(response.request.base_uri.to_s).to eq("http://withport.com:3000")
695
- end
696
- end
697
-
698
- it 'should return a valid object for 4xx response' do
699
- stub_response '<foo><bar>yes</bar></foo>', 401
700
- resp = @request.perform
701
- expect(resp.code).to eq(401)
702
- expect(resp.body).to eq("<foo><bar>yes</bar></foo>")
703
- expect(resp['foo']['bar']).to eq("yes")
704
- end
705
-
706
- it 'should return a valid object for 5xx response' do
707
- stub_response '<foo><bar>error</bar></foo>', 500
708
- resp = @request.perform
709
- expect(resp.code).to eq(500)
710
- expect(resp.body).to eq("<foo><bar>error</bar></foo>")
711
- expect(resp['foo']['bar']).to eq("error")
712
- end
713
-
714
- it "parses response lazily so codes can be checked prior" do
715
- stub_response 'not xml', 500
716
- @request.options[:format] = :xml
717
- expect {
718
- response = @request.perform
719
- expect(response.code).to eq(500)
720
- expect(response.body).to eq('not xml')
721
- }.not_to raise_error
722
- end
723
- end
724
- end
725
-
726
- it "should not attempt to parse empty responses" do
727
- [204, 304].each do |code|
728
- stub_response "", code
729
-
730
- @request.options[:format] = :xml
731
- expect(@request.perform).to be_nil
732
- end
733
- end
734
-
735
- it "should not fail for missing mime type" do
736
- stub_response "Content for you"
737
- @request.options[:format] = :html
738
- expect(@request.perform.parsed_response).to eq('Content for you')
739
- end
740
-
741
- [300, 301, 302, 305].each do |code|
742
- describe "a request that #{code} redirects" do
743
- before(:each) do
744
- @redirect = stub_response("", code)
745
- @redirect['location'] = '/foo'
746
-
747
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
748
- end
749
-
750
- describe "once" do
751
- before(:each) do
752
- allow(@http).to receive(:request).and_return(@redirect, @ok)
753
- end
754
-
755
- it "should be handled by GET transparently" do
756
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
757
- end
758
-
759
- it "should be handled by POST transparently" do
760
- @request.http_method = Net::HTTP::Post
761
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
762
- end
763
-
764
- it "should be handled by DELETE transparently" do
765
- @request.http_method = Net::HTTP::Delete
766
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
767
- end
768
-
769
- it "should be handled by MOVE transparently" do
770
- @request.http_method = Net::HTTP::Move
771
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
772
- end
773
-
774
- it "should be handled by COPY transparently" do
775
- @request.http_method = Net::HTTP::Copy
776
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
777
- end
778
-
779
- it "should be handled by PATCH transparently" do
780
- @request.http_method = Net::HTTP::Patch
781
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
782
- end
783
-
784
- it "should be handled by PUT transparently" do
785
- @request.http_method = Net::HTTP::Put
786
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
787
- end
788
-
789
- it "should be handled by HEAD transparently" do
790
- @request.http_method = Net::HTTP::Head
791
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
792
- end
793
-
794
- it "should be handled by OPTIONS transparently" do
795
- @request.http_method = Net::HTTP::Options
796
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
797
- end
798
-
799
- it "should be handled by MKCOL transparently" do
800
- @request.http_method = Net::HTTP::Mkcol
801
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
802
- end
803
-
804
- it "should be handled by LOCK transparently" do
805
- @request.http_method = Net::HTTP::Lock
806
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
807
- end
808
-
809
- it "should be handled by UNLOCK transparently" do
810
- @request.http_method = Net::HTTP::Unlock
811
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
812
- end
813
-
814
- it "should keep track of cookies between redirects" do
815
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
816
- @request.perform
817
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
818
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
819
- end
820
-
821
- it 'should update cookies with redirects' do
822
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
823
- @redirect['Set-Cookie'] = 'foo=tar;'
824
- @request.perform
825
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
826
- end
827
-
828
- it 'should keep cookies between redirects' do
829
- @request.options[:headers] = {'Cookie' => 'keep=me'}
830
- @redirect['Set-Cookie'] = 'foo=tar;'
831
- @request.perform
832
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
833
- end
834
-
835
- it "should handle multiple Set-Cookie headers between redirects" do
836
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
837
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
838
- @request.perform
839
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
840
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
841
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
842
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
843
- end
844
-
845
- it 'should make resulting request a get request if it not already' do
846
- @request.http_method = Net::HTTP::Delete
847
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
848
- expect(@request.http_method).to eq(Net::HTTP::Get)
849
- end
850
-
851
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
852
- @request.options[:maintain_method_across_redirects] = true
853
- @request.http_method = Net::HTTP::Delete
854
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
855
- expect(@request.http_method).to eq(Net::HTTP::Delete)
856
- end
857
-
858
- it 'should log the redirection' do
859
- logger_double = double
860
- expect(logger_double).to receive(:info).twice
861
- @request.options[:logger] = logger_double
862
- @request.perform
863
- end
864
- end
865
-
866
- describe "infinitely" do
867
- before(:each) do
868
- allow(@http).to receive(:request).and_return(@redirect)
869
- end
870
-
871
- it "should raise an exception" do
872
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
873
- end
874
- end
875
- end
876
- end
877
-
878
- describe "a request that 303 redirects" do
879
- before(:each) do
880
- @redirect = stub_response("", 303)
881
- @redirect['location'] = '/foo'
882
-
883
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
884
- end
885
-
886
- describe "once" do
887
- before(:each) do
888
- allow(@http).to receive(:request).and_return(@redirect, @ok)
889
- end
890
-
891
- it "should be handled by GET transparently" do
892
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
893
- end
894
-
895
- it "should be handled by POST transparently" do
896
- @request.http_method = Net::HTTP::Post
897
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
898
- end
899
-
900
- it "should be handled by DELETE transparently" do
901
- @request.http_method = Net::HTTP::Delete
902
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
903
- end
904
-
905
- it "should be handled by MOVE transparently" do
906
- @request.http_method = Net::HTTP::Move
907
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
908
- end
909
-
910
- it "should be handled by COPY transparently" do
911
- @request.http_method = Net::HTTP::Copy
912
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
913
- end
914
-
915
- it "should be handled by PATCH transparently" do
916
- @request.http_method = Net::HTTP::Patch
917
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
918
- end
919
-
920
- it "should be handled by PUT transparently" do
921
- @request.http_method = Net::HTTP::Put
922
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
923
- end
924
-
925
- it "should be handled by HEAD transparently" do
926
- @request.http_method = Net::HTTP::Head
927
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
928
- end
929
-
930
- it "should be handled by OPTIONS transparently" do
931
- @request.http_method = Net::HTTP::Options
932
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
933
- end
934
-
935
- it "should be handled by MKCOL transparently" do
936
- @request.http_method = Net::HTTP::Mkcol
937
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
938
- end
939
-
940
- it "should be handled by LOCK transparently" do
941
- @request.http_method = Net::HTTP::Lock
942
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
943
- end
944
-
945
- it "should be handled by UNLOCK transparently" do
946
- @request.http_method = Net::HTTP::Unlock
947
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
948
- end
949
-
950
- it "should keep track of cookies between redirects" do
951
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
952
- @request.perform
953
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
954
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
955
- end
956
-
957
- it 'should update cookies with redirects' do
958
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
959
- @redirect['Set-Cookie'] = 'foo=tar;'
960
- @request.perform
961
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
962
- end
963
-
964
- it 'should keep cookies between redirects' do
965
- @request.options[:headers] = {'Cookie' => 'keep=me'}
966
- @redirect['Set-Cookie'] = 'foo=tar;'
967
- @request.perform
968
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
969
- end
970
-
971
- it "should handle multiple Set-Cookie headers between redirects" do
972
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
973
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
974
- @request.perform
975
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
976
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
977
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
978
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
979
- end
980
-
981
- it 'should make resulting request a get request if it not already' do
982
- @request.http_method = Net::HTTP::Delete
983
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
984
- expect(@request.http_method).to eq(Net::HTTP::Get)
985
- end
986
-
987
- it 'should make resulting request a get request if options[:maintain_method_across_redirects] is false' do
988
- @request.options[:maintain_method_across_redirects] = false
989
- @request.http_method = Net::HTTP::Delete
990
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
991
- expect(@request.http_method).to eq(Net::HTTP::Get)
992
- end
993
-
994
- it 'should make resulting request a get request if options[:maintain_method_across_redirects] is true but options[:resend_on_redirect] is false' do
995
- @request.options[:maintain_method_across_redirects] = true
996
- @request.options[:resend_on_redirect] = false
997
- @request.http_method = Net::HTTP::Delete
998
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
999
- expect(@request.http_method).to eq(Net::HTTP::Get)
1000
- end
1001
-
1002
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] and options[:resend_on_redirect] is true' do
1003
- @request.options[:maintain_method_across_redirects] = true
1004
- @request.options[:resend_on_redirect] = true
1005
- @request.http_method = Net::HTTP::Delete
1006
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1007
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1008
- end
1009
-
1010
- it 'should log the redirection' do
1011
- logger_double = double
1012
- expect(logger_double).to receive(:info).twice
1013
- @request.options[:logger] = logger_double
1014
- @request.perform
1015
- end
1016
- end
1017
-
1018
- describe "infinitely" do
1019
- before(:each) do
1020
- allow(@http).to receive(:request).and_return(@redirect)
1021
- end
1022
-
1023
- it "should raise an exception" do
1024
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
1025
- end
1026
- end
1027
- end
1028
-
1029
- describe "a request that returns 304" do
1030
- before(:each) do
1031
- @redirect = stub_response("", 304)
1032
- @redirect['location'] = '/foo'
1033
- end
1034
-
1035
- before(:each) do
1036
- allow(@http).to receive(:request).and_return(@redirect)
1037
- end
1038
-
1039
- it "should report 304 with a GET request" do
1040
- expect(@request.perform.code).to eq(304)
1041
- end
1042
-
1043
- it "should report 304 with a POST request" do
1044
- @request.http_method = Net::HTTP::Post
1045
- expect(@request.perform.code).to eq(304)
1046
- end
1047
-
1048
- it "should report 304 with a DELETE request" do
1049
- @request.http_method = Net::HTTP::Delete
1050
- expect(@request.perform.code).to eq(304)
1051
- end
1052
-
1053
- it "should report 304 with a MOVE request" do
1054
- @request.http_method = Net::HTTP::Move
1055
- expect(@request.perform.code).to eq(304)
1056
- end
1057
-
1058
- it "should report 304 with a COPY request" do
1059
- @request.http_method = Net::HTTP::Copy
1060
- expect(@request.perform.code).to eq(304)
1061
- end
1062
-
1063
- it "should report 304 with a PATCH request" do
1064
- @request.http_method = Net::HTTP::Patch
1065
- expect(@request.perform.code).to eq(304)
1066
- end
1067
-
1068
- it "should report 304 with a PUT request" do
1069
- @request.http_method = Net::HTTP::Put
1070
- expect(@request.perform.code).to eq(304)
1071
- end
1072
-
1073
- it "should report 304 with a HEAD request" do
1074
- @request.http_method = Net::HTTP::Head
1075
- expect(@request.perform.code).to eq(304)
1076
- end
1077
-
1078
- it "should report 304 with a OPTIONS request" do
1079
- @request.http_method = Net::HTTP::Options
1080
- expect(@request.perform.code).to eq(304)
1081
- end
1082
-
1083
- it "should report 304 with a MKCOL request" do
1084
- @request.http_method = Net::HTTP::Mkcol
1085
- expect(@request.perform.code).to eq(304)
1086
- end
1087
-
1088
- it "should be handled by LOCK transparently" do
1089
- @request.http_method = Net::HTTP::Lock
1090
- expect(@request.perform.code).to eq(304)
1091
- end
1092
-
1093
- it "should be handled by UNLOCK transparently" do
1094
- @request.http_method = Net::HTTP::Unlock
1095
- expect(@request.perform.code).to eq(304)
1096
- end
1097
-
1098
- it 'should not log the redirection' do
1099
- logger_double = double
1100
- expect(logger_double).to receive(:info).once
1101
- @request.options[:logger] = logger_double
1102
- @request.perform
1103
- end
1104
- end
1105
-
1106
- [307, 308].each do |code|
1107
- describe "a request that #{code} redirects" do
1108
- before(:each) do
1109
- @redirect = stub_response("", code)
1110
- @redirect['location'] = '/foo'
1111
-
1112
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1113
- end
1114
-
1115
- describe "once" do
1116
- before(:each) do
1117
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1118
- end
1119
-
1120
- it "should be handled by GET transparently" do
1121
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1122
- end
1123
-
1124
- it "should be handled by POST transparently" do
1125
- @request.http_method = Net::HTTP::Post
1126
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1127
- end
1128
-
1129
- it "should be handled by DELETE transparently" do
1130
- @request.http_method = Net::HTTP::Delete
1131
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1132
- end
1133
-
1134
- it "should be handled by MOVE transparently" do
1135
- @request.http_method = Net::HTTP::Move
1136
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1137
- end
1138
-
1139
- it "should be handled by COPY transparently" do
1140
- @request.http_method = Net::HTTP::Copy
1141
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1142
- end
1143
-
1144
- it "should be handled by PATCH transparently" do
1145
- @request.http_method = Net::HTTP::Patch
1146
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1147
- end
1148
-
1149
- it "should be handled by PUT transparently" do
1150
- @request.http_method = Net::HTTP::Put
1151
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1152
- end
1153
-
1154
- it "should be handled by HEAD transparently" do
1155
- @request.http_method = Net::HTTP::Head
1156
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1157
- end
1158
-
1159
- it "should be handled by OPTIONS transparently" do
1160
- @request.http_method = Net::HTTP::Options
1161
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1162
- end
1163
-
1164
- it "should be handled by MKCOL transparently" do
1165
- @request.http_method = Net::HTTP::Mkcol
1166
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1167
- end
1168
-
1169
- it "should be handled by LOCK transparently" do
1170
- @request.http_method = Net::HTTP::Lock
1171
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1172
- end
1173
-
1174
- it "should be handled by UNLOCK transparently" do
1175
- @request.http_method = Net::HTTP::Unlock
1176
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1177
- end
1178
-
1179
-
1180
-
1181
- it "should keep track of cookies between redirects" do
1182
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
1183
- @request.perform
1184
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1185
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1186
- end
1187
-
1188
- it 'should update cookies with redirects' do
1189
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
1190
- @redirect['Set-Cookie'] = 'foo=tar;'
1191
- @request.perform
1192
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
1193
- end
1194
-
1195
- it 'should keep cookies between redirects' do
1196
- @request.options[:headers] = {'Cookie' => 'keep=me'}
1197
- @redirect['Set-Cookie'] = 'foo=tar;'
1198
- @request.perform
1199
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
1200
- end
1201
-
1202
- it "should handle multiple Set-Cookie headers between redirects" do
1203
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
1204
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
1205
- @request.perform
1206
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1207
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1208
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
1209
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
1210
- end
1211
-
1212
- it 'should maintain method in resulting request' do
1213
- @request.http_method = Net::HTTP::Delete
1214
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1215
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1216
- end
1217
-
1218
- it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is false' do
1219
- @request.options[:maintain_method_across_redirects] = false
1220
- @request.http_method = Net::HTTP::Delete
1221
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1222
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1223
- end
1224
-
1225
- it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is true' do
1226
- @request.options[:maintain_method_across_redirects] = true
1227
- @request.http_method = Net::HTTP::Delete
1228
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1229
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1230
- end
1231
-
1232
- it 'should log the redirection' do
1233
- logger_double = double
1234
- expect(logger_double).to receive(:info).twice
1235
- @request.options[:logger] = logger_double
1236
- @request.perform
1237
- end
1238
- end
1239
-
1240
- describe "infinitely" do
1241
- before(:each) do
1242
- allow(@http).to receive(:request).and_return(@redirect)
1243
- end
1244
-
1245
- it "should raise an exception" do
1246
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
1247
- end
1248
- end
1249
- end
1250
- end
1251
-
1252
- describe "#send_authorization_header?" do
1253
- context "basic_auth" do
1254
- before do
1255
- @credentials = { username: "username", password: "password" }
1256
- @authorization = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
1257
- @request.options[:basic_auth] = @credentials
1258
- @redirect = stub_response("", 302)
1259
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1260
- end
1261
-
1262
- before(:each) do
1263
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1264
- end
1265
-
1266
- it "should not send Authorization header when redirecting to a different host" do
1267
- @redirect['location'] = 'http://example.com/'
1268
- @request.perform
1269
- @request.send(:setup_raw_request)
1270
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to be_nil
1271
- end
1272
-
1273
- it "should send Authorization header when redirecting to a relative path" do
1274
- @redirect['location'] = '/v3'
1275
- @request.perform
1276
- @request.send(:setup_raw_request)
1277
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1278
- end
1279
-
1280
- it "should send Authorization header when redirecting to the same host" do
1281
- @redirect['location'] = 'http://api.foo.com/v2'
1282
- @request.perform
1283
- @request.send(:setup_raw_request)
1284
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1285
- end
1286
-
1287
- it "should send Authorization header when redirecting to a different port on the same host" do
1288
- @redirect['location'] = 'http://api.foo.com:3000/v3'
1289
- @request.perform
1290
- @request.send(:setup_raw_request)
1291
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1292
- end
1293
- end
1294
- end
1295
-
1296
- context "with POST http method" do
1297
- it "should raise argument error if query is not a hash" do
1298
- expect {
1299
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', format: :xml, query: 'astring').perform
1300
- }.to raise_error(ArgumentError)
1301
- end
1302
- end
1303
-
1304
- describe "argument validation" do
1305
- it "should raise argument error if basic_auth and digest_auth are both present" do
1306
- expect {
1307
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: {}, digest_auth: {}).perform
1308
- }.to raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
1309
- end
1310
-
1311
- it "should raise argument error if basic_auth is not a hash" do
1312
- expect {
1313
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: %w(foo bar)).perform
1314
- }.to raise_error(ArgumentError, ":basic_auth must be a hash")
1315
- end
1316
-
1317
- it "should raise argument error if digest_auth is not a hash" do
1318
- expect {
1319
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', digest_auth: %w(foo bar)).perform
1320
- }.to raise_error(ArgumentError, ":digest_auth must be a hash")
1321
- end
1322
-
1323
- it "should raise argument error if headers is not a hash" do
1324
- expect {
1325
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', headers: %w(foo bar)).perform
1326
- }.to raise_error(ArgumentError, ":headers must be a hash")
1327
- end
1328
-
1329
- it "should raise argument error if options method is not http accepted method" do
1330
- expect {
1331
- HTTParty::Request.new('SuperPost', 'http://api.foo.com/v1').perform
1332
- }.to raise_error(ArgumentError, "only get, post, patch, put, delete, head, and options methods are supported")
1333
- end
1334
-
1335
- it "should raise argument error if http method is post and query is not hash" do
1336
- expect {
1337
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', query: "message: hello").perform
1338
- }.to raise_error(ArgumentError, ":query must be hash if using HTTP Post")
1339
- end
1340
-
1341
- it "should raise RedirectionTooDeep error if limit is negative" do
1342
- expect {
1343
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', limit: -1).perform
1344
- }.to raise_error(HTTParty::RedirectionTooDeep, 'HTTP redirects too deep')
1345
- end
1346
- end
1347
-
1348
- context 'with Accept-Encoding header' do
1349
- it 'should disable content decoding if present' do
1350
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'Accept-Encoding' => 'custom'})
1351
- request.send(:setup_raw_request)
1352
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1353
- end
1354
-
1355
- it 'should disable content decoding if present and lowercase' do
1356
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'accept-encoding' => 'custom'})
1357
- request.send(:setup_raw_request)
1358
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1359
- end
1360
-
1361
- it 'should disable content decoding if present' do
1362
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1')
1363
- request.send(:setup_raw_request)
1364
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(true)
1365
- end
1366
- end
1367
- end