Feersum

 view release on metacpan or  search on metacpan

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

  sse.onmessage = e => log('sse', 'data: ' + e.data);
  sse.onerror = () => log('sse', 'SSE error/closed');
}
function stopSSE() { sse && sse.close(); }

function startWS() {
  const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
  ws = new WebSocket(proto + '//' + location.host + '/ws');
  ws.onopen = () => log('ws', 'Connected');
  ws.onmessage = e => log('ws', 'Received: ' + e.data);
  ws.onclose = () => log('ws', 'Closed');
}
function sendWS() { ws && ws.send('ping ' + Date.now()); }
function stopWS() { ws && ws.close(); }
</script>
</body>
</html>
HTML
    }

    # Server-Sent Events
    elsif ($path eq '/sse') {
        return sub {
            my $respond = shift;
            my $w = $respond->([200, [
                'Content-Type' => 'text/event-stream',
                'Cache-Control' => 'no-cache',
            ]]);
            my $count = 0;
            my $t; $t = AE::timer 0, 1, sub {
                eval { $w->write("data: tick " . ++$count . " @ " . localtime() . "\n\n") };
                if ($@ || $count >= 30) { undef $t; eval { $w->close } }
            };
        };
    }

    # WebSocket
    elsif ($path eq '/ws') {
        my $io = $env->{'psgix.io'} or return [500, [], ['No psgix.io']];
        my $hs = Protocol::WebSocket::Handshake::Server->new_from_psgi($env);
        $hs->parse('');
        unless ($hs->is_done) {
            return [400, [], ['Bad handshake']];
        }
        syswrite $io, $hs->to_string;

        my $frame = Protocol::WebSocket::Frame->new;
        my $w; $w = AE::io $io, 0, sub {
            my $buf;
            my $n = sysread $io, $buf, 8192;
            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;
        return [200, ['Content-Type' => 'text/plain'], [join("\n", @lines) . "\n"]];
    }

    else { return [404, ['Content-Type' => 'text/plain'], ["Not Found\n"]] }
};

# Enable PROXY protocol for L4 TLS termination
# This allows the frontend to send real client IP and SSL status
Plack::Handler::Feersum->new(
    listen => [$SOCKET_PATH],
    quiet  => 1,
    proxy_protocol => 1,  # Enable PROXY protocol v1/v2
)->run($app);
END { unlink $SOCKET_PATH if -e $SOCKET_PATH }



( run in 0.596 second using v1.01-cache-2.11-cpan-16aabcbfbcb )