httparty 0.16.2 → 0.20.0

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

Potentially problematic release.


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

Files changed (92) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +23 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/Changelog.md +72 -0
  7. data/Gemfile +5 -0
  8. data/README.md +5 -5
  9. data/docs/README.md +70 -5
  10. data/examples/README.md +28 -11
  11. data/examples/aaws.rb +6 -2
  12. data/examples/body_stream.rb +14 -0
  13. data/examples/idn.rb +10 -0
  14. data/examples/microsoft_graph.rb +52 -0
  15. data/examples/multipart.rb +22 -0
  16. data/examples/peer_cert.rb +9 -0
  17. data/examples/stream_download.rb +8 -2
  18. data/httparty.gemspec +3 -3
  19. data/lib/httparty/connection_adapter.rb +59 -16
  20. data/lib/httparty/cookie_hash.rb +10 -8
  21. data/lib/httparty/decompressor.rb +92 -0
  22. data/lib/httparty/exceptions.rb +3 -1
  23. data/lib/httparty/hash_conversions.rb +10 -4
  24. data/lib/httparty/headers_processor.rb +32 -0
  25. data/lib/httparty/logger/apache_formatter.rb +31 -6
  26. data/lib/httparty/logger/curl_formatter.rb +9 -7
  27. data/lib/httparty/logger/logger.rb +5 -1
  28. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  29. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  30. data/lib/httparty/net_digest_auth.rb +15 -15
  31. data/lib/httparty/parser.rb +9 -5
  32. data/lib/httparty/request/body.rb +46 -27
  33. data/lib/httparty/request/multipart_boundary.rb +2 -0
  34. data/lib/httparty/request.rb +75 -96
  35. data/lib/httparty/response/headers.rb +4 -2
  36. data/lib/httparty/response.rb +51 -8
  37. data/lib/httparty/response_fragment.rb +21 -0
  38. data/lib/httparty/text_encoder.rb +72 -0
  39. data/lib/httparty/utils.rb +13 -0
  40. data/lib/httparty/version.rb +3 -1
  41. data/lib/httparty.rb +70 -24
  42. data/website/css/common.css +1 -1
  43. metadata +33 -104
  44. data/.travis.yml +0 -10
  45. data/features/basic_authentication.feature +0 -20
  46. data/features/command_line.feature +0 -95
  47. data/features/deals_with_http_error_codes.feature +0 -26
  48. data/features/digest_authentication.feature +0 -30
  49. data/features/handles_compressed_responses.feature +0 -27
  50. data/features/handles_multiple_formats.feature +0 -57
  51. data/features/steps/env.rb +0 -27
  52. data/features/steps/httparty_response_steps.rb +0 -56
  53. data/features/steps/httparty_steps.rb +0 -43
  54. data/features/steps/mongrel_helper.rb +0 -127
  55. data/features/steps/remote_service_steps.rb +0 -92
  56. data/features/supports_read_timeout_option.feature +0 -13
  57. data/features/supports_redirection.feature +0 -22
  58. data/features/supports_timeout_option.feature +0 -13
  59. data/spec/fixtures/delicious.xml +0 -23
  60. data/spec/fixtures/empty.xml +0 -0
  61. data/spec/fixtures/google.html +0 -3
  62. data/spec/fixtures/ssl/generate.sh +0 -29
  63. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  64. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  65. data/spec/fixtures/ssl/generated/ca.key +0 -15
  66. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  67. data/spec/fixtures/ssl/generated/server.crt +0 -13
  68. data/spec/fixtures/ssl/generated/server.key +0 -15
  69. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  70. data/spec/fixtures/tiny.gif +0 -0
  71. data/spec/fixtures/twitter.csv +0 -2
  72. data/spec/fixtures/twitter.json +0 -1
  73. data/spec/fixtures/twitter.xml +0 -403
  74. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  75. data/spec/httparty/connection_adapter_spec.rb +0 -498
  76. data/spec/httparty/cookie_hash_spec.rb +0 -100
  77. data/spec/httparty/exception_spec.rb +0 -45
  78. data/spec/httparty/hash_conversions_spec.rb +0 -56
  79. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  80. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  81. data/spec/httparty/logger/logger_spec.rb +0 -38
  82. data/spec/httparty/net_digest_auth_spec.rb +0 -270
  83. data/spec/httparty/parser_spec.rb +0 -190
  84. data/spec/httparty/request/body_spec.rb +0 -60
  85. data/spec/httparty/request_spec.rb +0 -1312
  86. data/spec/httparty/response_spec.rb +0 -347
  87. data/spec/httparty/ssl_spec.rb +0 -74
  88. data/spec/httparty_spec.rb +0 -896
  89. data/spec/spec_helper.rb +0 -51
  90. data/spec/support/ssl_test_helper.rb +0 -47
  91. data/spec/support/ssl_test_server.rb +0 -80
  92. data/spec/support/stub_response.rb +0 -49
