Class: Async::HTTP::Protocol::HTTP1::Client
- Inherits:
-
Connection
- Object
- Protocol::HTTP1::Connection
- Connection
- Async::HTTP::Protocol::HTTP1::Client
- Defined in:
- lib/async/http/protocol/http1/client.rb
Instance Attribute Summary
Attributes inherited from Connection
Instance Method Summary collapse
-
#call(request, task: Task.current) ⇒ Object
Used by the client to send requests to the remote server.
Methods inherited from Connection
#as_json, #concurrency, #http1?, #http2?, #initialize, #peer, #read_line, #read_line?, #reusable?, #to_json, #to_s, #viable?
Constructor Details
This class inherits a constructor from Async::HTTP::Protocol::HTTP1::Connection
Instance Method Details
#call(request, task: Task.current) ⇒ Object
Used by the client to send requests to the remote server.
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 57 58 59 60 61 62 63 64 65 |
# File 'lib/async/http/protocol/http1/client.rb', line 14 def call(request, task: Task.current) # We need to keep track of connections which are not in the initial "ready" state. @ready = false Console.logger.debug(self) {"#{request.method} #{request.path} #{request.headers.inspect}"} # Mark the start of the trailers: trailer = request.headers.trailer! # We carefully interpret https://tools.ietf.org/html/rfc7230#section-6.3.1 to implement this correctly. begin write_request(request., request.method, request.path, @version, request.headers) rescue # If we fail to fully write the request and body, we can retry this request. raise RequestFailed end if request.body? body = request.body if protocol = request.protocol # This is a very tricky apect of handling HTTP/1 upgrade connections. In theory, this approach is a bit inefficient, because we spin up a task just to handle writing to the underlying stream when we could be writing to the stream directly. But we need to maintain some level of compatibility with HTTP/2. Additionally, we don't know if the upgrade request will be accepted, so starting to write the body at this point needs to be handled with care. task.async(annotation: "Upgrading request...") do # If this fails, this connection will be closed. write_upgrade_body(protocol, body) end elsif request.connect? task.async(annotation: "Tunnneling request...") do write_tunnel_body(@version, body) end else task.async(annotation: "Streaming request...") do # Once we start writing the body, we can't recover if the request fails. That's because the body might be generated dynamically, streaming, etc. write_body(@version, body, false, trailer) end end elsif protocol = request.protocol write_upgrade_body(protocol) else write_body(@version, body, false, trailer) end response = Response.read(self, request) @ready = true return response rescue # This will ensure that #reusable? returns false. @stream.close raise end |