NAME

Net::HTTP2::nghttp2::Session - HTTP/2 session management

SYNOPSIS

use Net::HTTP2::nghttp2::Session;

my $session = Net::HTTP2::nghttp2::Session->new_server(
    callbacks => {
        on_begin_headers => sub {
            my ($session, $stream_id) = @_;
            # New stream started
        },
        on_header => sub {
            my ($session, $stream_id, $name, $value, $flags) = @_;
            # Header received
        },
        on_frame_recv => sub {
            my ($session, $frame) = @_;
            # Frame received
        },
        on_stream_close => sub {
            my ($session, $stream_id, $error_code) = @_;
            # Stream closed
        },
        on_data_chunk_recv => sub {
            my ($session, $stream_id, $data, $flags) = @_;
            # Body data received
        },
    },
);

# Send connection preface
$session->send_connection_preface(
    max_concurrent_streams => 100,
);

# Process incoming data
$session->mem_recv($incoming_bytes);

# Get outgoing data to send
my $outgoing = $session->mem_send();

# Submit a response
$session->submit_response($stream_id,
    status  => 200,
    headers => [
        ['content-type', 'text/html'],
    ],
    body => '<html>...</html>',
);

METHODS

new_server

my $session = Net::HTTP2::nghttp2::Session->new_server(%args);

Create a new server-side HTTP/2 session.

Arguments:

callbacks

Hashref of callback handlers. Required callbacks: on_begin_headers, on_header, on_frame_recv. Optional: on_data_chunk_recv, on_stream_close.

user_data

Optional scalar passed to callbacks.

settings

Optional hashref of initial HTTP/2 settings.

new_client

my $session = Net::HTTP2::nghttp2::Session->new_client(%args);

Create a new client-side HTTP/2 session.

Arguments:

callbacks

Hashref of callback handlers. Recommended: on_header, on_data_chunk_recv, on_stream_close.

user_data

Optional scalar passed to callbacks.

send_connection_preface

$session->send_connection_preface(%settings);

Send HTTP/2 connection preface (SETTINGS frame). Default settings: max_concurrent_streams => 100, initial_window_size => 65535.

Additional settings:

enable_connect_protocol

Set to 1 to advertise RFC 8441 extended CONNECT support (SETTINGS_ENABLE_CONNECT_PROTOCOL). Required for WebSocket over HTTP/2.

mem_recv

my $consumed = $session->mem_recv($data);

Feed incoming data to the session. Returns number of bytes consumed. Triggers registered callbacks as frames are parsed.

mem_send

my $data = $session->mem_send();

Get outgoing data from the session. Returns bytes to send to peer (empty string if nothing pending).

submit_request

my $stream_id = $session->submit_request(%args);

Submit an HTTP/2 request (client-side). Returns the stream ID.

Arguments:

method

HTTP method. Default: 'GET'.

path

Request path. Default: '/'.

scheme

URL scheme. Default: 'https'.

authority

Host authority (e.g. 'example.com').

headers

Arrayref of [$name, $value] pairs for additional headers (including pseudo-headers like :protocol for RFC 8441 extended CONNECT).

body

Request body. Can be:

undef (or omitted)

No body. HEADERS frame sent with END_STREAM.

String

Static body. Sent as DATA frame(s) with END_STREAM after the last frame.

CODE ref

Streaming callback for bidirectional streams. The callback receives ($stream_id, $max_length) and must return one of:

($data, $eof_flag)

Send $data as a DATA frame. If $eof_flag is true, END_STREAM is set.

undef

Defer data production. Call resume_stream($stream_id) when data is ready.

This is required for protocols that keep the stream open for bidirectional exchange, such as WebSocket over HTTP/2 (RFC 8441 extended CONNECT).

submit_response

$session->submit_response($stream_id, %args);

Submit an HTTP/2 response on the given stream.

Arguments:

status

HTTP status code. Default: 200.

headers

Arrayref of [$name, $value] pairs.

body

Response body. Same types as submit_request: undef (no body), string (static body), or CODE ref (streaming callback with identical signature).

data_callback

Alternative to passing a CODE ref as body. Callback with the same streaming signature.

callback_data

Optional user data passed as third argument to the streaming callback.

submit_push_promise

my $promised_stream_id = $session->submit_push_promise($stream_id, %args);

Submit a server push promise.

submit_data

$session->submit_data($stream_id, $data, $eof);

Push data directly onto an existing stream. The stream must already have a data provider (established by submit_request or submit_response with a CODE ref or data_callback). This replaces the streaming callback with a one-shot static body, then resumes the stream.

Arguments:

$stream_id

The stream to send data on.

$data

The data to send. Can be undef for an empty DATA frame.

$eof

If true, the DATA frame will include END_STREAM, closing the stream.

This is useful when you have data available outside the streaming callback context and want to push it directly, such as forwarding WebSocket frames received from another source.

resume_stream

$session->resume_stream($stream_id);

Resume data production for a deferred stream. Call this after a streaming body callback has returned undef and new data is available. Works for both request and response streams.

terminate_session

$session->terminate_session($error_code);

Send a GOAWAY frame and terminate the session. The $error_code should be an nghttp2 error code (0 for NGHTTP2_NO_ERROR).

submit_rst_stream

$session->submit_rst_stream($stream_id, $error_code);

Send a RST_STREAM frame to abnormally terminate a stream. The $error_code should be an HTTP/2 error code (e.g. 0 for NO_ERROR, 8 for CANCEL).

submit_ping

$session->submit_ping($ack, $opaque_data);

Send a PING frame. Set $ack to 1 for a PING ACK response, 0 for an unsolicited PING. $opaque_data must be exactly 8 bytes, or undef for default.

submit_window_update

$session->submit_window_update($stream_id, $window_size_increment);

Send a WINDOW_UPDATE frame to increase the flow control window. Use $stream_id = 0 for connection-level flow control, or a specific stream ID for stream-level.

get_stream_user_data

my $data = $session->get_stream_user_data($stream_id);

Retrieve user data associated with a stream. Returns undef if no data is set.

set_stream_user_data

$session->set_stream_user_data($stream_id, $data);

Associate arbitrary user data with a stream. Useful for storing per-stream application state.

is_stream_deferred

my $bool = $session->is_stream_deferred($stream_id);

Returns true if the stream's data provider has been deferred (i.e. the streaming callback returned undef). The stream can be resumed with resume_stream().

want_read

my $bool = $session->want_read();

Returns true if the session wants to read more data.

want_write

my $bool = $session->want_write();

Returns true if the session has data to write.

resume_data

$session->resume_data($stream_id);

Low-level resume for deferred data production. Prefer resume_stream() which also clears the internal deferred flag.

CALLBACKS

All callbacks receive positional arguments and should return 0 on success.

on_begin_headers

sub { my ($stream_id, $frame_type, $flags) = @_; return 0; }

Called when a new headers block begins (new stream or trailers).

on_header

sub { my ($stream_id, $name, $value, $flags) = @_; return 0; }

Called for each header. Pseudo-headers (:method, :path, :scheme, :authority, :status, :protocol) are delivered before regular headers.

on_frame_recv

sub { my ($frame_hashref) = @_; return 0; }

Called when a complete frame is received. The hashref contains: type, flags, stream_id, length.

on_data_chunk_recv

sub { my ($stream_id, $data, $flags) = @_; return 0; }

Called when body data is received on a stream.

on_stream_close

sub { my ($stream_id, $error_code) = @_; return 0; }

Called when a stream is closed.