Class: Hook0::Transport
- Inherits:
-
Object
- Object
- Hook0::Transport
- Defined in:
- lib/hook0/transport.rb
Overview
How a request reaches the API, and what a server on the other end is not allowed to cost.
The transport answers the status and the bytes and knows nothing of what the API declares: reading those bytes is the generated half's job, and deciding whether to send them again is the client's. That is what lets one HTTP implementation serve both the hand-written event path and every generated method — a generated group calls whatever object it is handed, and this is the one this gem ships.
Nothing here reaches for a third-party HTTP library. Everything a server controls is bounded: how long one exchange may take, and how many bytes of body are read off the socket.
Constant Summary collapse
- DEFAULT_REQUEST_TIMEOUT =
Longest one attempt at reaching the API is given before it is abandoned, in seconds.
Ten seconds is far above what ingesting an event takes when the API is healthy, and short enough that a stuck connection does not hold a caller for a noticeable time.
10.0- DEFAULT_MAX_RESPONSE_BYTES =
Largest response body read off a socket, in bytes.
8 * 1024 * 1024
- DEFAULT_MAX_RESPONSE_HEADERS =
How many header lines an answer may carry before it is refused.
Net::HTTPbounds neither how many header lines it accepts nor how long one may be: it holds fifty thousand of them, and a single value of eight megabytes, without complaint. So the head of an answer is a server-controlled way to spend a caller's memory, and the ceiling has to be this client's own. Sixty-four is well above what the API sends. 64- DEFAULT_MAX_HEADER_BYTES =
Longest one header line may be, name and value together, in bytes.
64 * 1024
- DEFAULT_MAX_HEAD_BYTES =
Largest whole head an answer may carry, every line counted together, in bytes.
This is the one that bounds what a head costs. A line count and a size per line multiply: sixty-four lines of sixty-four kilobytes each is four megabytes of head, and both of the bounds above admit it. They earn their place by refusing early, on the line that crosses them rather than at the end of the head; this one sets the ceiling.
Sixteen kilobytes is what Node enforces by default, and matching it is the point: a lower ceiling would refuse heads another target accepts, and a higher one would not bind there at all, leaving each language a different effective limit.
16 * 1024
- JSON_MEDIA_TYPE =
What a request body says it carries, and what an answer is asked for in.
"application/json"- SCHEMES =
The schemes this transport reaches.
%w[http https].freeze
- UNREACHABLE =
What the standard library reports when the API was not reached at all.
[ IOError, SocketError, SystemCallError, Timeout::Error, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError ].freeze
Instance Method Summary collapse
-
#deliver(method, path, query = [], body = nil) ⇒ Array(Integer, Hash{String => String}, String)
What the API answered, headers included, whether or not it answered a success.
-
#initialize(base_url, token, timeout: DEFAULT_REQUEST_TIMEOUT, max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES, max_response_headers: DEFAULT_MAX_RESPONSE_HEADERS, max_header_bytes: DEFAULT_MAX_HEADER_BYTES, max_head_bytes: DEFAULT_MAX_HEAD_BYTES, retry_policy: RetryPolicy.new) ⇒ Transport
constructor
A new instance of Transport.
-
#request(method, path, query = [], body = nil) ⇒ Array(Integer, String)
What the API answered, whether or not it answered a success.
Constructor Details
#initialize(base_url, token, timeout: DEFAULT_REQUEST_TIMEOUT, max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES, max_response_headers: DEFAULT_MAX_RESPONSE_HEADERS, max_header_bytes: DEFAULT_MAX_HEADER_BYTES, max_head_bytes: DEFAULT_MAX_HEAD_BYTES, retry_policy: RetryPolicy.new) ⇒ Transport
Returns a new instance of Transport.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/hook0/transport.rb', line 170 def initialize( base_url, token, timeout: DEFAULT_REQUEST_TIMEOUT, max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES, max_response_headers: DEFAULT_MAX_RESPONSE_HEADERS, max_header_bytes: DEFAULT_MAX_HEADER_BYTES, max_head_bytes: DEFAULT_MAX_HEAD_BYTES, retry_policy: RetryPolicy.new ) @base_url = base_url @token = token @timeout = timeout @max_response_bytes = max_response_bytes @max_response_headers = max_response_headers @max_header_bytes = max_header_bytes @max_head_bytes = max_head_bytes @retry_policy = retry_policy end |
Instance Method Details
#deliver(method, path, query = [], body = nil) ⇒ Array(Integer, Hash{String => String}, String)
What the API answered, headers included, whether or not it answered a success.
Header names are lowercased and a later value wins over an earlier one under the same name, so a caller reads a header without knowing which case the server wrote it in.
218 219 220 221 |
# File 'lib/hook0/transport.rb', line 218 def deliver(method, path, query = [], body = nil) target = resolved(path, query) exchange(target, built(method, target, body)) end |
#request(method, path, query = [], body = nil) ⇒ Array(Integer, String)
What the API answered, whether or not it answered a success.
This is the shape the generated half of this gem reads, which is the status and the bytes. A caller that also needs what the answer carried beside its body — the delay a paced instance names is one — asks #deliver for it.
202 203 204 205 |
# File 'lib/hook0/transport.rb', line 202 def request(method, path, query = [], body = nil) status, _, payload = deliver(method, path, query, body) [status, payload] end |