PAGI-Server
view release on metacpan or search on metacpan
t/10-http-compliance.t view on Meta::CPAN
quiet => 1,
max_header_size => 1024, # Custom max header size
);
$loop->add($server);
await $server->listen;
my $port = $server->port;
# Create a stream and add to loop for proper async I/O
my $socket = IO::Socket::INET->new(
PeerAddr => '127.0.0.1',
PeerPort => $port,
Proto => 'tcp',
Blocking => 0,
) or die "Cannot connect: $!";
my $response = '';
my $done = $loop->new_future;
my $stream = IO::Async::Stream->new(
handle => $socket,
on_read => sub {
my ($s, $buffref, $eof) = @_;
$response .= $$buffref;
$$buffref = '';
if ($eof || $response =~ /\r\n\r\n/) {
$done->done unless $done->is_ready;
}
return 0;
},
on_closed => sub {
$done->done unless $done->is_ready;
},
);
$loop->add($stream);
# Send request with headers exceeding 1024 bytes
my $large_header = "X-Large: " . ("x" x 2000);
$stream->write("GET / HTTP/1.1\r\nHost: localhost\r\n$large_header\r\n\r\n");
# Wait with timeout
my $timeout = $loop->delay_future(after => 3)->then(sub { $done->done });
await Future->wait_any($done, $timeout);
like($response, qr/HTTP\/1\.1 431/, '431 response for headers exceeding max_header_size');
$loop->remove($stream);
await $server->shutdown;
$loop->remove($server);
})->()->get;
};
# Test 18: send() after disconnect is a no-op per spec
# This tests the unit behavior of the send function when connection is closed
subtest 'send() after disconnect returns completed Future' => sub {
# Test the _create_send implementation directly by verifying
# that it returns immediately when closed flag is set
# First verify by examining the send() return behavior in a streaming test
# where the client disconnects mid-stream
my $app_completed = 0;
my $error_during_send = 0;
my $test_app = async sub {
my ($scope, $receive, $send) = @_;
# Handle lifespan scope
if ($scope->{type} eq 'lifespan') {
while (1) {
my $event = await $receive->();
if ($event->{type} eq 'lifespan.startup') {
await $send->({ type => 'lifespan.startup.complete' });
}
elsif ($event->{type} eq 'lifespan.shutdown') {
await $send->({ type => 'lifespan.shutdown.complete' });
last;
}
}
return;
}
die "Unsupported scope type: $scope->{type}" unless $scope->{type} eq 'http';
# Start response
await $send->({
type => 'http.response.start',
status => 200,
headers => [['content-type', 'text/plain']],
});
# Send some content - force close by sending more => 0
await $send->({
type => 'http.response.body',
body => 'Hello',
more => 0,
});
# Now try to send AFTER response is complete
# This should be a no-op (not throw an error)
eval {
await $send->({
type => 'http.response.body',
body => 'This should be ignored',
more => 0,
});
};
if ($@) {
$error_during_send = 1;
}
$app_completed = 1;
};
my $server = PAGI::Server->new(
app => $test_app,
host => '127.0.0.1',
port => 0,
quiet => 1,
);
( run in 0.968 second using v1.01-cache-2.11-cpan-995e09ba956 )