httparty 0.15.0 → 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 (96) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +26 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/{History.md → Changelog.md} +137 -0
  7. data/Gemfile +8 -1
  8. data/Guardfile +3 -2
  9. data/README.md +6 -6
  10. data/docs/README.md +120 -38
  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 +7 -4
  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 +4 -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 +25 -16
  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 +96 -105
  39. data/lib/httparty/response/headers.rb +6 -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 +38 -106
  48. data/.simplecov +0 -1
  49. data/.travis.yml +0 -8
  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/1fe462c2.0 +0 -1
  69. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  70. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  71. data/spec/fixtures/ssl/generated/ca.key +0 -15
  72. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  73. data/spec/fixtures/ssl/generated/server.crt +0 -13
  74. data/spec/fixtures/ssl/generated/server.key +0 -15
  75. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  76. data/spec/fixtures/twitter.csv +0 -2
  77. data/spec/fixtures/twitter.json +0 -1
  78. data/spec/fixtures/twitter.xml +0 -403
  79. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  80. data/spec/httparty/connection_adapter_spec.rb +0 -495
  81. data/spec/httparty/cookie_hash_spec.rb +0 -100
  82. data/spec/httparty/exception_spec.rb +0 -45
  83. data/spec/httparty/hash_conversions_spec.rb +0 -49
  84. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  85. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  86. data/spec/httparty/logger/logger_spec.rb +0 -38
  87. data/spec/httparty/net_digest_auth_spec.rb +0 -268
  88. data/spec/httparty/parser_spec.rb +0 -178
  89. data/spec/httparty/request_spec.rb +0 -1244
  90. data/spec/httparty/response_spec.rb +0 -347
  91. data/spec/httparty/ssl_spec.rb +0 -74
  92. data/spec/httparty_spec.rb +0 -877
  93. data/spec/spec_helper.rb +0 -59
  94. data/spec/support/ssl_test_helper.rb +0 -47
  95. data/spec/support/ssl_test_server.rb +0 -80
  96. data/spec/support/stub_response.rb +0 -49
