httparty 0.17.0 → 0.17.1

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

Potentially problematic release.


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

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