Hypersonic
view release on metacpan or search on metacpan
lib/Hypersonic/Protocol/HTTP1.pm view on Meta::CPAN
sub gen_keepalive_check {
my ($class, $builder) = @_;
$builder->comment('HTTP/1.1: Check Connection header for keep-alive')
->line('int keep_alive = 1;') # HTTP/1.1 default is keep-alive
->if('len > 20')
->comment('Search for "Connection:" header (case-insensitive C or c)')
->line('const char* conn = strstr(recv_buf + 16, "onnection:");')
->if('conn && (conn[-1] == \'C\' || conn[-1] == \'c\')')
->if('strstr(conn, "close") || strstr(conn, "Close")')
->line('keep_alive = 0;')
->endif
->endif
->endif;
return $builder;
}
# Status code to text mapping (complete list)
sub _status_text {
my ($code) = @_;
my %text = (
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
204 => 'No Content',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
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',
415 => 'Unsupported Media Type',
422 => 'Unprocessable Entity',
429 => 'Too Many Requests',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
);
return $text{$code} // 'Unknown';
}
# Get status text (class method for external use)
sub status_text {
my ($class, $code) = @_;
return _status_text($code);
}
# ============================================================
# Chunked Transfer Encoding (HTTP/1.1 streaming)
# ============================================================
# Generate C code for chunked response headers
sub gen_chunked_start {
my ($class, $builder) = @_;
$builder->comment('Send HTTP/1.1 headers with chunked encoding')
->line('static void send_chunked_headers(int fd, int status, const char* content_type) {')
->line(' char headers[2048];')
->line(' const char* status_str = "OK";')
->line(' switch(status) {')
->line(' case 200: status_str = "OK"; break;')
->line(' case 201: status_str = "Created"; break;')
->line(' case 202: status_str = "Accepted"; break;')
->line(' case 204: status_str = "No Content"; break;')
->line(' case 206: status_str = "Partial Content"; break;')
->line(' case 400: status_str = "Bad Request"; break;')
->line(' case 401: status_str = "Unauthorized"; break;')
->line(' case 403: status_str = "Forbidden"; break;')
->line(' case 404: status_str = "Not Found"; break;')
->line(' case 500: status_str = "Internal Server Error"; break;')
->line(' case 503: status_str = "Service Unavailable"; break;')
->line(' }')
->line(' int len = snprintf(headers, sizeof(headers),')
->line(' "HTTP/1.1 %d %s\\r\\n"')
->line(' "Content-Type: %s\\r\\n"')
->line(' "Transfer-Encoding: chunked\\r\\n"')
->line(' "Connection: keep-alive\\r\\n"')
->line(' "\\r\\n",')
->line(' status, status_str, content_type);')
->line(' send(fd, headers, len, 0);')
->line('}')
->blank;
return $builder;
}
# Generate C code for sending a chunk (hex length + data + CRLF)
sub gen_chunked_write {
my ($class, $builder) = @_;
$builder->comment('Send a single chunk - HTTP/1.1 chunked transfer encoding')
->line('static void send_chunk(int fd, const char* data, size_t len) {')
->line(' if (len == 0) return;')
->line(' ')
->line(' char size_line[32];')
->line(' int header_len = snprintf(size_line, sizeof(size_line), "%zx\\r\\n", len);')
->line(' ')
->line(' /* Use writev for efficiency (header + data + crlf in one syscall) */')
->line(' struct iovec iov[3];')
->line(' iov[0].iov_base = size_line;')
->line(' iov[0].iov_len = header_len;')
->line(' iov[1].iov_base = (void*)data;')
->line(' iov[1].iov_len = len;')
->line(' iov[2].iov_base = "\\r\\n";')
->line(' iov[2].iov_len = 2;')
->line(' ')
->line(' writev(fd, iov, 3);')
->line('}')
->blank;
( run in 0.527 second using v1.01-cache-2.11-cpan-140bd7fdf52 )