Feersum

 view release on metacpan or  search on metacpan

eg/envoy-stream.yaml  view on Meta::CPAN

          "@type": type.googleapis.com/envoy.extensions.transport_sockets.proxy_protocol.v3.ProxyProtocolUpstreamTransport
          config:
            version: V2
          transport_socket:
            name: envoy.transport_sockets.raw_buffer
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer

      load_assignment:
        cluster_name: feersum_proxy_protocol
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 127.0.0.1
                      port_value: 5000
              # Add more for load balancing:
              # - endpoint:
              #     address:
              #       socket_address:
              #         address: 127.0.0.1
              #         port_value: 5001

      # Health check (TCP connect)
      health_checks:
        - timeout: 5s
          interval: 10s
          unhealthy_threshold: 3

eg/envoy-stream.yaml  view on Meta::CPAN

    #-------------------------------------------------------------------------
    # Plain TCP backend (no PROXY Protocol)
    #-------------------------------------------------------------------------
    - name: feersum_tcp
      type: STATIC
      connect_timeout: 5s
      lb_policy: ROUND_ROBIN

      load_assignment:
        cluster_name: feersum_tcp
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 127.0.0.1
                      port_value: 5000

    #-------------------------------------------------------------------------
    # Unix socket backend with PROXY Protocol v2
    #-------------------------------------------------------------------------
    - name: feersum_unix_proxy_protocol
      type: STATIC

eg/envoy-stream.yaml  view on Meta::CPAN

          "@type": type.googleapis.com/envoy.extensions.transport_sockets.proxy_protocol.v3.ProxyProtocolUpstreamTransport
          config:
            version: V2
          transport_socket:
            name: envoy.transport_sockets.raw_buffer
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer

      load_assignment:
        cluster_name: feersum_unix_proxy_protocol
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    pipe:
                      path: /tmp/feersum.sock

admin:
  address:
    socket_address:
      address: 127.0.0.1
      port_value: 9901

eg/envoy.yaml  view on Meta::CPAN

      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http_protocol_options:
              header_key_format:
                proper_case_words: {}

      load_assignment:
        cluster_name: feersum_tcp
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 127.0.0.1
                      port_value: 5000
              # Add more for load balancing:
              # - endpoint:
              #     address:
              #       socket_address:
              #         address: 127.0.0.1
              #         port_value: 5001
              # - endpoint:
              #     address:
              #       socket_address:
              #         address: 127.0.0.1
              #         port_value: 5002

      # Health check (optional)
      health_checks:
        - timeout: 5s
          interval: 10s
          unhealthy_threshold: 3

eg/envoy.yaml  view on Meta::CPAN

      typed_extension_protocol_options:
        envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
          "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
          explicit_http_config:
            http_protocol_options:
              header_key_format:
                proper_case_words: {}

      load_assignment:
        cluster_name: feersum_unix
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    pipe:
                      path: /tmp/feersum.sock

admin:
  address:
    socket_address:
      address: 127.0.0.1
      port_value: 9901

eg/healthcheck.pl  view on Meta::CPAN

#!/usr/bin/env perl
# Health check endpoint example for Docker / load balancers.
#
# GET /health returns 200 immediately even when the app is busy.
# All other paths go through the normal (potentially slow) app handler.
#
# Docker:
#   HEALTHCHECK --interval=5s CMD curl -f http://localhost:5000/health
#
use strict;
use warnings;
use Feersum;

eg/multi-instance.pl  view on Meta::CPAN

#!/usr/bin/env perl
# Two independent servers in one process, which is what new_instance() is for.
# Feersum->endjinn is a singleton with one handler and one set of tunables;
# new_instance() gives you a second of each, sharing only the event loop.
#
# Here: a public API on 5002 with tight limits, and an admin endpoint on 5003
# with its own handler, its own limits, and its own idea of keepalive.
#
#   perl eg/multi-instance.pl
#   curl localhost:5002/ ; curl localhost:5003/stats
use strict;
use warnings;
use EV;
use Feersum;
use IO::Socket::INET;

