http 0.8.0.pre4 → 0.8.0.pre5

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.
@@ -1,3 +1,5 @@
1
+ # AUTO-GENERATED FILE, DO NOT CHANGE IT MANUALLY
2
+
1
3
  require "delegate"
2
4
 
3
5
  module HTTP
@@ -9,7 +11,6 @@ module HTTP
9
11
  #
10
12
  # REASONS[400] # => "Bad Request"
11
13
  # REASONS[414] # => "Request-URI Too Long"
12
- # REASONS[418] # => "I'm a Teapot"
13
14
  #
14
15
  # @return [Hash<Fixnum => String>]
15
16
  REASONS = {
@@ -24,6 +25,7 @@ module HTTP
24
25
  205 => "Reset Content",
25
26
  206 => "Partial Content",
26
27
  207 => "Multi-Status",
28
+ 208 => "Already Reported",
27
29
  226 => "IM Used",
28
30
  300 => "Multiple Choices",
29
31
  301 => "Moved Permanently",
@@ -31,7 +33,6 @@ module HTTP
31
33
  303 => "See Other",
32
34
  304 => "Not Modified",
33
35
  305 => "Use Proxy",
34
- 306 => "Reserved",
35
36
  307 => "Temporary Redirect",
36
37
  308 => "Permanent Redirect",
37
38
  400 => "Bad Request",
@@ -47,16 +48,19 @@ module HTTP
47
48
  410 => "Gone",
48
49
  411 => "Length Required",
49
50
  412 => "Precondition Failed",
50
- 413 => "Request Entity Too Large",
51
- 414 => "Request-URI Too Long",
51
+ 413 => "Payload Too Large",
52
+ 414 => "URI Too Long",
52
53
  415 => "Unsupported Media Type",
53
- 416 => "Requested Range Not Satisfiable",
54
+ 416 => "Range Not Satisfiable",
54
55
  417 => "Expectation Failed",
55
- 418 => "I'm a Teapot",
56
+ 421 => "Misdirected Request",
56
57
  422 => "Unprocessable Entity",
57
58
  423 => "Locked",
58
59
  424 => "Failed Dependency",
59
60
  426 => "Upgrade Required",
61
+ 428 => "Precondition Required",
62
+ 429 => "Too Many Requests",
63
+ 431 => "Request Header Fields Too Large",
60
64
  500 => "Internal Server Error",
61
65
  501 => "Not Implemented",
62
66
  502 => "Bad Gateway",
@@ -65,7 +69,9 @@ module HTTP
65
69
  505 => "HTTP Version Not Supported",
66
70
  506 => "Variant Also Negotiates",
67
71
  507 => "Insufficient Storage",
68
- 510 => "Not Extended"
72
+ 508 => "Loop Detected",
73
+ 510 => "Not Extended",
74
+ 511 => "Network Authentication Required"
69
75
  }.each { |_, v| v.freeze }.freeze
70
76
  end
71
77
  end
@@ -1,4 +1,3 @@
1
- # rubocop:disable Lint/HandleExceptions
2
1
  module HTTP
3
2
  module Timeout
4
3
  class Global < PerOperation
@@ -11,24 +10,28 @@ module HTTP
11
10
  @total_timeout = time_left
12
11
  end
13
12
 
14
- # Abstracted out from the normal connect for SSL connections
15
- def connect_with_timeout(*args)
13
+ def connect(socket_class, host, port)
16
14
  reset_timer
15
+ ::Timeout.timeout(time_left, TimeoutError) do
16
+ @socket = socket_class.open(host, port)
17
+ end
17
18
 
18
- begin
19
- socket.connect_nonblock(*args)
19
+ log_time
20
+ end
21
+
22
+ def connect_ssl
23
+ reset_timer
20
24
 
25
+ begin
26
+ socket.connect_nonblock
21
27
  rescue IO::WaitReadable
