lib/async/http/protocol/http1/server.rb in async-http-0.76.0 vs lib/async/http/protocol/http1/server.rb in async-http-0.77.0
- old
+ new
@@ -4,13 +4,15 @@
# Copyright, 2018-2024, by Samuel Williams.
# Copyright, 2020, by Igor Sidorov.
# Copyright, 2023, by Thomas Morgan.
# Copyright, 2024, by Anton Zhuravsky.
-require_relative 'connection'
-require 'console/event/failure'
+require_relative "connection"
+require_relative "../../body/finishable"
+require "console/event/failure"
+
module Async
module HTTP
module Protocol
module HTTP1
class Server < Connection
@@ -18,11 +20,11 @@
@persistent = false
write_response(@version, status, {})
write_body(@version, nil)
rescue => error
# At this point, there is very little we can do to recover:
- Console::Event::Failure.for(error).emit(self, "Failed to write failure response.", severity: :debug)
+ Console::Event::Failure.for(error).emit(self, "Failed to write failure response!", severity: :debug)
end
def next_request
# The default is true.
return unless @persistent
@@ -33,22 +35,28 @@
unless persistent?(request.version, request.method, request.headers)
@persistent = false
end
return request
- rescue ::Protocol::HTTP1::BadRequest
+ rescue ::Protocol::HTTP1::BadRequest => error
fail_request(400)
# Conceivably we could retry here, but we don't really know how bad the error is, so it's better to just fail:
raise
end
# Server loop.
def each(task: Task.current)
task.annotate("Reading #{self.version} requests for #{self.class}.")
while request = next_request
+ if body = request.body
+ finishable = Body::Finishable.new(body)
+ request.body = finishable
+ end
+
response = yield(request, self)
+ version = request.version
body = response&.body
if hijacked?
body&.close
return
@@ -75,11 +83,11 @@
return body.call(stream)
elsif response.status == 101
# This code path is to support legacy behavior where the response status is set to 101, but the protocol is not upgraded. This may not be a valid use case, but it is supported for compatibility. We expect the response headers to contain the `upgrade` header.
write_response(@version, response.status, response.headers)
- stream = write_tunnel_body(request.version)
+ stream = write_tunnel_body(version)
# Same as above:
request = nil
response = nil
@@ -87,39 +95,39 @@
return body&.call(stream)
else
write_response(@version, response.status, response.headers)
if request.connect? and response.success?
- stream = write_tunnel_body(request.version)
+ stream = write_tunnel_body(version)
# Same as above:
request = nil
response = nil
# We must return here as no further request processing can be done:
return body.call(stream)
else
head = request.head?
- version = request.version
# Same as above:
- request = nil unless request.body
+ request = nil
response = nil
write_body(version, body, head, trailer)
end
end
- # We are done with the body, you shouldn't need to call close on it:
+ # We are done with the body:
body = nil
else
# If the request failed to generate a response, it was an internal server error:
write_response(@version, 500, {})
- write_body(request.version, nil)
+ write_body(version, nil)
+
+ request&.finish
end
- # Gracefully finish reading the request body if it was not already done so.
- request&.each{}
+ finishable&.wait
# This ensures we yield at least once every iteration of the loop and allow other fibers to execute.
task.yield
rescue => error
raise