Hypersonic

 view release on metacpan or  search on metacpan

lib/Hypersonic/Protocol/HTTP2.pm  view on Meta::CPAN

      ->line('    char cl_buf[16];')
      ->line('    snprintf(cl_buf, sizeof(cl_buf), "%d", body_len);')
      ->line('    ')
      ->line('    /* Build status string */')
      ->line('    char status_buf[4];')
      ->line('    snprintf(status_buf, sizeof(status_buf), "%d", status);')
      ->line('    ')
      ->line('    /* Submit HTTP/2 response headers */')
      ->line('    nghttp2_nv hdrs[] = {')
      ->line('        { (uint8_t*)":status", (uint8_t*)status_buf, 7, strlen(status_buf), NGHTTP2_NV_FLAG_NONE },')
      ->line('        { (uint8_t*)"content-type", (uint8_t*)ct, 12, strlen(ct), NGHTTP2_NV_FLAG_NONE },')
      ->line('        { (uint8_t*)"content-length", (uint8_t*)cl_buf, 14, strlen(cl_buf), NGHTTP2_NV_FLAG_NONE },')
      ->line('    };')
      ->line('    ')
      ->line('    /* Create data provider for body */')
      ->line('    nghttp2_data_provider data_prd;')
      ->line('    data_prd.source.ptr = (void*)body;')
      ->line('    data_prd.read_callback = h2_data_source_read_cb;')
      ->line('    ')
      ->line('    nghttp2_submit_response(session, stream_id, hdrs, 3, &data_prd);')
      ->line('    nghttp2_session_send(session);')

lib/Hypersonic/Protocol/HTTP2.pm  view on Meta::CPAN

# Generate 404 response for HTTP/2
sub gen_404_response {
    my ($class, $builder) = @_;
    
    $builder->comment('HTTP/2: Send 404 response')
      ->line('static void h2_send_404(nghttp2_session* session, int32_t stream_id) {')
      ->line('    static const char* body = "Not Found";')
      ->line('    ')
      ->line('    nghttp2_nv hdrs[] = {')
      ->line('        { (uint8_t*)":status", (uint8_t*)"404", 7, 3, NGHTTP2_NV_FLAG_NONE },')
      ->line('        { (uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE },')
      ->line('        { (uint8_t*)"content-length", (uint8_t*)"9", 14, 1, NGHTTP2_NV_FLAG_NONE },')
      ->line('    };')
      ->line('    ')
      ->line('    nghttp2_data_provider data_prd;')
      ->line('    data_prd.source.ptr = (void*)body;')
      ->line('    data_prd.read_callback = h2_data_source_read_cb;')
      ->line('    ')
      ->line('    nghttp2_submit_response(session, stream_id, hdrs, 3, &data_prd);')
      ->line('    nghttp2_session_send(session);')
      ->line('}')

lib/Hypersonic/Protocol/HTTP2.pm  view on Meta::CPAN

    my ($class, $builder) = @_;
    
    $builder->comment('HTTP/2 Streaming: Send HEADERS without END_STREAM (allows more DATA)')
      ->line('static int h2_stream_headers(nghttp2_session* session, int32_t stream_id,')
      ->line('                              int status, const char* content_type) {')
      ->line('    char status_str[4];')
      ->line('    snprintf(status_str, sizeof(status_str), "%d", status);')
      ->line('    ')
      ->line('    nghttp2_nv hdrs[] = {')
      ->line('        { (uint8_t*)":status", (uint8_t*)status_str, 7, strlen(status_str), NGHTTP2_NV_FLAG_NONE },')
      ->line('        { (uint8_t*)"content-type", (uint8_t*)content_type, 12, strlen(content_type), NGHTTP2_NV_FLAG_NONE },')
      ->line('    };')
      ->line('    ')
      ->line('    /* Submit headers WITHOUT END_STREAM - more DATA frames to come */')
      ->line('    int rv = nghttp2_submit_headers(session, NGHTTP2_FLAG_END_HEADERS,')
      ->line('                                     stream_id, NULL, hdrs, 2, NULL);')
      ->line('    if (rv < 0) return rv;')
      ->line('    ')
      ->line('    return nghttp2_session_send(session);')
      ->line('}')
      ->blank;

lib/Hypersonic/Stream.pm  view on Meta::CPAN

      ->endif
      ->blank
      ->line('s->extra_headers[0] = \'\\0\';')
      ->if('items >= 3 && SvROK(ST(2)) && SvTYPE(SvRV(ST(2))) == SVt_PVHV')
        ->line('HV* hv = (HV*)SvRV(ST(2));')
        ->line('int extra_pos = 0;')
        ->blank
        ->comment('Extract Content-Type')
        ->line('SV** ct = hv_fetchs(hv, "Content-Type", 0);')
        ->if('!ct')
          ->line('ct = hv_fetchs(hv, "content-type", 0);')
        ->endif
        ->if('ct && *ct')
          ->line('STRLEN len;')
          ->line('const char* val = SvPV(*ct, len);')
          ->if('len < sizeof(s->content_type)')
            ->line('memcpy(s->content_type, val, len);')
            ->line('s->content_type[len] = \'\\0\';')
          ->endif
        ->endif
        ->blank

t/0027-chunked-encoding.t  view on Meta::CPAN

    plan tests => 5;
    
    require XS::JIT::Builder;
    my $builder = XS::JIT::Builder->new;
    
    Hypersonic::Protocol::HTTP1->gen_chunked_start($builder);
    my $code = $builder->code;
    
    like($code, qr/void send_chunked_headers\(/, 'function defined');
    like($code, qr/Transfer-Encoding: chunked/, 'chunked header included');
    like($code, qr/Content-Type: %s/, 'content-type placeholder');
    like($code, qr/Connection: keep-alive/, 'keep-alive for streaming');
    like($code, qr/send\(fd, headers/, 'sends headers');
};

subtest 'gen_chunked_write uses writev' => sub {
    plan tests => 4;
    
    require XS::JIT::Builder;
    my $builder = XS::JIT::Builder->new;
    

t/0027-chunked-encoding.t  view on Meta::CPAN

    plan tests => 3;

    require XS::JIT::Builder;
    my $builder = XS::JIT::Builder->new;

    Hypersonic::Stream->gen_stream_start_c($builder);
    my $code = $builder->code;

    like($code, qr/Transfer-Encoding: chunked/, 'chunked header');
    like($code, qr/HTTP\/1\.1 %d %s/, 'HTTP/1.1 status line');
    like($code, qr/Content-Type: %s/, 'content-type included');
};

subtest 'Stream generates chunk writes with writev' => sub {
    plan tests => 2;

    require XS::JIT::Builder;
    my $builder = XS::JIT::Builder->new;

    Hypersonic::Stream->gen_stream_write_chunk_c($builder);
    my $code = $builder->code;

t/0029-sse.t  view on Meta::CPAN

};

subtest 'SSE headers set on start' => sub {
    plan tests => 2;
    
    my $mock_stream = MockStream4->new;
    
    my $sse = Hypersonic::SSE->new($mock_stream);
    $sse->event(data => 'test');
    
    is($MockStream4::headers_set->{'Content-Type'}, 'text/event-stream', 'content-type set');
    is($MockStream4::headers_set->{'Cache-Control'}, 'no-cache', 'cache-control set');
};

# ============================================================
# Test 18-20: RFC compliance edge cases
# ============================================================
subtest 'Event with empty data' => sub {
    plan tests => 2;
    
    my $event = Hypersonic::Protocol::SSE->format_event(data => '');



( run in 1.384 second using v1.01-cache-2.11-cpan-524268b4103 )