22
28
  IO.select([socket], nil, nil, time_left)
23
29
  log_time
24
30
  retry
25
-
26
- rescue Errno::EINPROGRESS
31
+ rescue IO::WaitWritable
27
32
  IO.select(nil, [socket], nil, time_left)
28
33
  log_time
29
34
  retry
30
-
31
- rescue Errno::EISCONN
32
35
  end
33
36
  end
34
37
 
@@ -58,26 +61,9 @@ module HTTP
58
61
  end
59
62
  end
60
63
 
61
- private
64
+ alias_method :<<, :write
62
65
 
63
- # Create a DNS resolver
64
- def resolve_address(host)
65
- addr = HostResolver.getaddress(host)
66
- return addr if addr
67
-
68
- reset_timer
69
-
70
- addr = Resolv::DNS.open(:timeout => time_left) do |dns|
71
- dns.getaddress
72
- end
73
-
74
- log_time
75
-
76
- addr
77
-
78
- rescue Resolv::ResolvTimeout
79
- raise TimeoutError, "DNS timed out after #{total_timeout} seconds"
80
- end
66
+ private
81
67
 
82
68
  # Due to the run/retry nature of nonblocking I/O, it's easier to keep track of time
83
69
  # via method calls instead of a block to monitor.
@@ -96,4 +82,3 @@ module HTTP
96
82
  end
97
83
  end
98
84
  end
99
- # rubocop:enable Lint/HandleExceptions
@@ -25,8 +25,6 @@ module HTTP
25
25
 
26
26
  # Configures the SSL connection and starts the connection
27
27
  def start_tls(host, ssl_socket_class, ssl_context)
28
- # TODO: abstract away SSLContexts so we can use other TLS libraries
29
- ssl_context ||= OpenSSL::SSL::SSLContext.new
30
28
  @socket = ssl_socket_class.new(socket, ssl_context)
31
29
  socket.sync_close = true
32
30
 
@@ -1,6 +1,3 @@
1
- # rubocop:disable Lint/HandleExceptions
2
- require "resolv"
3
-
4
1
  module HTTP
5
2
  module Timeout
6
3
  class PerOperation < Null
@@ -20,40 +17,28 @@ module HTTP
20
17
  @connect_timeout = options.fetch(:connect_timeout, CONNECT_TIMEOUT)
21
18
  end
22
19
 
23
- def connect(_, host, port)
24
- # https://github.com/celluloid/celluloid-io/blob/master/lib/celluloid/io/tcp_socket.rb
25
- begin
26
- addr = Resolv::IPv4.create(host)
27
- rescue ArgumentError
28
- end
29
-
30
- # Guess it's not IPv4! Is it IPv6?
31
- begin
32
- addr ||= Resolv::IPv6.create(host)
33
- rescue ArgumentError
20
+ def connect(socket_class, host, port)
21
+ ::Timeout.timeout(connect_timeout, TimeoutError) do
22
+ @socket = socket_class.open(host, port)
34
23
  end
24
+ end
35
25
 
36
- unless addr
37
- addr = resolve_address(host)
38
- fail Resolv::ResolvError, "DNS result has no information for #{host}" unless addr
26
+ def connect_ssl
27
+ socket.connect_nonblock
28
+ rescue IO::WaitReadable
29
+ if IO.select([socket], nil, nil, connect_timeout)
30
+ retry
31
+ else
32
+ raise TimeoutError, "Connection timed out after #{connect_timeout} seconds"
39
33
  end
40
-
41
- case addr
42
- when Resolv::IPv4
43
- family = Socket::AF_INET
44
- when Resolv::IPv6
45
- family = Socket::AF_INET6
46
- else fail ArgumentError, "unsupported address class: #{addr.class}"
34
+ rescue IO::WaitWritable
35
+ if IO.select(nil, [socket], nil, connect_timeout)
36
+ retry
37
+ else
38
+ raise TimeoutError, "Connection timed out after #{connect_timeout} seconds"
47
39
  end
