httparty 0.15.4 → 0.20.0

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

Potentially problematic release.


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

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