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 )