48
-
49
- @socket = Socket.new(family, Socket::SOCK_STREAM, 0)
50
-
51
- connect_with_timeout(Socket.sockaddr_in(port, addr.to_s))
52
40
  end
53
41
 
54
- # No changes need to be made for the SSL connection
55
- alias_method :connect_with_timeout, :connect_ssl
56
-
57
42
  # Read data from the socket
58
43
  def readpartial(size)
59
44
  socket.read_nonblock(size)
@@ -75,43 +60,6 @@ module HTTP
75
60
  raise TimeoutError, "Read timed out after #{write_timeout} seconds"
76
61
  end
77
62
  end
78
-
79
- private
80
-
81
- # Actually do the connect after we're setup
82
- def connect_with_timeout(*args)
83
- socket.connect_nonblock(*args)
84
-
85
- rescue IO::WaitReadable
86
- if IO.select([socket], nil, nil, connect_timeout)
87
- retry
88
- else
89
- raise TimeoutError, "Connection timed out after #{connect_timeout} seconds"
90
- end
91
-
92
- rescue Errno::EINPROGRESS
93
- if IO.select(nil, [socket], nil, connect_timeout)
94
- retry
95
- else
96
- raise TimeoutError, "Connection timed out after #{connect_timeout} seconds"
97
- end
98
-
99
- rescue Errno::EISCONN
100
- end
101
-
102
- # Create a DNS resolver
103
- def resolve_address(host)
104
- addr = HostResolver.getaddress(host)
105
- return addr if addr
106
-
107
- Resolv::DNS.open(:timeout => connect_timeout) do |dns|
108
- dns.getaddress
109
- end
110
-
111
- rescue Resolv::ResolvTimeout
112
- raise TimeoutError, "DNS timed out after #{connect_timeout} seconds"
113
- end
114
63
  end
115
64
  end
116
65
  end
117
- # rubocop:enable Lint/HandleExceptions
data/lib/http/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = "0.8.0.pre4"
2
+ VERSION = "0.8.0.pre5"
3
3
  end
@@ -1,10 +1,11 @@
1
1
  require "support/http_handling_shared"
2
2
  require "support/dummy_server"
3
+ require "support/ssl_helper"
4
+
3
5
  require "http/cache"
4
6
 
5
7
  RSpec.describe HTTP::Client do
6
8
  run_server(:dummy) { DummyServer.new }
7
- run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
8
9
 
9
10
  StubbedClient = Class.new(HTTP::Client) do
10
11
  def make_request(request, options)
@@ -59,7 +60,7 @@ RSpec.describe HTTP::Client do
59
60
  end
60
61
 
61
62
  it "fails if max amount of hops reached" do
