Class: Hyperion::ResponseWriter
- Inherits:
-
Object
- Object
- Hyperion::ResponseWriter
- Defined in:
- lib/hyperion/response_writer.rb
Overview
Serializes a Rack [status, headers, body] tuple to an HTTP/1.1 wire stream. Phase 5 replaces this with an io_buffer-batched writer; Phase 7 adds a sibling Http2ResponseWriter. Public surface (#write) stays stable.
Constant Summary collapse
- REASONS =
{ 200 => 'OK', 201 => 'Created', 204 => 'No Content', 301 => 'Moved Permanently', 302 => 'Found', 304 => 'Not Modified', 400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 413 => 'Payload Too Large', 414 => 'URI Too Long', 422 => 'Unprocessable Entity', 429 => 'Too Many Requests', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout' }.freeze
- CRLF_HEADER_VALUE =
/[\r\n]/
Instance Method Summary collapse
Instance Method Details
#write(io, status, headers, body, keep_alive: false) ⇒ Object
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 |
# File 'lib/hyperion/response_writer.rb', line 38 def write(io, status, headers, body, keep_alive: false) # Phase 1 buffers the full body so Content-Length is exact. # Phase 2 introduces chunked transfer-encoding for streaming bodies; # Phase 5 batches via IO::Buffer to avoid this intermediate String. buffered = +'' body.each { |chunk| buffered << chunk } reason = REASONS[status] || 'Unknown' date_str = Time.now.httpdate head = build_head(status, reason, headers, buffered.bytesize, keep_alive, date_str) # Phase 8 perf fix: coalesce status line + all headers + body into a # SINGLE io.write call. Each syscall round-trip is ~1 usec on macOS # kqueue; before this change we issued (1 status) + (N headers) + (1 blank) # + (1 body) = 8+ syscalls per response. Now: 1 syscall. if buffered.empty? io.write(head) else # Concatenate into the head buffer (which is already a fresh +'' from # the C builder or the Ruby fallback) so we still emit a single write. head << buffered io.write(head) end ensure body.close if body.respond_to?(:close) end |