@@ -1,1312 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '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 HTTPParty::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 body is multipart" do
347
- it "sets header Content-Type: multipart/form-data; boundary=" do
348
- @request.options[:body] = {file: File.open(File::NULL, 'r')}
349
- @request.send(:setup_raw_request)
350
- headers = @request.instance_variable_get(:@raw_request).each_header.to_a
351
- headers = Hash[*headers.flatten] # Ruby 2.0 doesn't have Array#to_h
352
- expect(headers['content-type']).to match(%r{^multipart/form-data; boundary=---})
353
- end
354
-
355
- context "and header Content-Type is provided" do
356
- it "overwrites the header to: multipart/form-data; boundary=" do
357
- @request.options[:body] = {file: File.open(File::NULL, 'r')}
358
- @request.options[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
359
- @request.send(:setup_raw_request)
360
- headers = @request.instance_variable_get(:@raw_request).each_header.to_a
361
- headers = Hash[*headers.flatten] # Ruby 2.0 doesn't have Array#to_h
362
- expect(headers['content-type']).to match(%r{^multipart/form-data; boundary=---})
363
- end
364
- end
365
- end
366
- end
367
-
368
- describe 'http' do
369
- it "should get a connection from the connection_adapter" do
370
- http = Net::HTTP.new('google.com')
371
- adapter = double('adapter')
372
- request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', connection_adapter: adapter)
373
- expect(adapter).to receive(:call).with(request.uri, request.options).and_return(http)
374
- expect(request.send(:http)).to be http
375
- end
376
- end
377
-
378
- describe '#format_from_mimetype' do
379
- it 'should handle text/xml' do
380
- ["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
381
- expect(@request.send(:format_from_mimetype, ct)).to eq(:xml)
382
- end
383
- end
384
-
385
- it 'should handle application/xml' do
386
- ["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
387
- expect(@request.send(:format_from_mimetype, ct)).to eq(:xml)
388
- end
389
- end
390
-
391
- it 'should handle text/json' do
392
- ["text/json", "text/json; charset=iso8859-1"].each do |ct|
393
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
394
- end
395
- end
396
-
397
- it 'should handle application/vnd.api+json' do
398
- ["application/vnd.api+json", "application/vnd.api+json; charset=iso8859-1"].each do |ct|
399
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
400
- end
401
- end
402
-
403
- it 'should handle application/hal+json' do
404
- ["application/hal+json", "application/hal+json; charset=iso8859-1"].each do |ct|
405
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
406
- end
407
- end
408
-
409
- it 'should handle application/json' do
410
- ["application/json", "application/json; charset=iso8859-1"].each do |ct|
411
- expect(@request.send(:format_from_mimetype, ct)).to eq(:json)
412
- end
413
- end
414
-
415
- it 'should handle text/csv' do
416
- ["text/csv", "text/csv; charset=iso8859-1"].each do |ct|
417
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
418
- end
419
- end
420
-
421
- it 'should handle application/csv' do
422
- ["application/csv", "application/csv; charset=iso8859-1"].each do |ct|
423
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
424
- end
425
- end
426
-
427
- it 'should handle text/comma-separated-values' do
428
- ["text/comma-separated-values", "text/comma-separated-values; charset=iso8859-1"].each do |ct|
429
- expect(@request.send(:format_from_mimetype, ct)).to eq(:csv)
430
- end
431
- end
432
-
433
- it 'should handle text/javascript' do
434
- ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
435
- expect(@request.send(:format_from_mimetype, ct)).to eq(:plain)
436
- end
437
- end
438
-
439
- it 'should handle application/javascript' do
440
- ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
441
- expect(@request.send(:format_from_mimetype, ct)).to eq(:plain)
442
- end
443
- end
444
-
445
- it "returns nil for an unrecognized mimetype" do
446
- expect(@request.send(:format_from_mimetype, "application/atom+xml")).to be_nil
447
- end
448
-
449
- it "returns nil when using a default parser" do
450
- @request.options[:parser] = lambda {}
451
- expect(@request.send(:format_from_mimetype, "text/json")).to be_nil
452
- end
453
- end
454
-
455
- describe 'parsing responses' do
456
- it 'should handle xml automatically' do
457
- xml = '<books><book><id>1234</id><name>Foo Bar!</name></book></books>'
458
- @request.options[:format] = :xml
459
- expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
460
- end
461
-
462
- it 'should handle utf-8 bom in xml' do
463
- xml = "\xEF\xBB\xBF<books><book><id>1234</id><name>Foo Bar!</name></book></books>"
464
- @request.options[:format] = :xml
465
- expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
466
- end
467
-
468
- it 'should handle csv automatically' do
469
- csv = ['"id","Name"', '"1234","Foo Bar!"'].join("\n")
470
- @request.options[:format] = :csv
471
- expect(@request.send(:parse_response, csv)).to eq([%w(id Name), ["1234", "Foo Bar!"]])
472
- end
473
-
474
- it 'should handle json automatically' do
475
- json = '{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}'
476
- @request.options[:format] = :json
477
- expect(@request.send(:parse_response, json)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
478
- end
479
-
480
- it 'should handle utf-8 bom in json' do
481
- json = "\xEF\xBB\xBF{\"books\": {\"book\": {\"name\": \"Foo Bar!\", \"id\": \"1234\"}}}"
482
- @request.options[:format] = :json
483
- expect(@request.send(:parse_response, json)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}})
484
- end
485
-
486
- it "should include any HTTP headers in the returned response" do
487
- @request.options[:format] = :html
488
- response = stub_response "Content"
489
- response.initialize_http_header("key" => "value")
490
-
491
- expect(@request.perform.headers).to eq({ "key" => ["value"] })
492
- end
493
-
494
- if "".respond_to?(:encoding)
495
-
496
- let(:response_charset) {
497
- @request.send(:get_charset)
498
- }
499
-
500
- it "should process charset in content type properly" do
501
- response = stub_response "Content".force_encoding('ascii-8bit')
502
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-8")
503
- resp = @request.perform
504
- expect(response_charset).to_not be_empty
505
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
506
- end
507
-
508
- it "should process charset in content type properly if it has a different case" do
509
- response = stub_response "Content".force_encoding('ascii-8bit')
510
- response.initialize_http_header("Content-Type" => "text/plain;CHARSET = utf-8")
511
- resp = @request.perform
512
- expect(response_charset).to_not be_empty
513
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
514
- end
515
-
516
- it "should process quoted charset in content type properly" do
517
- response = stub_response "Content".force_encoding('ascii-8bit')
518
- response.initialize_http_header("Content-Type" => "text/plain;charset = \"utf-8\"")
519
- resp = @request.perform
520
- expect(response_charset).to_not be_empty
521
- expect(resp.body.encoding).to eq(Encoding.find("UTF-8"))
522
- end
523
-
524
- it "should process response with a nil body" do
525
- response = stub_response nil
526
- response.initialize_http_header("Content-Type" => "text/html;charset=UTF-8")
527
- resp = @request.perform
528
- expect(resp.body).to be_nil
529
- end
530
-
531
- it "should process utf-16 charset with little endian bom correctly" do
532
- @request.options[:assume_utf16_is_big_endian] = true
533
-
534
- response = stub_response "\xFF\xFEC\x00o\x00n\x00t\x00e\x00n\x00t\x00"
535
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
536
- resp = @request.perform
537
- expect(response_charset).to_not be_empty
538
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16LE"))
539
- end
540
-
541
- it "should process utf-16 charset with big endian bom correctly" do
542
- @request.options[:assume_utf16_is_big_endian] = false
543
-
544
- response = stub_response "\xFE\xFF\x00C\x00o\x00n\x00t\x00e\x00n\x00t"
545
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
546
- resp = @request.perform
547
- expect(response_charset).to_not be_empty
548
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16BE"))
549
- end
550
-
551
- it "should assume utf-16 little endian if options has been chosen" do
552
- @request.options[:assume_utf16_is_big_endian] = false
553
-
554
- response = stub_response "C\x00o\x00n\x00t\x00e\x00n\x00t\x00"
555
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
556
- resp = @request.perform
557
- expect(response_charset).to_not be_empty
558
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16LE"))
559
- end
560
-
561
- it "should perform no encoding if the charset is not available" do
562
- response = stub_response "Content"
563
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-lols")
564
- resp = @request.perform
565
- expect(response_charset).to_not be_empty
566
- # This encoding does not exist, thus the string should not be encodd with it
567
- expect(resp.body.encoding).to_not eq(response_charset)
568
- expect(resp.body).to eq("Content")
569
- expect(resp.body.encoding).to eq("Content".encoding)
570
- end
571
-
572
- it "should perform no encoding if the content type is specified but no charset is specified" do
573
- response = stub_response "Content"
574
- response.initialize_http_header("Content-Type" => "text/plain")
575
- resp = @request.perform
576
- expect(response_charset).to be_nil
577
- expect(resp.body).to eq("Content")
578
- expect(resp.body.encoding).to eq("Content".encoding)
579
- end
580
- end
581
-
582
- describe 'with non-200 responses' do
583
- context "3xx responses" do
584
- it 'returns a valid object for 304 not modified' do
585
- stub_response '', 304
586
- resp = @request.perform
587
- expect(resp.code).to eq(304)
588
- expect(resp.body).to eq('')
589
- expect(resp).to be_nil
590
- end
591
-
592
- it "redirects if a 300 contains a location header" do
593
- redirect = stub_response '', 300
594
- redirect['location'] = 'http://foo.com/foo'
595
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
596
- allow(@http).to receive(:request).and_return(redirect, ok)
597
- response = @request.perform
598
- expect(response.request.base_uri.to_s).to eq("http://foo.com")
599
- expect(response.request.path.to_s).to eq("http://foo.com/foo")
600
- expect(response.request.uri.request_uri).to eq("/foo")
601
- expect(response.request.uri.to_s).to eq("http://foo.com/foo")
602
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
603
- end
604
-
605
- it "calls block given to perform with each redirect" do
606
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
607
- stub_request(:get, 'http://test.com/redirect')
608
- .to_return(
609
- status: [300, 'REDIRECT'],
610
- headers: { location: 'http://api.foo.com/v2' }
611
- )
612
- stub_request(:get, 'http://api.foo.com/v2')
613
- .to_return(body: '<hash><foo>bar</foo></hash>')
614
- body = ""
615
- @request.perform { |chunk| body += chunk }
616
- expect(body.length).to eq(27)
617
- end
618
-
619
- it "redirects if a 300 contains a relative location header" do
620
- redirect = stub_response '', 300
621
- redirect['location'] = '/foo/bar'
622
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
623
- allow(@http).to receive(:request).and_return(redirect, ok)
624
- response = @request.perform
625
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
626
- expect(response.request.path.to_s).to eq("/foo/bar")
627
- expect(response.request.uri.request_uri).to eq("/foo/bar")
628
- expect(response.request.uri.to_s).to eq("http://api.foo.com/foo/bar")
629
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
630
- end
631
-
632
- it "handles multiple redirects and relative location headers on different hosts" do
633
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
634
- stub_request(:get, 'http://test.com/redirect')
635
- .to_return(
636
- status: [300, 'REDIRECT'],
637
- headers: { location: "http://api.foo.com/v2" }
638
- )
639
- stub_request(:get, 'http://api.foo.com/v2')
640
- .to_return(
641
- status: [300, 'REDIRECT'],
642
- headers: { location: '/v3' }
643
- )
644
- stub_request(:get, 'http://api.foo.com/v3')
645
- .to_return(body: '<hash><foo>bar</foo></hash>')
646
- response = @request.perform
647
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
648
- expect(response.request.path.to_s).to eq("/v3")
649
- expect(response.request.uri.request_uri).to eq("/v3")
650
- expect(response.request.uri.to_s).to eq("http://api.foo.com/v3")
651
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
652
- end
653
-
654
- it "raises an error if redirect has duplicate location header" do
655
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
656
- stub_request(:get, 'http://test.com/redirect')
657
- .to_return(
658
- status: [300, 'REDIRECT'],
659
- headers: {
660
- location: ['http://api.foo.com/v2', 'http://api.foo.com/v2']
661
- }
662
- )
663
- expect {@request.perform}.to raise_error(HTTParty::DuplicateLocationHeader)
664
- end
665
-
666
- it "returns the HTTParty::Response when the 300 does not contain a location header" do
667
- stub_response '', 300
668
- expect(HTTParty::Response).to be === @request.perform
669
- end
670
-
671
- it "redirects including port" do
672
- stub_request(:get, 'http://withport.com:3000/v1')
673
- .to_return(
674
- status: [301, 'Moved Permanently'],
675
- headers: { location: 'http://withport.com:3000/v2' }
676
- )
677
- stub_request(:get, 'http://withport.com:3000/v2')
678
- .to_return(status: 200)
679
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://withport.com:3000/v1')
680
- response = request.perform
681
- expect(response.request.base_uri.to_s).to eq("http://withport.com:3000")
682
- end
683
- end
684
-
685
- it 'should return a valid object for 4xx response' do
686
- stub_response '<foo><bar>yes</bar></foo>', 401
687
- resp = @request.perform
688
- expect(resp.code).to eq(401)
689
- expect(resp.body).to eq("<foo><bar>yes</bar></foo>")
690
- expect(resp['foo']['bar']).to eq("yes")
691
- end
692
-
693
- it 'should return a valid object for 5xx response' do
694
- stub_response '<foo><bar>error</bar></foo>', 500
695
- resp = @request.perform
696
- expect(resp.code).to eq(500)
697
- expect(resp.body).to eq("<foo><bar>error</bar></foo>")
698
- expect(resp['foo']['bar']).to eq("error")
699
- end
700
-
701
- it "parses response lazily so codes can be checked prior" do
702
- stub_response 'not xml', 500
703
- @request.options[:format] = :xml
704
- expect {
705
- response = @request.perform
706
- expect(response.code).to eq(500)
707
- expect(response.body).to eq('not xml')
708
- }.not_to raise_error
709
- end
710
- end
711
- end
712
-
713
- it "should not attempt to parse empty responses" do
714
- [204, 304].each do |code|
715
- stub_response "", code
716
-
717
- @request.options[:format] = :xml
718
- expect(@request.perform).to be_nil
719
- end
720
- end
721
-
722
- it "should not fail for missing mime type" do
723
- stub_response "Content for you"
724
- @request.options[:format] = :html
725
- expect(@request.perform.parsed_response).to eq('Content for you')
726
- end
727
-
728
- [300, 301, 302, 305].each do |code|
729
- describe "a request that #{code} redirects" do
730
- before(:each) do
731
- @redirect = stub_response("", code)
732
- @redirect['location'] = '/foo'
733
-
734
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
735
- end
736
-
737
- describe "once" do
738
- before(:each) do
739
- allow(@http).to receive(:request).and_return(@redirect, @ok)
740
- end
741
-
742
- it "should be handled by GET transparently" do
743
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
744
- end
745
-
746
- it "should be handled by POST transparently" do
747
- @request.http_method = Net::HTTP::Post
748
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
749
- end
750
-
751
- it "should be handled by DELETE transparently" do
752
- @request.http_method = Net::HTTP::Delete
753
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
754
- end
755
-
756
- it "should be handled by MOVE transparently" do
757
- @request.http_method = Net::HTTP::Move
758
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
759
- end
760
-
761
- it "should be handled by COPY transparently" do
762
- @request.http_method = Net::HTTP::Copy
763
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
764
- end
765
-
766
- it "should be handled by PATCH transparently" do
767
- @request.http_method = Net::HTTP::Patch
768
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
769
- end
770
-
771
- it "should be handled by PUT transparently" do
772
- @request.http_method = Net::HTTP::Put
773
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
774
- end
775
-
776
- it "should be handled by HEAD transparently" do
777
- @request.http_method = Net::HTTP::Head
778
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
779
- end
780
-
781
- it "should be handled by OPTIONS transparently" do
782
- @request.http_method = Net::HTTP::Options
783
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
784
- end
785
-
786
- it "should be handled by MKCOL transparently" do
787
- @request.http_method = Net::HTTP::Mkcol
788
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
789
- end
790
-
791
- it "should keep track of cookies between redirects" do
792
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
793
- @request.perform
794
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
795
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
796
- end
797
-
798
- it 'should update cookies with redirects' do
799
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
800
- @redirect['Set-Cookie'] = 'foo=tar;'
801
- @request.perform
802
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
803
- end
804
-
805
- it 'should keep cookies between redirects' do
806
- @request.options[:headers] = {'Cookie' => 'keep=me'}
807
- @redirect['Set-Cookie'] = 'foo=tar;'
808
- @request.perform
809
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
810
- end
811
-
812
- it "should handle multiple Set-Cookie headers between redirects" do
813
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
814
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
815
- @request.perform
816
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
817
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
818
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
819
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
820
- end
821
-
822
- it 'should make resulting request a get request if it not already' do
823
- @request.http_method = Net::HTTP::Delete
824
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
825
- expect(@request.http_method).to eq(Net::HTTP::Get)
826
- end
827
-
828
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
829
- @request.options[:maintain_method_across_redirects] = true
830
- @request.http_method = Net::HTTP::Delete
831
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
832
- expect(@request.http_method).to eq(Net::HTTP::Delete)
833
- end
834
-
835
- it 'should log the redirection' do
836
- logger_double = double
837
- expect(logger_double).to receive(:info).twice
838
- @request.options[:logger] = logger_double
839
- @request.perform
840
- end
841
- end
842
-
843
- describe "infinitely" do
844
- before(:each) do
845
- allow(@http).to receive(:request).and_return(@redirect)
846
- end
847
-
848
- it "should raise an exception" do
849
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
850
- end
851
- end
852
- end
853
- end
854
-
855
- describe "a request that 303 redirects" do
856
- before(:each) do
857
- @redirect = stub_response("", 303)
858
- @redirect['location'] = '/foo'
859
-
860
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
861
- end
862
-
863
- describe "once" do
864
- before(:each) do
865
- allow(@http).to receive(:request).and_return(@redirect, @ok)
866
- end
867
-
868
- it "should be handled by GET transparently" do
869
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
870
- end
871
-
872
- it "should be handled by POST transparently" do
873
- @request.http_method = Net::HTTP::Post
874
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
875
- end
876
-
877
- it "should be handled by DELETE transparently" do
878
- @request.http_method = Net::HTTP::Delete
879
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
880
- end
881
-
882
- it "should be handled by MOVE transparently" do
883
- @request.http_method = Net::HTTP::Move
884
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
885
- end
886
-
887
- it "should be handled by COPY transparently" do
888
- @request.http_method = Net::HTTP::Copy
889
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
890
- end
891
-
892
- it "should be handled by PATCH transparently" do
893
- @request.http_method = Net::HTTP::Patch
894
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
895
- end
896
-
897
- it "should be handled by PUT transparently" do
898
- @request.http_method = Net::HTTP::Put
899
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
900
- end
901
-
902
- it "should be handled by HEAD transparently" do
903
- @request.http_method = Net::HTTP::Head
904
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
905
- end
906
-
907
- it "should be handled by OPTIONS transparently" do
908
- @request.http_method = Net::HTTP::Options
909
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
910
- end
911
-
912
- it "should be handled by MKCOL transparently" do
913
- @request.http_method = Net::HTTP::Mkcol
914
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
915
- end
916
-
917
- it "should keep track of cookies between redirects" do
918
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
919
- @request.perform
920
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
921
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
922
- end
923
-
924
- it 'should update cookies with redirects' do
925
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
926
- @redirect['Set-Cookie'] = 'foo=tar;'
927
- @request.perform
928
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
929
- end
930
-
931
- it 'should keep cookies between redirects' do
932
- @request.options[:headers] = {'Cookie' => 'keep=me'}
933
- @redirect['Set-Cookie'] = 'foo=tar;'
934
- @request.perform
935
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
936
- end
937
-
938
- it "should handle multiple Set-Cookie headers between redirects" do
939
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
940
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
941
- @request.perform
942
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
943
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
944
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
945
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
946
- end
947
-
948
- it 'should make resulting request a get request if it not already' do
949
- @request.http_method = Net::HTTP::Delete
950
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
951
- expect(@request.http_method).to eq(Net::HTTP::Get)
952
- end
953
-
954
- it 'should make resulting request a get request if options[:maintain_method_across_redirects] is false' do
955
- @request.options[:maintain_method_across_redirects] = false
956
- @request.http_method = Net::HTTP::Delete
957
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
958
- expect(@request.http_method).to eq(Net::HTTP::Get)
959
- end
960
-
961
- it 'should make resulting request a get request if options[:maintain_method_across_redirects] is true but options[:resend_on_redirect] is false' do
962
- @request.options[:maintain_method_across_redirects] = true
963
- @request.options[:resend_on_redirect] = false
964
- @request.http_method = Net::HTTP::Delete
965
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
966
- expect(@request.http_method).to eq(Net::HTTP::Get)
967
- end
968
-
969
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] and options[:resend_on_redirect] is true' do
970
- @request.options[:maintain_method_across_redirects] = true
971
- @request.options[:resend_on_redirect] = true
972
- @request.http_method = Net::HTTP::Delete
973
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
974
- expect(@request.http_method).to eq(Net::HTTP::Delete)
975
- end
976
-
977
- it 'should log the redirection' do
978
- logger_double = double
979
- expect(logger_double).to receive(:info).twice
980
- @request.options[:logger] = logger_double
981
- @request.perform
982
- end
983
- end
984
-
985
- describe "infinitely" do
986
- before(:each) do
987
- allow(@http).to receive(:request).and_return(@redirect)
988
- end
989
-
990
- it "should raise an exception" do
991
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
992
- end
993
- end
994
- end
995
-
996
- describe "a request that returns 304" do
997
- before(:each) do
998
- @redirect = stub_response("", 304)
999
- @redirect['location'] = '/foo'
1000
- end
1001
-
1002
- before(:each) do
1003
- allow(@http).to receive(:request).and_return(@redirect)
1004
- end
1005
-
1006
- it "should report 304 with a GET request" do
1007
- expect(@request.perform.code).to eq(304)
1008
- end
1009
-
1010
- it "should report 304 with a POST request" do
1011
- @request.http_method = Net::HTTP::Post
1012
- expect(@request.perform.code).to eq(304)
1013
- end
1014
-
1015
- it "should report 304 with a DELETE request" do
1016
- @request.http_method = Net::HTTP::Delete
1017
- expect(@request.perform.code).to eq(304)
1018
- end
1019
-
1020
- it "should report 304 with a MOVE request" do
1021
- @request.http_method = Net::HTTP::Move
1022
- expect(@request.perform.code).to eq(304)
1023
- end
1024
-
1025
- it "should report 304 with a COPY request" do
1026
- @request.http_method = Net::HTTP::Copy
1027
- expect(@request.perform.code).to eq(304)
1028
- end
1029
-
1030
- it "should report 304 with a PATCH request" do
1031
- @request.http_method = Net::HTTP::Patch
1032
- expect(@request.perform.code).to eq(304)
1033
- end
1034
-
1035
- it "should report 304 with a PUT request" do
1036
- @request.http_method = Net::HTTP::Put
1037
- expect(@request.perform.code).to eq(304)
1038
- end
1039
-
1040
- it "should report 304 with a HEAD request" do
1041
- @request.http_method = Net::HTTP::Head
1042
- expect(@request.perform.code).to eq(304)
1043
- end
1044
-
1045
- it "should report 304 with a OPTIONS request" do
1046
- @request.http_method = Net::HTTP::Options
1047
- expect(@request.perform.code).to eq(304)
1048
- end
1049
-
1050
- it "should report 304 with a MKCOL request" do
1051
- @request.http_method = Net::HTTP::Mkcol
1052
- expect(@request.perform.code).to eq(304)
1053
- end
1054
-
1055
- it 'should not log the redirection' do
1056
- logger_double = double
1057
- expect(logger_double).to receive(:info).once
1058
- @request.options[:logger] = logger_double
1059
- @request.perform
1060
- end
1061
- end
1062
-
1063
- [307, 308].each do |code|
1064
- describe "a request that #{code} redirects" do
1065
- before(:each) do
1066
- @redirect = stub_response("", code)
1067
- @redirect['location'] = '/foo'
1068
-
1069
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1070
- end
1071
-
1072
- describe "once" do
1073
- before(:each) do
1074
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1075
- end
1076
-
1077
- it "should be handled by GET transparently" do
1078
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1079
- end
1080
-
1081
- it "should be handled by POST transparently" do
1082
- @request.http_method = Net::HTTP::Post
1083
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1084
- end
1085
-
1086
- it "should be handled by DELETE transparently" do
1087
- @request.http_method = Net::HTTP::Delete
1088
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1089
- end
1090
-
1091
- it "should be handled by MOVE transparently" do
1092
- @request.http_method = Net::HTTP::Move
1093
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1094
- end
1095
-
1096
- it "should be handled by COPY transparently" do
1097
- @request.http_method = Net::HTTP::Copy
1098
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1099
- end
1100
-
1101
- it "should be handled by PATCH transparently" do
1102
- @request.http_method = Net::HTTP::Patch
1103
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1104
- end
1105
-
1106
- it "should be handled by PUT transparently" do
1107
- @request.http_method = Net::HTTP::Put
1108
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1109
- end
1110
-
1111
- it "should be handled by HEAD transparently" do
1112
- @request.http_method = Net::HTTP::Head
1113
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1114
- end
1115
-
1116
- it "should be handled by OPTIONS transparently" do
1117
- @request.http_method = Net::HTTP::Options
1118
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1119
- end
1120
-
1121
- it "should be handled by MKCOL transparently" do
1122
- @request.http_method = Net::HTTP::Mkcol
1123
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1124
- end
1125
-
1126
- it "should keep track of cookies between redirects" do
1127
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
1128
- @request.perform
1129
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1130
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1131
- end
1132
-
1133
- it 'should update cookies with redirects' do
1134
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
1135
- @redirect['Set-Cookie'] = 'foo=tar;'
1136
- @request.perform
1137
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
1138
- end
1139
-
1140
- it 'should keep cookies between redirects' do
1141
- @request.options[:headers] = {'Cookie' => 'keep=me'}
1142
- @redirect['Set-Cookie'] = 'foo=tar;'
1143
- @request.perform
1144
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
1145
- end
1146
-
1147
- it "should handle multiple Set-Cookie headers between redirects" do
1148
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
1149
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
1150
- @request.perform
1151
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1152
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1153
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
1154
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
1155
- end
1156
-
1157
- it 'should maintain method in resulting request' do
1158
- @request.http_method = Net::HTTP::Delete
1159
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1160
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1161
- end
1162
-
1163
- it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is false' do
1164
- @request.options[:maintain_method_across_redirects] = false
1165
- @request.http_method = Net::HTTP::Delete
1166
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1167
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1168
- end
1169
-
1170
- it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is true' do
1171
- @request.options[:maintain_method_across_redirects] = true
1172
- @request.http_method = Net::HTTP::Delete
1173
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1174
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1175
- end
1176
-
1177
- it 'should log the redirection' do
1178
- logger_double = double
1179
- expect(logger_double).to receive(:info).twice
1180
- @request.options[:logger] = logger_double
1181
- @request.perform
1182
- end
1183
- end
1184
-
1185
- describe "infinitely" do
1186
- before(:each) do
1187
- allow(@http).to receive(:request).and_return(@redirect)
1188
- end
1189
-
1190
- it "should raise an exception" do
1191
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
1192
- end
1193
- end
1194
- end
1195
- end
1196
-
1197
- describe "#send_authorization_header?" do
1198
- context "basic_auth" do
1199
- before do
1200
- @credentials = { username: "username", password: "password" }
1201
- @authorization = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
1202
- @request.options[:basic_auth] = @credentials
1203
- @redirect = stub_response("", 302)
1204
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1205
- end
1206
-
1207
- before(:each) do
1208
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1209
- end
1210
-
1211
- it "should not send Authorization header when redirecting to a different host" do
1212
- @redirect['location'] = 'http://example.com/'
1213
- @request.perform
1214
- @request.send(:setup_raw_request)
1215
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to be_nil
1216
- end
1217
-
1218
- it "should send Authorization header when redirecting to a relative path" do
1219
- @redirect['location'] = '/v3'
1220
- @request.perform
1221
- @request.send(:setup_raw_request)
1222
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1223
- end
1224
-
1225
- it "should send Authorization header when redirecting to the same host" do
1226
- @redirect['location'] = 'http://api.foo.com/v2'
1227
- @request.perform
1228
- @request.send(:setup_raw_request)
1229
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1230
- end
1231
-
1232
- it "should send Authorization header when redirecting to a different port on the same host" do
1233
- @redirect['location'] = 'http://api.foo.com:3000/v3'
1234
- @request.perform
1235
- @request.send(:setup_raw_request)
1236
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1237
- end
1238
- end
1239
- end
1240
-
1241
- context "with POST http method" do
1242
- it "should raise argument error if query is not a hash" do
1243
- expect {
1244
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', format: :xml, query: 'astring').perform
1245
- }.to raise_error(ArgumentError)
1246
- end
1247
- end
1248
-
1249
- describe "argument validation" do
1250
- it "should raise argument error if basic_auth and digest_auth are both present" do
1251
- expect {
1252
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: {}, digest_auth: {}).perform
1253
- }.to raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
1254
- end
1255
-
1256
- it "should raise argument error if basic_auth is not a hash" do
1257
- expect {
1258
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: %w(foo bar)).perform
1259
- }.to raise_error(ArgumentError, ":basic_auth must be a hash")
1260
- end
1261
-
1262
- it "should raise argument error if digest_auth is not a hash" do
1263
- expect {
1264
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', digest_auth: %w(foo bar)).perform
1265
- }.to raise_error(ArgumentError, ":digest_auth must be a hash")
1266
- end
1267
-
1268
- it "should raise argument error if headers is not a hash" do
1269
- expect {
1270
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', headers: %w(foo bar)).perform
1271
- }.to raise_error(ArgumentError, ":headers must be a hash")
1272
- end
1273
-
1274
- it "should raise argument error if options method is not http accepted method" do
1275
- expect {
1276
- HTTParty::Request.new('SuperPost', 'http://api.foo.com/v1').perform
1277
- }.to raise_error(ArgumentError, "only get, post, patch, put, delete, head, and options methods are supported")
1278
- end
1279
-
1280
- it "should raise argument error if http method is post and query is not hash" do
1281
- expect {
1282
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', query: "message: hello").perform
1283
- }.to raise_error(ArgumentError, ":query must be hash if using HTTP Post")
1284
- end
1285
-
1286
- it "should raise RedirectionTooDeep error if limit is negative" do
1287
- expect {
1288
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', limit: -1).perform
1289
- }.to raise_error(HTTParty::RedirectionTooDeep, 'HTTP redirects too deep')
1290
- end
1291
- end
1292
-
1293
- context 'with Accept-Encoding header' do
1294
- it 'should disable content decoding if present' do
1295
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'Accept-Encoding' => 'custom'})
1296
- request.send(:setup_raw_request)
1297
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1298
- end
1299
-
1300
- it 'should disable content decoding if present and lowercase' do
1301
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'accept-encoding' => 'custom'})
1302
- request.send(:setup_raw_request)
1303
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1304
- end
1305
-
1306
- it 'should disable content decoding if present' do
1307
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1')
1308
- request.send(:setup_raw_request)
1309
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(true)
1310
- end
1311
- end
1312
- end