62
- client = StubbedClient.new(:follow => 5).stub(
63
+ client = StubbedClient.new(:follow => {:max_hops => 5}).stub(
63
64
  "http://example.com/" => redirect_response("/1"),
64
65
  "http://example.com/1" => redirect_response("/2"),
65
66
  "http://example.com/2" => redirect_response("/3"),
@@ -169,44 +170,39 @@ RSpec.describe HTTP::Client do
169
170
 
170
171
  include_context "HTTP handling" do
171
172
  let(:options) { {} }
172
- let(:server) { dummy }
173
- let(:client) { described_class.new(options) }
173
+ let(:server) { dummy }
174
+ let(:client) { described_class.new(options) }
174
175
  end
175
176
 
176
- describe "SSL" do
177
+ describe "working with SSL" do
178
+ run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
179
+
177
180
  let(:client) do
178
- described_class.new(
179
- options.merge(
180
- :ssl_context => OpenSSL::SSL::SSLContext.new.tap do |context|
181
- context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
182
-
183
- context.verify_mode = OpenSSL::SSL::VERIFY_PEER
184
- context.ca_file = File.join(certs_dir, "ca.crt")
185
- context.cert = OpenSSL::X509::Certificate.new(
186
- File.read(File.join(certs_dir, "client.crt"))
187
- )
188
- context.key = OpenSSL::PKey::RSA.new(
189
- File.read(File.join(certs_dir, "client.key"))
190
- )
191
- context
192
- end
193
- )
194
- )
181
+ described_class.new options.merge :ssl_context => SSLHelper.client_context
195
182
  end
196
183
 
197
- include_context "HTTP handling", true do
184
+ include_context "HTTP handling" do
198
185
  let(:server) { dummy_ssl }
199
186
  end
200
187
 
201
- it "works via SSL" do
188
+ it "just works" do
202
189
  response = client.get(dummy_ssl.endpoint)
203
190
  expect(response.body.to_s).to eq("<!doctype html>")
204
191
  end
205
192
 
206
- context "with a mismatch host" do
207
- it "errors" do
208
- expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }
209
- .to raise_error(OpenSSL::SSL::SSLError, /does not match/)
193
+ it "fails with OpenSSL::SSL::SSLError if host mismatch" do
194
+ expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }
195
+ .to raise_error(OpenSSL::SSL::SSLError, /does not match/)
196
+ end
197
+
198
+ context "with SSL options instead of a context" do
199
+ let(:client) do
200
+ described_class.new options.merge :ssl => SSLHelper.client_params
201
+ end
202
+
203
+ it "just works" do
204
+ response = client.get(dummy_ssl.endpoint)
205
+ expect(response.body.to_s).to eq("<!doctype html>")
210
206
  end
211
207
  end
212
208
  end
@@ -35,6 +35,7 @@ RSpec.describe HTTP::Options, "merge" do
35
35
  :keep_alive_timeout => 10,
36
36
  :headers => {:accept => "xml", :bar => "bar"},
37
37
  :timeout_options => {:foo => :bar},
38
+ :ssl => {:foo => "bar"},
38
39
  :proxy => {:proxy_address => "127.0.0.1", :proxy_port => 8080})
39
40
 