eg/sse-server.pl  view on Meta::CPAN

    my $path = $req->env->{PATH_INFO};

    if ($path eq '/' || $path eq '/index.html') {
        # Serve HTML page
        $req->send_response(200, [
            'Content-Type' => 'text/html; charset=utf-8',
            'Cache-Control' => 'no-cache',
        ], \$html_page);
    }
    elsif ($path eq '/events') {
        # SSE endpoint
        start_sse_stream($req);
    }
    else {
        $req->send_response(404, ['Content-Type' => 'text/plain'], \"Not Found\n");
    }
});

sub start_sse_stream {
    my $req = shift;
    my $id = ++$client_id;

eg/ssl-proxy/backend.pl  view on Meta::CPAN

            unless ($n) { undef $w; close $io; return }
            $frame->append($buf);
            while (defined(my $msg = $frame->next)) {
                my $reply = Protocol::WebSocket::Frame->new(buffer => "echo: $msg")->to_bytes;
                syswrite $io, $reply;
            }
        };
        return;
    }

    # Info endpoint - shows connection info including PROXY protocol data
    elsif ($path eq '/info') {
        my @lines = (
            "=== Connection Info (from PROXY Protocol) ===",
            "REMOTE_ADDR: $env->{REMOTE_ADDR}",
            "REMOTE_PORT: $env->{REMOTE_PORT}",
            "psgi.url_scheme: $env->{'psgi.url_scheme'}",
            "",
            "=== Request Headers ===",
        );
        push @lines, map { "$_: $env->{$_}" } sort grep /^(REQUEST_|PATH_|SERVER_|HTTP_)/, keys %$env;

eg/ssl-proxy/run.pl  view on Meta::CPAN

chdir "$FindBin::Bin/../..";
system 'eg/ssl-proxy/gen-cert.sh' unless -f 'eg/ssl-proxy/server.crt';

my $backend = fork // die; exec $^X, '-Iblib/lib', '-Iblib/arch', 'eg/ssl-proxy/backend.pl' unless $backend;
sleep 1;
my $stunnel = fork // die; exec 'stunnel', 'eg/ssl-proxy/stunnel.conf' unless $stunnel;

$SIG{$_} = sub { kill 9, $backend, $stunnel; exit } for qw(INT TERM);
print "Backend PID: $backend\n";
print "Stunnel PID: $stunnel\n";
print "\nTest endpoints:\n";
print "  curl -k https://localhost:8443/       # Home page\n";
print "  curl -k https://localhost:8443/info   # Connection info (shows PROXY protocol data)\n";
waitpid -1, 0 while wait > 0;

lib/Feersum.pm  view on Meta::CPAN

    NonBlocking=true
    User=www-data
    Group=www-data

See C<eg/systemd-socket.pl> for socket activation code.

=head2 Docker

    HEALTHCHECK --interval=5s CMD curl -sf http://localhost:5000/health

See C<eg/healthcheck.pl> for a health check endpoint pattern.

=head2 Reverse Proxy

Feersum works behind nginx, HAProxy, Caddy, or Envoy.  See C<eg/nginx.conf>,
C<eg/haproxy.cfg>, C<eg/Caddyfile>, C<eg/envoy.yaml> for example configs.
Enable C<reverse_proxy> or C<proxy_protocol> as appropriate.

=head2 Zero-Downtime Restart

For a B<PSGI> app use L<Plack::Handler::Feersum>:

picotls-git/include/picotls.h  view on Meta::CPAN


/**
 * global variables exposed
 */
extern struct st_ptls_log_t {
    /**
     * if application-data (e.g., payload) should be emitted as well
     */
    volatile unsigned may_include_appdata : 1;
    /**
     * endpoints that want to disable logging entirely can provide this value to the loggers
     */
    ptls_log_conn_state_t dummy_conn_state;
    /**
     * generation counter that is incremented whenever the state of loggers change; see `st_ptls_log_state_t::generation`
     */
    volatile uint64_t _generation;
} ptls_log;

/**
 * initializes a ptls_log_conn_state_t. `conn_id` and `peeraddr` (of type struct sockaddr) are optional; pass 0 and NULL

picotls-git/lib/picotls.c  view on Meta::CPAN

            if ((ret = call_on_client_hello_cb(tls_cbarg, ch->server_name, raw_message, ch->cipher_suites, ch->alpn.list,
                                               ch->alpn.count, NULL, 0, NULL, 0, NULL, 0, NULL, 0, 1)) != 0)
                return ret;
        }
        return PTLS_ALERT_PROTOCOL_VERSION;
    }

    /* Check TLS 1.3-specific constraints. Hereafter, we might exit without calling on_client_hello. That's fine because this CH is
     * ought to be rejected. */
    if (ch->legacy_version <= 0x0300) {
        /* RFC 8446 Appendix D.5: any endpoint receiving a Hello message with legacy_version set to 0x0300 MUST abort the handshake
         * with a "protocol_version" alert. */
        return PTLS_ALERT_PROTOCOL_VERSION;
    }
    if (!(ch->compression_methods.count == 1 && ch->compression_methods.ids[0] == 0))
        return PTLS_ALERT_ILLEGAL_PARAMETER;
    /* pre-shared key */
    if (ch->psk.hash_end != NULL) {
        /* PSK must be the last extension */
        if (!ch->psk.is_last_extension)
            return PTLS_ALERT_ILLEGAL_PARAMETER;

t/h2-03-edge-cases.t  view on Meta::CPAN


    $sock->close();
    exit($got_error ? 0 : 2);
}, timeout_mult => TIMEOUT_MULT);

