1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| | use Rack::Lint
use Rack::ContentLength
use Rack::ContentType, "text/plain"
class DieIfUsed
def each
abort "body.each called after response hijack\n"
end
def close
abort "body.close called after response hijack\n"
end
end
def lazy_close(io)
thr = Thread.new do
# wait and see if Rainbows! accidentally closes us
sleep((ENV["DELAY"] || 10).to_i)
begin
io.close
rescue => e
warn "E: #{e.message} (#{e.class})"
exit!(3)
end
end
at_exit { thr.join }
end
run lambda { |env|
case env["PATH_INFO"]
when "/hijack_req"
if env["rack.hijack?"]
io = env["rack.hijack"].call
if io.respond_to?(:read_nonblock) &&
env["rack.hijack_io"].respond_to?(:read_nonblock)
# exercise both, since we Rack::Lint may use different objects
env["rack.hijack_io"].write("HTTP/1.0 200 OK\r\n\r\n")
io.write("request.hijacked")
lazy_close(io)
return [ 500, {}, DieIfUsed.new ]
end
end
[ 500, {}, [ "hijack BAD\n" ] ]
when "/hijack_res"
r = "response.hijacked"
[ 200,
{
"Content-Length" => r.bytesize.to_s,
"rack.hijack" => proc do |sock|
io.write(r)
lazy_close(sock)
end
},
DieIfUsed.new
]
end
}
|