40
41
  expect(foo.merge(bar).to_hash).to eq(
@@ -47,6 +48,7 @@ RSpec.describe HTTP::Options, "merge" do
47
48
  :json => {:bar => "bar"},
48
49
  :persistent => "https://www.googe.com",
49
50
  :keep_alive_timeout => 10,
51
+ :ssl => {:foo => "bar"},
50
52
  :headers => {"Foo" => "foo", "Accept" => "xml", "Bar" => "bar"},
51
53
  :proxy => {:proxy_address => "127.0.0.1", :proxy_port => 8080},
52
54
  :follow => nil,
@@ -3,95 +3,376 @@ RSpec.describe HTTP::Redirector do
3
3
  HTTP::Response.new(status, "1.1", headers, body)
4
4
  end
5
5
 
6
- def redirect_response(location, status)
6
+ def redirect_response(status, location)
7
7
  simple_response status, "", "Location" => location
8
8
  end
9
9
 
10
- let(:max_hops) { 5 }
11
- subject(:redirector) { described_class.new max_hops }
10
+ describe "#strict" do
11
+ subject { redirector.strict }
12
12
 
13
- context "following 300 redirect" do
14
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
15
- let(:orig_response) { redirect_response "http://example.com/", 300 }
13
+ context "by default" do
14
+ let(:redirector) { described_class.new }
15
+ it { is_expected.to be true }
16
+ end
17
+ end
16
18
 
17
- it "follows without changing verb" do
18
- redirector.perform(orig_request, orig_response) do |request|
19
- expect(request.verb).to be orig_request.verb
20
- simple_response 200
21
- end
19
+ describe "#max_hops" do
20
+ subject { redirector.max_hops }
21
+
22
+ context "by default" do
23
+ let(:redirector) { described_class.new }
24
+ it { is_expected.to eq 5 }
22
25
  end
23
26
  end
24
27
 
25
- context "following 301 redirect" do
26
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
27
- let(:orig_response) { redirect_response "http://example.com/", 301 }
28
+ describe "#perform" do
29
+ let(:options) { {} }
30
+ let(:redirector) { described_class.new options }
31
+
32
+ it "fails with TooManyRedirectsError if max hops reached" do
33
+ req = HTTP::Request.new :head, "http://example.com"
34
+ res = proc { |prev_req| redirect_response(301, "#{prev_req.uri}/1") }
35
+
36
+ expect { redirector.perform(req, res.call(req), &res) }
37
+ .to raise_error HTTP::Redirector::TooManyRedirectsError
38
+ end
39
+
40
+ it "fails with EndlessRedirectError if endless loop detected" do
41
+ req = HTTP::Request.new :head, "http://example.com"
42
+ res = redirect_response(301, req.uri)
43
+
44
+ expect { redirector.perform(req, res) { res } }
45
+ .to raise_error HTTP::Redirector::EndlessRedirectError
46
+ end
47
+
48
+ it "fails with StateError if there were no Location header" do
49
+ req = HTTP::Request.new :head, "http://example.com"
50
+ res = simple_response(301)
51
+
52
+ expect { |b| redirector.perform(req, res, &b) }
53
+ .to raise_error HTTP::StateError
54
+ end
55
+
56
+ it "returns first non-redirect response" do
57
+ req = HTTP::Request.new :head, "http://example.com"
58
+ hops = [
59
+ redirect_response(301, "http://example.com/1"),
60
+ redirect_response(301, "http://example.com/2"),
61
+ redirect_response(301, "http://example.com/3"),
62
+ simple_response(200, "foo"),
63
+ redirect_response(301, "http://example.com/4"),
64
+ simple_response(200, "bar")
65
+ ]
28
66
 
29
- it "follows without changing verb" do
30
- redirector.perform(orig_request, orig_response) do |request|
31
- expect(request.verb).to be orig_request.verb
32
- simple_response 200
67
+ res = redirector.perform(req, hops.shift) { hops.shift }
68
+ expect(res.to_s).to eq "foo"
69
+ end
70
+
71
+ context "following 300 redirect" do
72
+ context "with strict mode" do
73
+ let(:options) { {:strict => true} }
74
+
75
+ it "it follows with original verb if it's safe" do
76
+ req = HTTP::Request.new :head, "http://example.com"
77
+ res = redirect_response 300, "http://example.com/1"
78
+
79
+ redirector.perform(req, res) do |prev_req, _|
80
+ expect(prev_req.verb).to be :head
81
+ simple_response 200
82
+ end
83
+ end
84
+
85
+ it "raises StateError if original request was PUT" do
86
+ req = HTTP::Request.new :put, "http://example.com"
87
+ res = redirect_response 300, "http://example.com/1"
88
+
89
+ expect { redirector.perform(req, res) { simple_response 200 } }
90
+ .to raise_error HTTP::StateError
91
+ end
92
+
93
+ it "raises StateError if original request was POST" do
94
+ req = HTTP::Request.new :post, "http://example.com"
95
+ res = redirect_response 300, "http://example.com/1"
96
+
97
+ expect { redirector.perform(req, res) { simple_response 200 } }
98
+ .to raise_error HTTP::StateError
99
+ end
100
+
101
+ it "raises StateError if original request was DELETE" do
102
+ req = HTTP::Request.new :delete, "http://example.com"
103
+ res = redirect_response 300, "http://example.com/1"
104
+
105
+ expect { redirector.perform(req, res) { simple_response 200 } }
106
+ .to raise_error HTTP::StateError
107
+ end
108
+ end
109
+
110
+ context "with non-strict mode" do
111
+ let(:options) { {:strict => false} }
112
+
113
+ it "it follows with original verb if it's safe" do
114
+ req = HTTP::Request.new :head, "http://example.com"
115
+ res = redirect_response 300, "http://example.com/1"
116
+
117
+ redirector.perform(req, res) do |prev_req, _|
118
+ expect(prev_req.verb).to be :head
119
+ simple_response 200
120
+ end
121
+ end
122
+
123
+ it "it follows with GET if original request was PUT" do
124
+ req = HTTP::Request.new :put, "http://example.com"
125
+ res = redirect_response 300, "http://example.com/1"
126
+
127
+ redirector.perform(req, res) do |prev_req, _|
128
+ expect(prev_req.verb).to be :get
129
+ simple_response 200
130
+ end
131
+ end
132
+
133
+ it "it follows with GET if original request was POST" do
134
+ req = HTTP::Request.new :post, "http://example.com"
135
+ res = redirect_response 300, "http://example.com/1"
136
+
137
+ redirector.perform(req, res) do |prev_req, _|
138
+ expect(prev_req.verb).to be :get
139
+ simple_response 200
140
+ end
141
+ end
142
+
143
+ it "it follows with GET if original request was DELETE" do
144
+ req = HTTP::Request.new :delete, "http://example.com"
145
+ res = redirect_response 300, "http://example.com/1"
146
+
147
+ redirector.perform(req, res) do |prev_req, _|
148
+ expect(prev_req.verb).to be :get
149
+ simple_response 200
150
+ end
151
+ end
33
152
  end
34
153
  end
35
- end
36
154
 
37
- context "following 302 redirect" do
38
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
39
- let(:orig_response) { redirect_response "http://example.com/", 302 }
155
+ context "following 301 redirect" do
156
+ context "with strict mode" do
157
+ let(:options) { {:strict => true} }
158
+
159
+ it "it follows with original verb if it's safe" do
160
+ req = HTTP::Request.new :head, "http://example.com"
161
+ res = redirect_response 301, "http://example.com/1"
162
+
163
+ redirector.perform(req, res) do |prev_req, _|
164
+ expect(prev_req.verb).to be :head
165
+ simple_response 200
166
+ end
167
+ end
168
+
169
+ it "raises StateError if original request was PUT" do
170
+ req = HTTP::Request.new :put, "http://example.com"
171
+ res = redirect_response 301, "http://example.com/1"
172
+
173
+ expect { redirector.perform(req, res) { simple_response 200 } }
174
+ .to raise_error HTTP::StateError
175
+ end
176
+
177
+ it "raises StateError if original request was POST" do
178
+ req = HTTP::Request.new :post, "http://example.com"
179
+ res = redirect_response 301, "http://example.com/1"
180
+
181
+ expect { redirector.perform(req, res) { simple_response 200 } }
182
+ .to raise_error HTTP::StateError
183
+ end
184
+
185
+ it "raises StateError if original request was DELETE" do
186
+ req = HTTP::Request.new :delete, "http://example.com"
187
+ res = redirect_response 301, "http://example.com/1"
188
+
189
+ expect { redirector.perform(req, res) { simple_response 200 } }
190
+ .to raise_error HTTP::StateError
191
+ end
192
+ end
193
+
194
+ context "with non-strict mode" do
195
+ let(:options) { {:strict => false} }
196
+
197
+ it "it follows with original verb if it's safe" do
198
+ req = HTTP::Request.new :head, "http://example.com"
199
+ res = redirect_response 301, "http://example.com/1"
200
+
201
+ redirector.perform(req, res) do |prev_req, _|
202
+ expect(prev_req.verb).to be :head
203
+ simple_response 200
204
+ end
205
+ end
206
+
207
+ it "it follows with GET if original request was PUT" do
208
+ req = HTTP::Request.new :put, "http://example.com"
209
+ res = redirect_response 301, "http://example.com/1"
210
+
211
+ redirector.perform(req, res) do |prev_req, _|
212
+ expect(prev_req.verb).to be :get
213
+ simple_response 200
214
+ end
215
+ end
216
+
217
+ it "it follows with GET if original request was POST" do
218
+ req = HTTP::Request.new :post, "http://example.com"
219
+ res = redirect_response 301, "http://example.com/1"
220
+
221
+ redirector.perform(req, res) do |prev_req, _|
222
+ expect(prev_req.verb).to be :get
223
+ simple_response 200
224
+ end
225
+ end
40
226
 
41
- it "follows without changing verb" do
42
- redirector.perform(orig_request, orig_response) do |request|
43
- expect(request.verb).to be orig_request.verb
44
- simple_response 200
227
+ it "it follows with GET if original request was DELETE" do
228
+ req = HTTP::Request.new :delete, "http://example.com"
229
+ res = redirect_response 301, "http://example.com/1"
230
+
231
+ redirector.perform(req, res) do |prev_req, _|
232
+ expect(prev_req.verb).to be :get
233
+ simple_response 200
234
+ end
235
+ end
45
236
  end
46
237
  end
47
- end
48
238
 
49
- context "following 303 redirect" do
50
- context "upon POST request" do
51
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
52
- let(:orig_response) { redirect_response "http://example.com/", 303 }
239
+ context "following 302 redirect" do
240
+ context "with strict mode" do
241
+ let(:options) { {:strict => true} }
53
242
 
54
- it "follows without changing verb" do
55
- redirector.perform(orig_request, orig_response) do |request|
56
- expect(request.verb).to be :get
57
- simple_response 200
243
+ it "it follows with original verb if it's safe" do
244
+ req = HTTP::Request.new :head, "http://example.com"
245
+ res = redirect_response 302, "http://example.com/1"
246
+
247
+ redirector.perform(req, res) do |prev_req, _|
248
+ expect(prev_req.verb).to be :head
249
+ simple_response 200
250
+ end
251
+ end
252
+
253
+ it "raises StateError if original request was PUT" do
254
+ req = HTTP::Request.new :put, "http://example.com"
255
+ res = redirect_response 302, "http://example.com/1"
256
+
257
+ expect { redirector.perform(req, res) { simple_response 200 } }
258
+ .to raise_error HTTP::StateError
259
+ end
260
+
261
+ it "raises StateError if original request was POST" do
262
+ req = HTTP::Request.new :post, "http://example.com"
263
+ res = redirect_response 302, "http://example.com/1"
264
+
265
+ expect { redirector.perform(req, res) { simple_response 200 } }
266
+ .to raise_error HTTP::StateError
267
+ end
268
+
269
+ it "raises StateError if original request was DELETE" do
270
+ req = HTTP::Request.new :delete, "http://example.com"
271
+ res = redirect_response 302, "http://example.com/1"
272
+
273
+ expect { redirector.perform(req, res) { simple_response 200 } }
274
+ .to raise_error HTTP::StateError
275
+ end
276
+ end
277
+
278
+ context "with non-strict mode" do
279
+ let(:options) { {:strict => false} }
280
+
281
+ it "it follows with original verb if it's safe" do
282
+ req = HTTP::Request.new :head, "http://example.com"
283
+ res = redirect_response 302, "http://example.com/1"
284
+
285
+ redirector.perform(req, res) do |prev_req, _|
286
+ expect(prev_req.verb).to be :head
287
+ simple_response 200
288
+ end
289
+ end
290
+
291
+ it "it follows with GET if original request was PUT" do
292
+ req = HTTP::Request.new :put, "http://example.com"
293
+ res = redirect_response 302, "http://example.com/1"
294
+
295
+ redirector.perform(req, res) do |prev_req, _|
296
+ expect(prev_req.verb).to be :get
297
+ simple_response 200
298
+ end
299
+ end
300
+
301
+ it "it follows with GET if original request was POST" do
302
+ req = HTTP::Request.new :post, "http://example.com"
303
+ res = redirect_response 302, "http://example.com/1"
304
+
305
+ redirector.perform(req, res) do |prev_req, _|
306
+ expect(prev_req.verb).to be :get
307
+ simple_response 200
308
+ end
309
+ end
310
+
311
+ it "it follows with GET if original request was DELETE" do
312
+ req = HTTP::Request.new :delete, "http://example.com"
313
+ res = redirect_response 302, "http://example.com/1"
314
+
315
+ redirector.perform(req, res) do |prev_req, _|
316
+ expect(prev_req.verb).to be :get
317
+ simple_response 200
318
+ end
58
319
  end
59
320
  end
60
321
  end
61
322
 
62
- context "upon HEAD request" do
63
- let(:orig_request) { HTTP::Request.new :head, "http://www.example.com/" }
64
- let(:orig_response) { redirect_response "http://example.com/", 303 }
323
+ context "following 303 redirect" do
324
+ it "follows with HEAD if original request was HEAD" do
325
+ req = HTTP::Request.new :head, "http://example.com"
326
+ res = redirect_response 303, "http://example.com/1"
65
327
 
66
- it "follows without changing verb" do
67
- redirector.perform(orig_request, orig_response) do |request|
68
- expect(request.verb).to be :get
328
+ redirector.perform(req, res) do |prev_req, _|
329
+ expect(prev_req.verb).to be :head
330
+ simple_response 200
331
+ end
332
+ end
333
+
334
+ it "follows with GET if original request was GET" do
335
+ req = HTTP::Request.new :get, "http://example.com"
336
+ res = redirect_response 303, "http://example.com/1"
337
+
338
+ redirector.perform(req, res) do |prev_req, _|
339
+ expect(prev_req.verb).to be :get
340
+ simple_response 200
341
+ end
342
+ end
343
+
344
+ it "follows with GET if original request was neither GET nor HEAD" do
345
+ req = HTTP::Request.new :post, "http://example.com"
346
+ res = redirect_response 303, "http://example.com/1"
347
+
348
+ redirector.perform(req, res) do |prev_req, _|
349
+ expect(prev_req.verb).to be :get
69
350
  simple_response 200
70
351
  end
71
352
  end
72
353
  end
73
- end
74
354
 
75
- context "following 307 redirect" do
76
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
77
- let(:orig_response) { redirect_response "http://example.com/", 307 }
355
+ context "following 307 redirect" do
356
+ it "follows with original request's verb" do
357
+ req = HTTP::Request.new :post, "http://example.com"
358
+ res = redirect_response 307, "http://example.com/1"
78
359
 
79
- it "follows without changing verb" do
80
- redirector.perform(orig_request, orig_response) do |request|
81
- expect(request.verb).to be orig_request.verb
82
- simple_response 200
360
+ redirector.perform(req, res) do |prev_req, _|
361
+ expect(prev_req.verb).to be :post
362
+ simple_response 200
363
+ end
83
364
  end
84
365
  end
85
- end
86
366
 
87
- context "following 308 redirect" do
88
- let(:orig_request) { HTTP::Request.new :post, "http://www.example.com/" }
89
- let(:orig_response) { redirect_response "http://example.com/", 308 }
367
+ context "following 308 redirect" do
368
+ it "follows with original request's verb" do
369
+ req = HTTP::Request.new :post, "http://example.com"
370
+ res = redirect_response 308, "http://example.com/1"
90
371
 
91
- it "follows without changing verb" do
92
- redirector.perform(orig_request, orig_response) do |request|
93
- expect(request.verb).to be orig_request.verb
94
- simple_response 200
372
+ redirector.perform(req, res) do |prev_req, _|
373
+ expect(prev_req.verb).to be :post
374
+ simple_response 200
375
+ end
95
376
  end
96
377
  end
97
378
  end