is $body_received, 0,
    'handler never received the oversized body';

# ========================================================================
# Administrative limits produce a real HTTP status on H2, as on H1, not a
# stream reset with INTERNAL_ERROR (which RFC 9113 reserves for the endpoint's
# own faults and which leaves the client with no status at all).
# ========================================================================
$evh->max_uri_len(200);

h2_fork_test("H2 over-long :path answers 414", $port, sub {
    my ($port) = @_;
    my $sock = h2_connect($port) or exit(1);

    my $headers_block = hpack_encode_headers(
        [':method',    'GET'],

t/h2-10-write-timeout.t  view on Meta::CPAN

my $wt = 1.0 * TIMEOUT_MULT;
$evh->write_timeout($wt);

# The writer must OUTLIVE the handler: if it goes out of scope its DESTROY
# completes the response, so nothing ever stalls and the timeout cannot fire.
my @keep_writers;
# Streaming response that writes once then stops - should trigger timeout
$evh->request_handler(sub {
    my $r = shift;
    my $path = $r->env->{PATH_INFO} // '';
    if ($path eq '/ok') {          # control endpoint, answers normally
        $r->send_response(200, ['Content-Type' => 'text/plain'], ['CONTROLOK']);
        return;
    }
    my $w = $r->start_streaming(200, ['Content-Type' => 'text/plain']);
    $w->write("hello");
    push @keep_writers, $w;
    # Intentionally never write again and never close - let timeout fire
});

# nghttp will get a partial response then RST_STREAM (or connection close)

t/native-07-return-from-io-wrong-handle.t  view on Meta::CPAN

            last if defined $cl && length($body) >= $cl;
            last if !defined $cl;
        }
    }
    close $s;
    return $buf;
}

# --- 1. wrong handle handed back ---
my $got = talk(proxy_v2() . "GET /wrong HTTP/1.1\r\nHost: x\r\n\r\n");
like $got // q{}, qr{^HTTP/1\.1\ 200}x, 'takeover endpoint answered';
my ($body) = ($got // q{}) =~ /\r\n\r\n(.*)\z/s;
isnt $body, 'NO-CROAK', 'return_from_psgix_io rejected the wrong handle'
    or diag 'it accepted a handle wrapping a different descriptor';
like $body // q{}, qr/does not wrap this connection/,
    'and said why' or diag "croak was: " . ($body // 'undef');

# --- 2. PROXY v2 trailing TLV fragment ---
# One valid TLV (type 0x03, 1 byte) then a 2-byte tail that cannot be a header.
my $good_tlv = "\x03" . pack('n', 1) . "\xff";
my $ok_resp  = talk(proxy_v2($good_tlv)



( run in 2.368 seconds using v1.01-cache-2.11-cpan-cb04b646d8c )