NAME

Hypersonic - Blazing fast HTTP server with JIT-compiled C event loop

SYNOPSIS

use Hypersonic;

my $server = Hypersonic->new();

# Handlers return STRINGS - they run ONCE at compile time
$server->get('/api/hello' => sub {
    '{"message":"Hello, World!"}'
});

$server->get('/health' => sub {
    'OK'
});

# Compile routes - generates C code and compiles via XS::JIT
$server->compile();

# Run the server
$server->run(
    port    => 8080,
    workers => 4,
);

DESCRIPTION

Hypersonic is a benchmark-focused micro HTTP server that uses XS::JIT to generate and compile C code at runtime. The entire event loop runs in C with no Perl in the hot path.

What it does:

1. Static route handlers run ONCE at compile() time
2. Response strings (including HTTP headers) are baked into C as static constants
3. Dynamic routes run Perl handlers per-request with JIT-compiled request objects
4. A pure C event loop (kqueue/epoll) is generated and compiled
5. Security headers are pre-computed and baked into responses at compile time
6. Optional TLS/HTTPS support via OpenSSL with JIT-compiled wrappers

Performance: ~290,000 requests/second on a single core (macOS/kqueue).

METHODS

new

my $server = Hypersonic->new(%options);

Create a new Hypersonic server instance.

Options:

cache_dir

Directory for caching compiled XS modules. Default: _hypersonic_cache

tls

Enable TLS/HTTPS support. Requires cert_file and key_file. Default: 0

cert_file

Path to TLS certificate file (PEM format). Required if tls is enabled.

key_file

Path to TLS private key file (PEM format). Required if tls is enabled.

max_connections

Maximum number of concurrent connections. Default: 10000

max_request_size

Maximum request size in bytes. Default: 8192

keepalive_timeout

Keep-alive connection timeout in seconds. Default: 30

recv_timeout

Receive timeout in seconds. Default: 30

drain_timeout

Graceful shutdown drain timeout in seconds. Default: 5

enable_security_headers

Enable security headers (X-Frame-Options, X-Content-Type-Options, etc.). Default: 1

security_headers

HashRef of custom security header values. Example:

security_headers => {
    'X-Frame-Options'         => 'SAMEORIGIN',
    'Content-Security-Policy' => "default-src 'self'",
}
websocket_rooms

Enable WebSocket Room support for broadcast groups. Default: 0

Only set to 1 if you need Hypersonic::WebSocket::Room for broadcasting to groups of connections. This adds Room-specific XS code to your compiled server.

max_rooms

Maximum number of rooms when websocket_rooms is enabled. Default: 1000

max_clients_per_room

Maximum clients per room when websocket_rooms is enabled. Default: 10000

c_helpers

C helper functions to inject early in the generated code, making them available to all routes. Can be a coderef that receives an XS::JIT::Builder, or a raw C string.

# Using a coderef
c_helpers => sub {
    my ($builder) = @_;
    $builder->line('static int double_value(int x) { return x * 2; }');
}

# Or raw C string
c_helpers => 'static int double_value(int x) { return x * 2; }'

These helpers are available to need_xs_builder routes.

Example with TLS:

my $server = Hypersonic->new(
    tls       => 1,
    cert_file => '/path/to/cert.pem',
    key_file  => '/path/to/key.pem',
);

get

$server->get('/path' => sub { ... });
$server->get('/path' => sub { ... }, \%options);

Register a GET route handler.

post

$server->post('/path' => sub { ... });

Register a POST route handler.

put

$server->put('/path' => sub { ... });

Register a PUT route handler.

del

$server->del('/path' => sub { ... });

Register a DELETE route handler.

patch

$server->patch('/path' => sub { ... });

Register a PATCH route handler.

$server->head('/path' => sub { ... });

Register a HEAD route handler.

options

$server->options('/path' => sub { ... });

Register an OPTIONS route handler.

websocket

$server->websocket('/ws' => sub {
    my ($ws) = @_;

    $ws->on(open => sub {
        $ws->send('Welcome!');
    });

    $ws->on(message => sub {
        my ($data) = @_;
        $ws->send("Echo: $data");
    });

    $ws->on(close => sub {
        my ($code, $reason) = @_;
        # Connection closed
    });
});

Register a WebSocket route handler. The handler receives a Hypersonic::WebSocket object when a client upgrades to WebSocket.

WebSocket Object Methods:

$ws->on($event, $handler)

Register event handlers. Events: open, message, binary, ping, pong, close, error.

