Skip to content

Commit 26858f5

Browse files
Close replaced error responses.
Assisted-By: devx/b3414b50-d642-461b-95a8-8f773c4d087b
1 parent cc9bb1e commit 26858f5

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

lib/utopia/redirection.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,25 @@ def call(request)
6262
response = Response.wrap(@delegate.call(request))
6363

6464
if unhandled_error?(response) && location = @codes[response.status]
65+
resource_status = response.status
66+
67+
# The original response is replaced by the configured error document:
68+
response.close
69+
6570
error_request = request.with(method: "GET", path_info: location)
6671

6772
error_response = Response.wrap(@delegate.call(error_request))
6873

6974
if error_response.status >= 400
70-
raise RequestFailure.new(request.path_info, response.status, location, error_response.status)
75+
error = RequestFailure.new(request.path_info, resource_status, location, error_response.status)
76+
77+
# The failed error document will not be returned to the server:
78+
error_response.close(error)
79+
80+
raise error
7181
else
7282
# Feed the error code back with the error document:
73-
error_response.status = response.status
83+
error_response.status = resource_status
7484
return error_response
7585
end
7686
else

test/utopia/redirection.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@
99
describe Utopia::Redirection do
1010
include ProtocolApplication
1111

12+
def tracked_body(name, events)
13+
body = Protocol::HTTP::Body::Buffered.wrap([name.to_s])
14+
15+
body.define_singleton_method(:close) do |error = nil|
16+
events << [name, error]
17+
super(error)
18+
end
19+
20+
return body
21+
end
22+
1223
let(:app) do
1324
Utopia::Application.build(lambda{|request|
1425
case request.path_info
@@ -72,10 +83,51 @@
7283
expect(body).to be == "File not found :("
7384
end
7485

86+
it "closes the response replaced by an error document" do
87+
events = []
88+
application = Utopia::Application.build(lambda do |request|
89+
if request.path_info == "/error"
90+
Utopia::Response[200, {}, tracked_body(:error, events)]
91+
else
92+
Utopia::Response[404, {}, tracked_body(:original, events)]
93+
end
94+
end) do
95+
use Utopia::Redirection::Errors, 404 => "/error"
96+
end
97+
98+
response = application.call(Protocol::HTTP::Request["GET", "/missing"])
99+
100+
expect(response.status).to be == 404
101+
expect(events).to be == [[:original, nil]]
102+
expect(response.read).to be == "error"
103+
end
104+
75105
it "should blow up if internal error redirect also fails" do
76106
expect{get "/teapot"}.to raise_exception Utopia::Redirection::RequestFailure
77107
end
78108

109+
it "closes both responses when the error document fails" do
110+
events = []
111+
application = Utopia::Application.build(lambda do |request|
112+
if request.path_info == "/error"
113+
Utopia::Response[500, {}, tracked_body(:error, events)]
114+
else
115+
Utopia::Response[404, {}, tracked_body(:original, events)]
116+
end
117+
end) do
118+
use Utopia::Redirection::Errors, 404 => "/error"
119+
end
120+
121+
expect do
122+
application.call(Protocol::HTTP::Request["GET", "/missing"])
123+
end.to raise_exception(Utopia::Redirection::RequestFailure)
124+
125+
expect(events.size).to be == 2
126+
expect(events[0]).to be == [:original, nil]
127+
expect(events[1][0]).to be == :error
128+
expect(events[1][1]).to be_a(Utopia::Redirection::RequestFailure)
129+
end
130+
79131
it "should redirect deep url to top" do
80132
get "/hierarchy/a/b/c/d/e"
81133

0 commit comments

Comments
 (0)