Skip to content

Commit

Permalink
Ensure socket to backend is closed
Browse files Browse the repository at this point in the history
  • Loading branch information
thekid committed Jan 19, 2025
1 parent 1460267 commit d06d384
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 29 deletions.
61 changes: 32 additions & 29 deletions src/main/php/xp/web/srv/ForwardRequests.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,40 +57,43 @@ public function handleData($socket) {

if (Input::REQUEST === $request->kind) {
$this->backend->connect();
$message= "{$request->method()} {$request->resource()} HTTP/{$request->version()}\r\n";
$headers= [];
foreach ($request->headers() as $name => $value) {
isset($exclude[$name]) || $message.= "{$name}: {$value}\r\n";
$headers[$name]= $value;
}
// \util\cmd\Console::writeLine('>>> ', $message);
$this->backend->write($message."\r\n");
foreach ($this->transmit($request->incoming(), $this->backend) as $step) {
// yield 'read' => $socket;
}

$response= new Input($this->backend);
foreach ($response->consume() as $_) { }
try {
$message= "{$request->method()} {$request->resource()} HTTP/{$request->version()}\r\n";
$headers= [];
foreach ($request->headers() as $name => $value) {
isset($exclude[$name]) || $message.= "{$name}: {$value}\r\n";
$headers[$name]= $value;
}
// \util\cmd\Console::writeLine('>>> ', $message);
$this->backend->write($message."\r\n");
foreach ($this->transmit($request->incoming(), $this->backend) as $step) {
// yield 'read' => $socket;
}

// Switch protocols
if (101 === $response->status()) {
$result= ['websocket', ['path' => $request->resource(), 'headers' => $headers]];
} else {
$result= null;
}
$response= new Input($this->backend);
foreach ($response->consume() as $_) { }

// yield 'write' => $socket;
$message= "HTTP/{$response->version()} {$response->status()} {$response->message()}\r\n";
foreach ($response->headers() as $name => $value) {
isset($exclude[$name]) || $message.= "{$name}: {$value}\r\n";
}
// \util\cmd\Console::writeLine('<<< ', $message);
$socket->write($message."\r\n");
// Switch protocols
if (101 === $response->status()) {
$result= ['websocket', ['path' => $request->resource(), 'headers' => $headers]];
} else {
$result= null;
}

foreach ($this->transmit($response->incoming(), $socket) as $step) {
// yield 'write' => $socket;
$message= "HTTP/{$response->version()} {$response->status()} {$response->message()}\r\n";
foreach ($response->headers() as $name => $value) {
isset($exclude[$name]) || $message.= "{$name}: {$value}\r\n";
}
// \util\cmd\Console::writeLine('<<< ', $message);
$socket->write($message."\r\n");

foreach ($this->transmit($response->incoming(), $socket) as $step) {
// yield 'write' => $socket;
}
} finally {
$this->backend->close();
}
$this->backend->close();

return $result;
} else if (Input::CLOSE === $request->kind) {
Expand Down
51 changes: 51 additions & 0 deletions src/test/php/web/unittest/server/ForwardRequestsTest.class.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php namespace web\unittest\server;

use io\IOException;
use test\{Assert, Test};
use web\unittest\Channel;
use xp\web\srv\ForwardRequests;
Expand Down Expand Up @@ -106,4 +107,54 @@ public function forward_post_request_with_chunked_request() {
Assert::equals($request, implode('', $backend->out));
Assert::equals($response, implode('', $client->out));
}

#[Test]
public function backend_socket_closed() {
$request= $this->message(
'POST / HTTP/1.0',
'Transfer-Encoding: chunked',
'',
"4\r\nTest\r\n0\r\n\r\n",
);
$response= $this->message(
'HTTP/1.0 201 Created',
'Location: /test/1',
'',
''
);
$client= new Channel([$request]);
$backend= new Channel([$response]);
$this->forward($client, $backend);

Assert::false($backend->isConnected());
}

#[Test]
public function backend_socket_closed_on_errors() {
$request= $this->message(
'POST / HTTP/1.0',
'Transfer-Encoding: chunked',
'',
"4\r\nTest\r\n0\r\n\r\n",
);
$response= $this->message(
'HTTP/1.0 201 Created',
'Location: /test/1',
'',
''
);
$client= new class([$request]) extends Channel {
public function write($chunk) {
throw new IOException('Test');
}
};
$backend= new Channel([$response]);
try {
$this->forward($client, $backend);
} catch (IOException $expected) {
// ...
}

Assert::false($backend->isConnected());
}
}

0 comments on commit d06d384

Please sign in to comment.