$ws->send($data)

Send a text message to the client.

$ws->send_binary($data)

Send binary data to the client.

$ws->ping($data)

Send a ping frame (optional payload).

$ws->close($code, $reason)

Initiate close handshake. Default code: 1000.

$ws->is_open, $ws->is_closing, $ws->is_closed

Check connection state.

$ws->param($name), $ws->header($name)

Access request parameters and headers from the upgrade request.

Example - Chat Server:

$server->websocket('/chat' => sub {
    my ($ws) = @_;

    $ws->on(open => sub {
        # New user connected
    });

    $ws->on(message => sub {
        my ($msg) = @_;
        # Broadcast to other clients...
    });
});

WebSocket Handler Registry

Hypersonic::WebSocket::Handler provides a global connection registry for managing all active WebSocket connections. Connections are automatically registered when created and unregistered when closed.

Class Methods:

Hypersonic::WebSocket::Handler->count

Returns total number of active WebSocket connections.

Hypersonic::WebSocket::Handler->get($fd)

Get the WebSocket object for a file descriptor.

Hypersonic::WebSocket::Handler->is_websocket($fd)

Check if a file descriptor is a registered WebSocket.

Hypersonic::WebSocket::Handler->broadcast($message, [$exclude])

Send text message to ALL connected WebSocket clients. Optional second argument is a WebSocket to exclude (typically the sender).

Example - Global Broadcast:

use Hypersonic::WebSocket::Handler;

$server->websocket('/ws' => sub {
    my ($ws) = @_;
    
    $ws->on(open => sub {
        my $count = Hypersonic::WebSocket::Handler->count;
        $ws->send("You are connection #$count");
        Hypersonic::WebSocket::Handler->broadcast("A user joined!", $ws);
    });
    
    $ws->on(message => sub {
        my ($msg) = @_;
        # Broadcast to ALL WebSocket clients except sender
        Hypersonic::WebSocket::Handler->broadcast("User: $msg", $ws);
    });
    
    $ws->on(close => sub {
        Hypersonic::WebSocket::Handler->broadcast("A user left");
    });
});

WebSocket with Rooms

Hypersonic::WebSocket::Room provides broadcast groups for sending messages to subsets of connections. You must enable rooms explicitly:

my $server = Hypersonic->new(
    websocket_rooms      => 1,      # Enable Room support
    max_rooms            => 100,    # Max rooms (default: 1000)
    max_clients_per_room => 1000,   # Max clients per room (default: 10000)
);

Example - Multi-Room Chat:

use Hypersonic::WebSocket::Room;

$server->websocket('/chat/:room' => sub {
    my ($ws) = @_;
    my $room_name = $ws->param('room');
    
    # Create or get existing room
    my $room = Hypersonic::WebSocket::Room->new($room_name);
    
    $ws->on(open => sub {
        $room->join($ws);
        $room->broadcast("Someone joined $room_name", $ws);  # Exclude sender
        $ws->send("Welcome to $room_name! (" . $room->count . " users)");
    });
    
    $ws->on(message => sub {
        my ($msg) = @_;
        # Broadcast to everyone in this room except sender
        $room->broadcast($msg, $ws);
    });
    
    $ws->on(close => sub {
        $room->leave($ws);
        $room->broadcast("Someone left $room_name");
    });
});

Room Methods:

Hypersonic::WebSocket::Room->new($name)

Create or get a room by name.

$room->name

Get room name.

$room->join($ws)

Add a WebSocket connection to the room.

$room->leave($ws)

Remove a WebSocket connection from the room.

$room->has($ws)

Check if a connection is in the room.

$room->count

Get number of connections in the room.

$room->count_open

Get number of OPEN (not closing/closed) connections in the room.

$room->broadcast($message, $exclude)

Send text message to all room members. Optional $exclude WebSocket connection to skip (typically the sender).

$room->broadcast_binary($data, $exclude)

Send binary data to all room members.

$room->close_all($code, $reason)

Close all connections in the room with given code and reason.

$room->clear

Remove all connections from the room (without closing them).

$room->clients

Get list of all WebSocket connections in the room.

Global Broadcast Pattern:

To broadcast to ALL connected WebSocket clients, use a global room:

my $global = Hypersonic::WebSocket::Room->new('__global__');

