1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Add support for the rack hijack protocol

This commit is contained in:
Evan Phoenix 2013-02-05 22:39:16 -08:00
parent 804a6e2c20
commit daa76a1e90
6 changed files with 51 additions and 7 deletions

View file

@ -36,14 +36,22 @@ module Puma
@timeout_at = nil
@requests_served = 0
@hijacked = false
end
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked
def inspect
"#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
end
# For the hijack protocol (allows us to just put the Client object
# into the env)
def call
@hijacked = true
env[HIJACK_IO] ||= @io
end
def set_timeout(val)
@timeout_at = Time.now + val
end

View file

@ -147,5 +147,9 @@ module Puma
COLON = ": ".freeze
NEWLINE = "\n".freeze
HIJACK_P = "rack.hijack?".freeze
HIJACK = "rack.hijack".freeze
HIJACK_IO = "rack.hijack_io".freeze
end
end

View file

@ -332,6 +332,9 @@ module Puma
env[PUMA_SOCKET] = client
env[HIJACK_P] = true
env[HIJACK] = req
body = req.body
env[RACK_INPUT] = body
@ -345,6 +348,9 @@ module Puma
begin
begin
status, headers, res_body = @app.call(env)
return :async if req.hijacked
status = status.to_i
if status == -1
@ -406,6 +412,8 @@ module Puma
end
end
response_hijack = nil
headers.each do |k, vs|
case k
when CONTENT_LENGTH2
@ -416,6 +424,9 @@ module Puma
content_length = nil
when CONTENT_TYPE
next if no_body
when HIJACK
response_hijack = vs
next
end
vs.split(NEWLINE).each do |v|
@ -435,18 +446,25 @@ module Puma
lines << CONNECTION_CLOSE
end
if content_length
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
chunked = false
elsif allow_chunked
lines << TRANSFER_ENCODING_CHUNKED
chunked = true
unless response_hijack
if content_length
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
chunked = false
elsif allow_chunked
lines << TRANSFER_ENCODING_CHUNKED
chunked = true
end
end
lines << line_ending
fast_write client, lines.to_s
if response_hijack
response_hijack.call client
return :async
end
res_body.each do |part|
if chunked
client.syswrite part.bytesize.to_s(16)

3
test/hello-delay.ru Normal file
View file

@ -0,0 +1,3 @@
sleep 5
run lambda { |env| [200, {"Content-Type" => "text/plain"}, ["Hello World"]] }

6
test/hijack.ru Normal file
View file

@ -0,0 +1,6 @@
run lambda { |env|
io = env['rack.hijack'].call
io.puts "HTTP/1.1 200\r\n\r\nBLAH"
[-1, {}, []]
}

5
test/hijack2.ru Normal file
View file

@ -0,0 +1,5 @@
run lambda { |env|
body = lambda { |io| io.puts "BLAH\n"; io.close }
[200, { 'rack.hijack' => body }, []]
}