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 )