$server->websocket('/ws' => sub {
    my ($ws) = @_;
    
    $ws->on(open => sub {
        $global->join($ws);
        $global->broadcast("A user joined! (" . $global->count . " online)");
    });
    
    $ws->on(message => sub {
        my ($msg) = @_;
        $global->broadcast($msg, $ws);  # Send to all except sender
    });
    
    $ws->on(close => sub {
        $global->leave($ws);
        $global->broadcast("A user left");
    });
});

streaming

$server->get('/events' => sub {
    my ($stream) = @_;

    # Send SSE events
    my $sse = $stream->sse;
    $sse->event(type => 'update', data => 'Hello');
    $sse->keepalive;
    $sse->close;
}, { streaming => 1 });

Enable streaming responses for a route. The handler receives a Hypersonic::Stream object instead of returning a static response.

Stream Object Methods:

$stream->write($data)

Write data to the response (chunked encoding).

$stream->end($data)

Write final data and close the stream.

$stream->sse

Get an Hypersonic::SSE object for Server-Sent Events.

SSE Object Methods:

$sse->event(type => $type, data => $data, id => $id)

Send an SSE event with optional type and id.

$sse->data($data)

Send a data-only event (no type field).

$sse->retry($ms)

Set client reconnection interval in milliseconds.

$sse->keepalive

Send a keepalive comment to prevent timeout.

$sse->comment($text)

Send an SSE comment.

$sse->close

Close the SSE stream.

Example - Server-Sent Events:

$server->get('/notifications' => sub {
    my ($stream) = @_;
    my $sse = $stream->sse;

    $sse->retry(3000);  # Reconnect after 3s
    $sse->event(
        type => 'notification',
        data => '{"message":"New update!"}',
        id   => '12345',
    );

    # Keep connection alive...
    $sse->keepalive;
}, { streaming => 1 });

Route Handler Options

All route methods accept an optional hashref as the third argument:

$server->get('/path' => sub { ... }, {
    dynamic       => 1,           # Force dynamic handler
    parse_query   => 1,           # Parse query string
    parse_headers => 1,           # Parse HTTP headers
    parse_cookies => 1,           # Parse Cookie header
    parse_json    => 1,           # Parse JSON body
    parse_form    => 1,           # Parse form-urlencoded body
    before        => [\&mw1],     # Per-route before middleware
    after         => [\&mw2],     # Per-route after middleware
    need_xs_builder => 1,         # Generate C code at compile time
});

need_xs_builder Routes

When need_xs_builder => 1, the route handler is called at compile time with a fresh XS::JIT::Builder object instead of a request object. The handler must generate C code and return a hashref with the XS function name:

$server->get('/xs/counter' => sub {
    my ($builder) = @_;
    
    # Generate C code for this route
    $builder->line('static int counter = 0;')
      ->line('static void handle_counter(pTHX_ int fd,')
      ->line('    const char* method, int method_len,')
      ->line('    const char* path, int path_len,')
      ->line('    const char* body, int body_len,')
      ->line('    char** resp_out, int* resp_len_out) {')
      ->line('    counter++;')
      ->line('    static char response[256];')
      ->line('    int n = snprintf(response, sizeof(response),')
      ->line('        "HTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n"')
      ->line('        "Content-Length: 14\\r\\n\\r\\n{\\"count\\":%d}", counter);')
      ->line('    *resp_out = response;')
      ->line('    *resp_len_out = n;')
      ->line('}');
    
    return { xs_function => 'handle_counter' };
}, { need_xs_builder => 1 });

The XS function signature must match:

void func_name(pTHX_ int fd,
               const char* method, int method_len,
               const char* path, int path_len,
               const char* body, int body_len,
               char** resp_out, int* resp_len_out);

The function should write a complete HTTP response to *resp_out and set *resp_len_out to the response length.

Use with c_helpers to share utility functions:

my $server = Hypersonic->new(
    c_helpers => sub {
        my ($builder) = @_;
        $builder->line('static int double_it(int x) { return x * 2; }');
    },
);

$server->get('/double/:n' => sub {
    my ($builder) = @_;
    # Can use double_it() from c_helpers!
    # ...
}, { need_xs_builder => 1 });

static

$server->static('/static' => './public');
$server->static('/assets' => './assets', \%options);

Serve static files from a directory. Files are read at compile time and baked into C string constants for maximum performance.

Arguments:

url_prefix

URL path prefix for static files (e.g., /static)

directory

Filesystem directory containing files

options (optional)

HashRef with options:

max_age

Cache-Control max-age in seconds. Default: 3600

etag

Generate ETag headers (MD5 hash). Default: 1

index

Directory index file. Default: index.html

gzip

