-
Hey folks, I'm a bit confused about socket hijacking in Rack 3. I should mention I'm fairly new to working with Rack directly. The spec says:
My understanding is that the usage of these headers has changed in Rack 3, as the upgrade guide says:
My first question is: does the spec need to be updated? Secondly, my confusion lies in the behaviour of the two kinds of hijacking. Am I right in saying that partial hijacking writes HTTP response headers to the socket, whereas full hijacking does not? If my above statement is correct, then should the following code write HTTP response headers since it's a "full hijack" as per the Rack 3 spec? body = proc do |stream|
5.times do
stream.write "#{Time.now}\n\n"
sleep 1
end
ensure
stream.close
end
[200, { "content-type" => "text/plain", "rack.hijack" => body }, []] I tested that on Puma and Falcon and both servers wrote HTTP headers back to the client before streaming the body. I'd appreciate any clarification :). Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
What do you think needs to be updated?
That's correct. The example you give is a partial hijack. However, it's better to write it like this now: [200, {"content-type" => "text/plain"}, body] Full hijack is very difficult to use correctly and impossible for HTTP/2+, I advise you don't use it. To use full hijack, you'd write code like this: if io = env['rack.hijack']&.call
io.write("connection: close\r\n\r\nHello World\r\n")
io.close
end |
Beta Was this translation helpful? Give feedback.
-
Sorry I should've been clearer. I think these two lines in the spec need updating?
The upgrade guide says:
And the changelog says:
The language in the spec makes me think
Ahh right, thanks! Yeah I'm aware of streaming bodies, and also that full hijacking is a bad idea. My curiosity here is largely academic to try and understand what's what. Your talk at RubyKaigi 2022 sent me down this rabbit hole! (Fantastic talk btw!) Thanks for the help :) |
Beta Was this translation helpful? Give feedback.
-
Let's step back a little bit. In Rack 2, there was no way to advertise support for only partial hijack or only full hijack. The presence and truthiness of
This is enforced by Let's clarify what's actually required:
Full and partial hijack are distinct operations and there is no real dependency between them. More specifically, all HTTP versions can support partial hijack, but not all versions can (easily) support full hijack - the expectations of full hijack is that you'd write response headers using the HTTP/1 protocol, but HTTP/2 isn't a stream based protocol (trying to call In Rack 3, streaming response body is always supported and a requirement of Rack 3, which is Because full hijack and partial hijack are actually distinct operations, and because Rails depends on full hijack, I did need to support it in So, from the changelog:
Yes, this is true, the cases are:
Both of these are independent of each other. But in Rack 2, that was not the case (as per The upgrade guide states this clearly and also tries to guide users to wards streaming response bodies (because they are slightly more ergonomic from an interface POV):
This is stating that previously This is outlined in the Rack specification (derived from the Rack 3
The above statement refers to the case (1).
This implies that applications should NOT set the response header Does this clarify things for you or am I mis-understanding something? Let me make one more clarification, (1) talks about a response header called |
Beta Was this translation helpful? Give feedback.
Let's step back a little bit.
In Rack 2, there was no way to advertise support for only partial hijack or only full hijack. The presence and truthiness of
env['rack.hijack?']
implied:[200, {'rack.hijack' => body}, nil]
.env['rack.hijack']
is available for full hijack.This is enforced by
Rack::Lint
.Let's clarify what's actually required:
env['rack.hijack?']
.env['rack.hijack']
. The mere presence of that field is sufficient to indicate that full hijack is possible.Full and partial hijack are distinct operati…