@@ -1,1244 +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 utf-16 charset with little endian bom correctly" do
489
- @request.options[:assume_utf16_is_big_endian] = true
490
-
491
- response = stub_response "\xFF\xFEC\x00o\x00n\x00t\x00e\x00n\x00t\x00"
492
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16")
493
- resp = @request.perform
494
- expect(response_charset).to_not be_empty
495
- expect(resp.body.encoding).to eq(Encoding.find("UTF-16LE"))
496
- end
497
-
498
- it "should process utf-16 charset with big endian bom correctly" do
499
- @request.options[:assume_utf16_is_big_endian] = false
500
-
501
- response = stub_response "\xFE\xFF\x00C\x00o\x00n\x00t\x00e\x00n\x00t"
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-16BE"))
506
- end
507
-
508
- it "should assume utf-16 little endian if options has been chosen" do
509
- @request.options[:assume_utf16_is_big_endian] = false
510
-
511
- response = stub_response "C\x00o\x00n\x00t\x00e\x00n\x00t\x00"
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-16LE"))
516
- end
517
-
518
- it "should perform no encoding if the charset is not available" do
519
- response = stub_response "Content"
520
- response.initialize_http_header("Content-Type" => "text/plain;charset = utf-lols")
521
- resp = @request.perform
522
- expect(response_charset).to_not be_empty
523
- # This encoding does not exist, thus the string should not be encodd with it
524
- expect(resp.body.encoding).to_not eq(response_charset)
525
- expect(resp.body).to eq("Content")
526
- expect(resp.body.encoding).to eq("Content".encoding)
527
- end
528
-
529
- it "should perform no encoding if the content type is specified but no charset is specified" do
530
- response = stub_response "Content"
531
- response.initialize_http_header("Content-Type" => "text/plain")
532
- resp = @request.perform
533
- expect(response_charset).to be_nil
534
- expect(resp.body).to eq("Content")
535
- expect(resp.body.encoding).to eq("Content".encoding)
536
- end
537
- end
538
-
539
- describe 'with non-200 responses' do
540
- context "3xx responses" do
541
- it 'returns a valid object for 304 not modified' do
542
- stub_response '', 304
543
- resp = @request.perform
544
- expect(resp.code).to eq(304)
545
- expect(resp.body).to eq('')
546
- expect(resp).to be_nil
547
- end
548
-
549
- it "redirects if a 300 contains a location header" do
550
- redirect = stub_response '', 300
551
- redirect['location'] = 'http://foo.com/foo'
552
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
553
- allow(@http).to receive(:request).and_return(redirect, ok)
554
- response = @request.perform
555
- expect(response.request.base_uri.to_s).to eq("http://foo.com")
556
- expect(response.request.path.to_s).to eq("http://foo.com/foo")
557
- expect(response.request.uri.request_uri).to eq("/foo")
558
- expect(response.request.uri.to_s).to eq("http://foo.com/foo")
559
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
560
- end
561
-
562
- it "calls block given to perform with each redirect" do
563
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
564
- FakeWeb.register_uri(:get, "http://test.com/redirect", status: [300, "REDIRECT"], location: "http://api.foo.com/v2")
565
- FakeWeb.register_uri(:get, "http://api.foo.com/v2", body: "<hash><foo>bar</foo></hash>")
566
- body = ""
567
- response = @request.perform { |chunk| body += chunk }
568
- expect(body.length).to eq(27)
569
- end
570
-
571
- it "redirects if a 300 contains a relative location header" do
572
- redirect = stub_response '', 300
573
- redirect['location'] = '/foo/bar'
574
- ok = stub_response('<hash><foo>bar</foo></hash>', 200)
575
- allow(@http).to receive(:request).and_return(redirect, ok)
576
- response = @request.perform
577
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
578
- expect(response.request.path.to_s).to eq("/foo/bar")
579
- expect(response.request.uri.request_uri).to eq("/foo/bar")
580
- expect(response.request.uri.to_s).to eq("http://api.foo.com/foo/bar")
581
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
582
- end
583
-
584
- it "handles multiple redirects and relative location headers on different hosts" do
585
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
586
- FakeWeb.register_uri(:get, "http://test.com/redirect", status: [300, "REDIRECT"], location: "http://api.foo.com/v2")
587
- FakeWeb.register_uri(:get, "http://api.foo.com/v2", status: [300, "REDIRECT"], location: "/v3")
588
- FakeWeb.register_uri(:get, "http://api.foo.com/v3", body: "<hash><foo>bar</foo></hash>")
589
- response = @request.perform
590
- expect(response.request.base_uri.to_s).to eq("http://api.foo.com")
591
- expect(response.request.path.to_s).to eq("/v3")
592
- expect(response.request.uri.request_uri).to eq("/v3")
593
- expect(response.request.uri.to_s).to eq("http://api.foo.com/v3")
594
- expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}})
595
- end
596
-
597
- it "raises an error if redirect has duplicate location header" do
598
- @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml)
599
- FakeWeb.register_uri(:get, "http://test.com/redirect", status: [300, "REDIRECT"], location: ["http://api.foo.com/v2","http://api.foo.com/v2"])
600
- expect {@request.perform}.to raise_error(HTTParty::DuplicateLocationHeader)
601
- end
602
-
603
- it "returns the HTTParty::Response when the 300 does not contain a location header" do
604
- stub_response '', 300
605
- expect(HTTParty::Response).to be === @request.perform
606
- end
607
-
608
- it "redirects including port" do
609
- FakeWeb.register_uri(:get, "http://withport.com:3000/v1", status: [301, "Moved Permanently"], location: "http://withport.com:3000/v2")
610
- FakeWeb.register_uri(:get, "http://withport.com:3000/v2", status: 200)
611
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://withport.com:3000/v1')
612
- response = request.perform
613
- expect(response.request.base_uri.to_s).to eq("http://withport.com:3000")
614
- end
615
- end
616
-
617
- it 'should return a valid object for 4xx response' do
618
- stub_response '<foo><bar>yes</bar></foo>', 401
619
- resp = @request.perform
620
- expect(resp.code).to eq(401)
621
- expect(resp.body).to eq("<foo><bar>yes</bar></foo>")
622
- expect(resp['foo']['bar']).to eq("yes")
623
- end
624
-
625
- it 'should return a valid object for 5xx response' do
626
- stub_response '<foo><bar>error</bar></foo>', 500
627
- resp = @request.perform
628
- expect(resp.code).to eq(500)
629
- expect(resp.body).to eq("<foo><bar>error</bar></foo>")
630
- expect(resp['foo']['bar']).to eq("error")
631
- end
632
-
633
- it "parses response lazily so codes can be checked prior" do
634
- stub_response 'not xml', 500
635
- @request.options[:format] = :xml
636
- expect {
637
- response = @request.perform
638
- expect(response.code).to eq(500)
639
- expect(response.body).to eq('not xml')
640
- }.not_to raise_error
641
- end
642
- end
643
- end
644
-
645
- it "should not attempt to parse empty responses" do
646
- [204, 304].each do |code|
647
- stub_response "", code
648
-
649
- @request.options[:format] = :xml
650
- expect(@request.perform).to be_nil
651
- end
652
- end
653
-
654
- it "should not fail for missing mime type" do
655
- stub_response "Content for you"
656
- @request.options[:format] = :html
657
- expect(@request.perform.parsed_response).to eq('Content for you')
658
- end
659
-
660
- [300, 301, 302, 305].each do |code|
661
- describe "a request that #{code} redirects" do
662
- before(:each) do
663
- @redirect = stub_response("", code)
664
- @redirect['location'] = '/foo'
665
-
666
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
667
- end
668
-
669
- describe "once" do
670
- before(:each) do
671
- allow(@http).to receive(:request).and_return(@redirect, @ok)
672
- end
673
-
674
- it "should be handled by GET transparently" do
675
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
676
- end
677
-
678
- it "should be handled by POST transparently" do
679
- @request.http_method = Net::HTTP::Post
680
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
681
- end
682
-
683
- it "should be handled by DELETE transparently" do
684
- @request.http_method = Net::HTTP::Delete
685
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
686
- end
687
-
688
- it "should be handled by MOVE transparently" do
689
- @request.http_method = Net::HTTP::Move
690
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
691
- end
692
-
693
- it "should be handled by COPY transparently" do
694
- @request.http_method = Net::HTTP::Copy
695
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
696
- end
697
-
698
- it "should be handled by PATCH transparently" do
699
- @request.http_method = Net::HTTP::Patch
700
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
701
- end
702
-
703
- it "should be handled by PUT transparently" do
704
- @request.http_method = Net::HTTP::Put
705
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
706
- end
707
-
708
- it "should be handled by HEAD transparently" do
709
- @request.http_method = Net::HTTP::Head
710
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
711
- end
712
-
713
- it "should be handled by OPTIONS transparently" do
714
- @request.http_method = Net::HTTP::Options
715
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
716
- end
717
-
718
- it "should be handled by MKCOL transparently" do
719
- @request.http_method = Net::HTTP::Mkcol
720
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
721
- end
722
-
723
- it "should keep track of cookies between redirects" do
724
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
725
- @request.perform
726
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
727
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
728
- end
729
-
730
- it 'should update cookies with redirects' do
731
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
732
- @redirect['Set-Cookie'] = 'foo=tar;'
733
- @request.perform
734
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
735
- end
736
-
737
- it 'should keep cookies between redirects' do
738
- @request.options[:headers] = {'Cookie' => 'keep=me'}
739
- @redirect['Set-Cookie'] = 'foo=tar;'
740
- @request.perform
741
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
742
- end
743
-
744
- it "should handle multiple Set-Cookie headers between redirects" do
745
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
746
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
747
- @request.perform
748
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
749
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
750
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
751
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
752
- end
753
-
754
- it 'should make resulting request a get request if it not already' do
755
- @request.http_method = Net::HTTP::Delete
756
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
757
- expect(@request.http_method).to eq(Net::HTTP::Get)
758
- end
759
-
760
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
761
- @request.options[:maintain_method_across_redirects] = true
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::Delete)
765
- end
766
-
767
- it 'should log the redirection' do
768
- logger_double = double
769
- expect(logger_double).to receive(:info).twice
770
- @request.options[:logger] = logger_double
771
- @request.perform
772
- end
773
- end
774
-
775
- describe "infinitely" do
776
- before(:each) do
777
- allow(@http).to receive(:request).and_return(@redirect)
778
- end
779
-
780
- it "should raise an exception" do
781
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
782
- end
783
- end
784
- end
785
- end
786
-
787
- describe "a request that 303 redirects" do
788
- before(:each) do
789
- @redirect = stub_response("", 303)
790
- @redirect['location'] = '/foo'
791
-
792
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
793
- end
794
-
795
- describe "once" do
796
- before(:each) do
797
- allow(@http).to receive(:request).and_return(@redirect, @ok)
798
- end
799
-
800
- it "should be handled by GET transparently" do
801
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
802
- end
803
-
804
- it "should be handled by POST transparently" do
805
- @request.http_method = Net::HTTP::Post
806
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
807
- end
808
-
809
- it "should be handled by DELETE transparently" do
810
- @request.http_method = Net::HTTP::Delete
811
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
812
- end
813
-
814
- it "should be handled by MOVE transparently" do
815
- @request.http_method = Net::HTTP::Move
816
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
817
- end
818
-
819
- it "should be handled by COPY transparently" do
820
- @request.http_method = Net::HTTP::Copy
821
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
822
- end
823
-
824
- it "should be handled by PATCH transparently" do
825
- @request.http_method = Net::HTTP::Patch
826
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
827
- end
828
-
829
- it "should be handled by PUT transparently" do
830
- @request.http_method = Net::HTTP::Put
831
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
832
- end
833
-
834
- it "should be handled by HEAD transparently" do
835
- @request.http_method = Net::HTTP::Head
836
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
837
- end
838
-
839
- it "should be handled by OPTIONS transparently" do
840
- @request.http_method = Net::HTTP::Options
841
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
842
- end
843
-
844
- it "should be handled by MKCOL transparently" do
845
- @request.http_method = Net::HTTP::Mkcol
846
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
847
- end
848
-
849
- it "should keep track of cookies between redirects" do
850
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
851
- @request.perform
852
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
853
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
854
- end
855
-
856
- it 'should update cookies with redirects' do
857
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
858
- @redirect['Set-Cookie'] = 'foo=tar;'
859
- @request.perform
860
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
861
- end
862
-
863
- it 'should keep cookies between redirects' do
864
- @request.options[:headers] = {'Cookie' => 'keep=me'}
865
- @redirect['Set-Cookie'] = 'foo=tar;'
866
- @request.perform
867
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
868
- end
869
-
870
- it "should handle multiple Set-Cookie headers between redirects" do
871
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
872
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
873
- @request.perform
874
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
875
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
876
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
877
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
878
- end
879
-
880
- it 'should make resulting request a get request if it not already' do
881
- @request.http_method = Net::HTTP::Delete
882
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
883
- expect(@request.http_method).to eq(Net::HTTP::Get)
884
- end
885
-
886
- it 'should make resulting request a get request if options[:maintain_method_across_redirects] is false' do
887
- @request.options[:maintain_method_across_redirects] = false
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 true but options[:resend_on_redirect] is false' do
894
- @request.options[:maintain_method_across_redirects] = true
895
- @request.options[:resend_on_redirect] = false
896
- @request.http_method = Net::HTTP::Delete
897
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
898
- expect(@request.http_method).to eq(Net::HTTP::Get)
899
- end
900
-
901
- it 'should not make resulting request a get request if options[:maintain_method_across_redirects] and options[:resend_on_redirect] is true' do
902
- @request.options[:maintain_method_across_redirects] = true
903
- @request.options[:resend_on_redirect] = true
904
- @request.http_method = Net::HTTP::Delete
905
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
906
- expect(@request.http_method).to eq(Net::HTTP::Delete)
907
- end
908
-
909
- it 'should log the redirection' do
910
- logger_double = double
911
- expect(logger_double).to receive(:info).twice
912
- @request.options[:logger] = logger_double
913
- @request.perform
914
- end
915
- end
916
-
917
- describe "infinitely" do
918
- before(:each) do
919
- allow(@http).to receive(:request).and_return(@redirect)
920
- end
921
-
922
- it "should raise an exception" do
923
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
924
- end
925
- end
926
- end
927
-
928
- describe "a request that returns 304" do
929
- before(:each) do
930
- @redirect = stub_response("", 304)
931
- @redirect['location'] = '/foo'
932
- end
933
-
934
- before(:each) do
935
- allow(@http).to receive(:request).and_return(@redirect)
936
- end
937
-
938
- it "should report 304 with a GET request" do
939
- expect(@request.perform.code).to eq(304)
940
- end
941
-
942
- it "should report 304 with a POST request" do
943
- @request.http_method = Net::HTTP::Post
944
- expect(@request.perform.code).to eq(304)
945
- end
946
-
947
- it "should report 304 with a DELETE request" do
948
- @request.http_method = Net::HTTP::Delete
949
- expect(@request.perform.code).to eq(304)
950
- end
951
-
952
- it "should report 304 with a MOVE request" do
953
- @request.http_method = Net::HTTP::Move
954
- expect(@request.perform.code).to eq(304)
955
- end
956
-
957
- it "should report 304 with a COPY request" do
958
- @request.http_method = Net::HTTP::Copy
959
- expect(@request.perform.code).to eq(304)
960
- end
961
-
962
- it "should report 304 with a PATCH request" do
963
- @request.http_method = Net::HTTP::Patch
964
- expect(@request.perform.code).to eq(304)
965
- end
966
-
967
- it "should report 304 with a PUT request" do
968
- @request.http_method = Net::HTTP::Put
969
- expect(@request.perform.code).to eq(304)
970
- end
971
-
972
- it "should report 304 with a HEAD request" do
973
- @request.http_method = Net::HTTP::Head
974
- expect(@request.perform.code).to eq(304)
975
- end
976
-
977
- it "should report 304 with a OPTIONS request" do
978
- @request.http_method = Net::HTTP::Options
979
- expect(@request.perform.code).to eq(304)
980
- end
981
-
982
- it "should report 304 with a MKCOL request" do
983
- @request.http_method = Net::HTTP::Mkcol
984
- expect(@request.perform.code).to eq(304)
985
- end
986
-
987
- it 'should not log the redirection' do
988
- logger_double = double
989
- expect(logger_double).to receive(:info).once
990
- @request.options[:logger] = logger_double
991
- @request.perform
992
- end
993
- end
994
-
995
- [307, 308].each do |code|
996
- describe "a request that #{code} redirects" do
997
- before(:each) do
998
- @redirect = stub_response("", code)
999
- @redirect['location'] = '/foo'
1000
-
1001
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1002
- end
1003
-
1004
- describe "once" do
1005
- before(:each) do
1006
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1007
- end
1008
-
1009
- it "should be handled by GET transparently" do
1010
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1011
- end
1012
-
1013
- it "should be handled by POST transparently" do
1014
- @request.http_method = Net::HTTP::Post
1015
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1016
- end
1017
-
1018
- it "should be handled by DELETE transparently" do
1019
- @request.http_method = Net::HTTP::Delete
1020
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1021
- end
1022
-
1023
- it "should be handled by MOVE transparently" do
1024
- @request.http_method = Net::HTTP::Move
1025
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1026
- end
1027
-
1028
- it "should be handled by COPY transparently" do
1029
- @request.http_method = Net::HTTP::Copy
1030
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1031
- end
1032
-
1033
- it "should be handled by PATCH transparently" do
1034
- @request.http_method = Net::HTTP::Patch
1035
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1036
- end
1037
-
1038
- it "should be handled by PUT transparently" do
1039
- @request.http_method = Net::HTTP::Put
1040
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1041
- end
1042
-
1043
- it "should be handled by HEAD transparently" do
1044
- @request.http_method = Net::HTTP::Head
1045
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1046
- end
1047
-
1048
- it "should be handled by OPTIONS transparently" do
1049
- @request.http_method = Net::HTTP::Options
1050
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1051
- end
1052
-
1053
- it "should be handled by MKCOL transparently" do
1054
- @request.http_method = Net::HTTP::Mkcol
1055
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1056
- end
1057
-
1058
- it "should keep track of cookies between redirects" do
1059
- @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
1060
- @request.perform
1061
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1062
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1063
- end
1064
-
1065
- it 'should update cookies with redirects' do
1066
- @request.options[:headers] = {'Cookie' => 'foo=bar;'}
1067
- @redirect['Set-Cookie'] = 'foo=tar;'
1068
- @request.perform
1069
- expect(@request.options[:headers]['Cookie']).to match(/foo=tar/)
1070
- end
1071
-
1072
- it 'should keep cookies between redirects' do
1073
- @request.options[:headers] = {'Cookie' => 'keep=me'}
1074
- @redirect['Set-Cookie'] = 'foo=tar;'
1075
- @request.perform
1076
- expect(@request.options[:headers]['Cookie']).to match(/keep=me/)
1077
- end
1078
-
1079
- it "should handle multiple Set-Cookie headers between redirects" do
1080
- @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly'
1081
- @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly'
1082
- @request.perform
1083
- expect(@request.options[:headers]['Cookie']).to match(/foo=bar/)
1084
- expect(@request.options[:headers]['Cookie']).to match(/name=value/)
1085
- expect(@request.options[:headers]['Cookie']).to match(/one=1/)
1086
- expect(@request.options[:headers]['Cookie']).to match(/two=2/)
1087
- end
1088
-
1089
- it 'should maintain method in resulting request' do
1090
- @request.http_method = Net::HTTP::Delete
1091
- expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}})
1092
- expect(@request.http_method).to eq(Net::HTTP::Delete)
1093
- end
1094
-
1095
- it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is false' do
1096
- @request.options[:maintain_method_across_redirects] = false
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 true' do
1103
- @request.options[:maintain_method_across_redirects] = true
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 log the redirection' do
1110
- logger_double = double
1111
- expect(logger_double).to receive(:info).twice
1112
- @request.options[:logger] = logger_double
1113
- @request.perform
1114
- end
1115
- end
1116
-
1117
- describe "infinitely" do
1118
- before(:each) do
1119
- allow(@http).to receive(:request).and_return(@redirect)
1120
- end
1121
-
1122
- it "should raise an exception" do
1123
- expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep)
1124
- end
1125
- end
1126
- end
1127
- end
1128
-
1129
- describe "#send_authorization_header?" do
1130
- context "basic_auth" do
1131
- before do
1132
- @credentials = { username: "username", password: "password" }
1133
- @authorization = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
1134
- @request.options[:basic_auth] = @credentials
1135
- @redirect = stub_response("", 302)
1136
- @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
1137
- end
1138
-
1139
- before(:each) do
1140
- allow(@http).to receive(:request).and_return(@redirect, @ok)
1141
- end
1142
-
1143
- it "should not send Authorization header when redirecting to a different host" do
1144
- @redirect['location'] = 'http://example.com/'
1145
- @request.perform
1146
- @request.send(:setup_raw_request)
1147
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to be_nil
1148
- end
1149
-
1150
- it "should send Authorization header when redirecting to a relative path" do
1151
- @redirect['location'] = '/v3'
1152
- @request.perform
1153
- @request.send(:setup_raw_request)
1154
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1155
- end
1156
-
1157
- it "should send Authorization header when redirecting to the same host" do
1158
- @redirect['location'] = 'http://api.foo.com/v2'
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 a different port on the same host" do
1165
- @redirect['location'] = 'http://api.foo.com:3000/v3'
1166
- @request.perform
1167
- @request.send(:setup_raw_request)
1168
- expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization)
1169
- end
1170
- end
1171
- end
1172
-
1173
- context "with POST http method" do
1174
- it "should raise argument error if query is not a hash" do
1175
- expect {
1176
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', format: :xml, query: 'astring').perform
1177
- }.to raise_error(ArgumentError)
1178
- end
1179
- end
1180
-
1181
- describe "argument validation" do
1182
- it "should raise argument error if basic_auth and digest_auth are both present" do
1183
- expect {
1184
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: {}, digest_auth: {}).perform
1185
- }.to raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
1186
- end
1187
-
1188
- it "should raise argument error if basic_auth is not a hash" do
1189
- expect {
1190
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: %w(foo bar)).perform
1191
- }.to raise_error(ArgumentError, ":basic_auth must be a hash")
1192
- end
1193
-
1194
- it "should raise argument error if digest_auth is not a hash" do
1195
- expect {
1196
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', digest_auth: %w(foo bar)).perform
1197
- }.to raise_error(ArgumentError, ":digest_auth must be a hash")
1198
- end
1199
-
1200
- it "should raise argument error if headers is not a hash" do
1201
- expect {
1202
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', headers: %w(foo bar)).perform
1203
- }.to raise_error(ArgumentError, ":headers must be a hash")
1204
- end
1205
-
1206
- it "should raise argument error if options method is not http accepted method" do
1207
- expect {
1208
- HTTParty::Request.new('SuperPost', 'http://api.foo.com/v1').perform
1209
- }.to raise_error(ArgumentError, "only get, post, patch, put, delete, head, and options methods are supported")
1210
- end
1211
-
1212
- it "should raise argument error if http method is post and query is not hash" do
1213
- expect {
1214
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', query: "message: hello").perform
1215
- }.to raise_error(ArgumentError, ":query must be hash if using HTTP Post")
1216
- end
1217
-
1218
- it "should raise RedirectionTooDeep error if limit is negative" do
1219
- expect {
1220
- HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', limit: -1).perform
1221
- }.to raise_error(HTTParty::RedirectionTooDeep, 'HTTP redirects too deep')
1222
- end
1223
- end
1224
-
1225
- context 'with Accept-Encoding header' do
1226
- it 'should disable content decoding if present' do
1227
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'Accept-Encoding' => 'custom'})
1228
- request.send(:setup_raw_request)
1229
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1230
- end
1231
-
1232
- it 'should disable content decoding if present and lowercase' do
1233
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'accept-encoding' => 'custom'})
1234
- request.send(:setup_raw_request)
1235
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false)
1236
- end
1237
-
1238
- it 'should disable content decoding if present' do
1239
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1')
1240
- request.send(:setup_raw_request)
1241
- expect(request.instance_variable_get(:@raw_request).decode_content).to eq(true)
1242
- end
1243
- end
1244
- end