Serve .gz files if available. Default: 0

Example:

# Serve files from ./public at /static/*
$server->static('/static' => './public', {
    max_age => 86400,    # Cache for 1 day
    etag    => 1,        # Enable ETags
});

# Multiple static directories
$server->static('/assets' => './assets');
$server->static('/images' => './img');

Supported MIME types:

HTML, CSS, JavaScript, JSON, XML, PNG, JPEG, GIF, SVG, WebP, WOFF2, PDF, and many more. Unknown extensions default to application/octet-stream.

Performance:

Static files are fully JIT-compiled - the complete HTTP response (headers + body) is baked into C as a string constant. Zero Perl overhead at request time.

Static vs Dynamic Routes

Static routes have handlers that run once at compile time:

# Handler runs ONCE, response is baked into C
$server->get('/health' => sub { '{"status":"ok"}' });

Dynamic routes have handlers that run per-request:

# Automatic: path parameters make it dynamic
$server->get('/users/:id' => sub {
    my ($req) = @_;
    return '{"id":"' . $req->param('id') . '"}';
});

# Explicit: force dynamic with option
$server->post('/api/data' => sub {
    my ($req) = @_;
    return '{"received":"' . $req->body . '"}';
}, { dynamic => 1 });

Dynamic handlers receive a Hypersonic::Request object with:

$req->method         # HTTP method
$req->path           # Request path
$req->body           # Request body
$req->param('name')  # Path parameter by name
$req->query_param('key')  # Query string parameter
$req->header('name') # Request header
$req->cookie('name') # Cookie value
$req->json           # Parsed JSON body (hashref)
$req->form_param('key')   # Form field value

Response Formats

Handlers can return several formats:

# Simple string (status 200, text/plain or auto-detect JSON)
return '{"status":"ok"}';

# ArrayRef: [status, headers, body]
return [201, { 'Content-Type' => 'application/json' }, '{"id":1}'];

# HashRef: { status, headers, body }
return { status => 200, headers => {}, body => 'hello' };

# Hypersonic::Response object
use Hypersonic::Response 'res';
return res->status(201)->json({ id => 1 });

before

$server->before(sub {
    my ($req) = @_;
    # Return undef to continue, or a response to short-circuit
    return;
});

Register global before middleware. Runs before every dynamic route handler. Return a response to short-circuit (skip the handler and after middleware). Return undef to continue to the handler.

after

$server->after(sub {
    my ($req, $response) = @_;
    # Can modify and return the response
    return $response;
});

Register global after middleware. Runs after every dynamic route handler. Receives the request and response, can modify and return the response.

session_config

$server->session_config(
    secret      => 'your-secret-key-at-least-16-chars',
    cookie_name => 'sid',           # Default: 'hsid'
    max_age     => 86400,           # Default: 86400 (1 day)
    path        => '/',             # Default: '/'
    httponly    => 1,               # Default: 1
    secure      => 1,               # Default: 0
    samesite    => 'Strict',        # Default: 'Lax'
);

Enable session support with signed cookies and in-memory storage. Sessions are automatically loaded before each request and saved after.

Configuration options:

  • secret (required) - HMAC-SHA256 signing key (minimum 16 chars)

  • cookie_name - Session cookie name (default: 'hsid')

  • max_age - Session lifetime in seconds (default: 86400)

  • path - Cookie path (default: '/')

  • httponly - Set HttpOnly flag (default: 1)

  • secure - Set Secure flag for HTTPS (default: 0)

  • samesite - SameSite attribute: 'Strict', 'Lax', 'None' (default: 'Lax')

Usage in handlers:

$server->post('/login' => sub {
    my ($req) = @_;
    my $data = $req->json;
    
    if (authenticate($data->{user}, $data->{pass})) {
        $req->session('user', $data->{user});
        $req->session('logged_in', 1);
        $req->session_regenerate;  # Security: regenerate after login
        return res->json({ success => 1 });
    }
    return res->unauthorized('Invalid credentials');
}, { dynamic => 1, parse_json => 1 });

$server->get('/profile' => sub {
    my ($req) = @_;
    my $user = $req->session('user') // 'guest';
    return res->json({ user => $user });
}, { dynamic => 1 });

$server->post('/logout' => sub {
    my ($req) = @_;
    $req->session_clear;
    return res->json({ logged_out => 1 });
}, { dynamic => 1 });

See Hypersonic::Session for more details.

compress

