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