$server->compress(
    min_size => 1024,    # Default: 1024 bytes
    level    => 6,       # Default: 6 (1=fastest, 9=smallest)
);

Enable JIT-compiled gzip compression for dynamic responses. Responses are compressed in C using zlib for maximum performance.

Configuration options:

  • min_size - Minimum response size to compress (default: 1024 bytes)

  • level - Compression level 1-9 (default: 6)

How it works:

1. At compile time, zlib compression code is JIT-compiled into the server
2. For each request, the C code checks Accept-Encoding: gzip header
3. If response body is larger than min_size, it's gzip compressed
4. Content-Encoding: gzip header is added automatically

Requirements: zlib library must be installed (standard on most systems).

See Hypersonic::Compress for more details.

Middleware Examples

# Authentication middleware
$server->before(sub {
    my ($req) = @_;
    my $token = $req->header('Authorization');
    unless ($token && validate_token($token)) {
        return res->unauthorized('Invalid token');
    }
    return;  # Continue to handler
});

# Logging middleware
$server->after(sub {
    my ($req, $res) = @_;
    warn "[" . $req->method . "] " . $req->path . "\n";
    return $res;
});

# Per-route middleware
$server->get('/admin/:id' => sub { ... }, {
    before => [\&require_admin],
    after  => [\&audit_log],
});

async_pool

$server->async_pool(
    workers    => 8,       # Thread pool size (default: 8)
    queue_size => 4096,    # Max queued operations (default: 4096)
);

Enable the JIT-compiled async thread pool for non-blocking operations. When enabled, the event loop integrates with Hypersonic::Future::Pool to process completed async operations.

Example - Async route with Future:

use Hypersonic;
use Hypersonic::Future;
use Hypersonic::Future::Pool;
use Hypersonic::Response 'res';

my $server = Hypersonic->new;

# Enable async pool
$server->async_pool(workers => 4);

# Dynamic route that uses Future for async work
$server->get('/compute/:n' => sub {
    my ($req) = @_;
    my $n = $req->param('n');

    # Create a future and submit work to thread pool
    my $f = Hypersonic::Future->new;

    Hypersonic::Future::Pool->submit($f, sub {
        # This runs in thread pool
        my $result = 0;
        $result += $_ for 1..$n;
        return $result;
    }, []);

    # Return future - response sent when resolved
    return $f->then(sub {
        my ($result) = @_;
        return res->json({ sum => $result });
    });
});

$server->compile;
$server->run(port => 8080);

Future API:

# Create futures
my $f = Hypersonic::Future->new;
my $f2 = Hypersonic::Future->new_done(@values);
my $f3 = Hypersonic::Future->new_fail($error, $category);

# Resolve/reject
$f->done(@values);
$f->fail($message, $category);

# State checks
$f->is_ready;     # True if done, failed, or cancelled
$f->is_done;      # True if resolved with values
$f->is_failed;    # True if rejected
$f->is_cancelled; # True if cancelled

# Get results
my @values = $f->result;     # Returns result values
my ($msg, $cat) = $f->failure;  # Returns error info

# Chaining
$f->then(sub { ... })
  ->catch(sub { ... })
  ->finally(sub { ... });

# Callbacks
$f->on_done(sub { my @vals = @_; ... });
$f->on_fail(sub { my ($msg, $cat) = @_; ... });
$f->on_ready(sub { ... });  # Called for any completion

# Convergent futures
Hypersonic::Future->needs_all($f1, $f2, $f3);  # All must succeed
Hypersonic::Future->needs_any($f1, $f2);       # First success wins
Hypersonic::Future->wait_all($f1, $f2, $f3);   # Wait for all (success or fail)
Hypersonic::Future->wait_any($f1, $f2);        # Wait for first completion

See Hypersonic::Future and Hypersonic::Future::Pool for full documentation.

compile

$server->compile();

Compile all registered routes into JIT'd native code. This:

1. Executes static handlers once to get response strings
2. Analyzes which features each route needs (JIT philosophy)
3. Generates C code with responses as static constants
4. Generates dynamic handler caller with only needed parsing
5. Compiles via XS::JIT

Must be called after all routes are registered, before run().

JIT Feature Detection

Hypersonic uses a "JIT philosophy" - only code that's actually needed gets compiled. The compile() method analyzes your routes and sets these flags:

needs_streaming

Set when any route has streaming => 1. Compiles Hypersonic::Stream and Hypersonic::SSE XS code.

needs_websocket

Set when any websocket() routes are registered. Compiles Hypersonic::WebSocket and Hypersonic::Protocol::WebSocket::Frame XS code.

needs_websocket_handler

Automatically set when needs_websocket is true. Compiles Hypersonic::WebSocket::Handler for connection registry.

needs_websocket_rooms

Set when websocket_rooms => 1 is passed to new(), or when any WebSocket route has rooms => 1 in its options. Compiles Hypersonic::WebSocket::Room for broadcast groups.

has_any_middleware

Set when global before() or after() middleware is registered.

has_route_middleware

Set when any route has per-route before or after options.

needs_async_pool

Set when async_pool() is called. Compiles Hypersonic::Future and Hypersonic::Future::Pool for async thread pool operations.

You can inspect these flags after compile:

$server->compile();
my $analysis = $server->{route_analysis};

say "Has streaming: ", $analysis->{needs_streaming} ? "yes" : "no";
say "Has WebSocket: ", $analysis->{needs_websocket} ? "yes" : "no";
say "Has Rooms: ", $analysis->{needs_websocket_rooms} ? "yes" : "no";

dispatch

my $response = $server->dispatch($request_arrayref);

Dispatch a request and return the response. Primarily for testing.

Request is an arrayref: [method, path, body, keep_alive, fd]

run

$server->run(port => 8080, workers => 4);

Start the HTTP server event loop.

Options:

port

Port to listen on. Default: 8080

workers

Number of worker processes. Default: 1

FULL EXAMPLE

use Hypersonic;
use Hypersonic::Response 'res';

my $server = Hypersonic->new(
    max_request_size => 16384,
    enable_security_headers => 1,
);

# Global middleware
$server->before(sub {
    my ($req) = @_;
    # Log request
    warn $req->method . ' ' . $req->path . "\n";
    return;  # Continue
});

# Static route (runs once at compile time)
$server->get('/health' => sub {
    '{"status":"ok"}'
});

# Dynamic route with path parameter
$server->get('/users/:id' => sub {
    my ($req) = @_;
    my $id = $req->param('id');
    return res->json({ id => $id, name => "User $id" });
});

# POST with JSON body
$server->post('/users' => sub {
    my ($req) = @_;
    my $data = $req->json;
    return res->status(201)->json({ created => $data->{name} });
}, { parse_json => 1 });

# Query parameters
$server->get('/search' => sub {
    my ($req) = @_;
    my $q = $req->query_param('q') // '';
    return res->json({ query => $q });
}, { dynamic => 1, parse_query => 1 });

$server->compile();
$server->run(port => 8080, workers => 4);

BENCHMARK

HTTP Server Performance (wrk, 2 threads, 100 connections, 10s)

Native execution on Apple M1, single worker, plaintext "Hello, World!" response:

Framework       Language        Req/sec     Latency     Relative
----------------------------------------------------------------
Hypersonic      Perl (JIT→C)    266,076     0.34ms      1.87x
Actix-web       Rust            238,454     0.40ms      1.68x
Gin             Go              141,943     1.02ms      1.00x
FastAPI         Python/uvicorn   11,677     8.56ms      0.08x

Perl Route Matching Benchmark

======================================================================
Benchmark: Route matching for GET /api/hello
======================================================================

Comparison (higher is better):
         Rate     Dancer2 HTTP_Router Mojolicious       Plack Hypersonic
Dancer2       17713/s          --        -83%        -91%       -100%      -100%
HTTP_Router  107178/s        505%          --        -45%        -97%       -99%
Mojolicious  196110/s       1007%         83%          --        -95%       -98%
Plack       3937159/s      22127%       3573%       1908%          --       -58%
Hypersonic  9336325/s      52608%       8611%       4661%        137%         --

SEE ALSO

Hypersonic::Request - JIT-compiled request object

Hypersonic::Response - Fluent response builder

Hypersonic::Stream - Streaming response object

Hypersonic::SSE - Server-Sent Events API

Hypersonic::WebSocket - WebSocket connection API

Hypersonic::WebSocket::Handler - WebSocket global registry and broadcast

Hypersonic::WebSocket::Room - WebSocket broadcast groups

Hypersonic::Future - High-performance async Future

Hypersonic::Future::Pool - Thread pool for async operations

Hypersonic::Socket - Low-level socket operations

Hypersonic::TLS - TLS/HTTPS support

XS::JIT - The JIT compiler used by Hypersonic

AUTHOR

LNATION <email@lnation.org>

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 4407:

Non-ASCII character seen before =encoding in '(JIT→C)'. Assuming UTF-8