Skip to content

Commit 8eb88ba

Browse files
committed
Only allow chunked-encoding for requests
1 parent 5c5cb0b commit 8eb88ba

File tree

3 files changed

+49
-11
lines changed

3 files changed

+49
-11
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ Failing to do so will result in the server parsing the incoming request,
9393
but never sending a response back to the client.
9494

9595
The `Server` supports both HTTP/1.1 and HTTP/1.0 request messages.
96-
If a client sends an invalid request message or uses an invalid HTTP protocol
97-
version, it will emit an `error` event, send an HTTP error response to the
98-
client and close the connection:
96+
If a client sends an invalid request message, uses an invalid HTTP protocol
97+
version or sends an invalid `Transfer-Encoding` in the request header, it will
98+
emit an `error` event, send an HTTP error response to the client and close the connection:
9999

100100
```php
101101
$http->on('error', function (Exception $e) {

src/Server.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,18 @@ public function handleRequest(ConnectionInterface $conn, RequestInterface $reque
143143
$contentLength = 0;
144144
$stream = new CloseProtectionStream($conn);
145145
if ($request->hasHeader('Transfer-Encoding')) {
146-
$transferEncodingHeader = $request->getHeader('Transfer-Encoding');
147-
// 'chunked' must always be the final value of 'Transfer-Encoding' according to: https://tools.ietf.org/html/rfc7230#section-3.3.1
148-
if (strtolower(end($transferEncodingHeader)) === 'chunked') {
149-
$stream = new ChunkedDecoder($stream);
150146

151-
$request = $request->withoutHeader('Transfer-Encoding');
152-
$request = $request->withoutHeader('Content-Length');
153-
154-
$contentLength = null;
147+
if (strtolower($request->getHeaderLine('Transfer-Encoding')) !== 'chunked') {
148+
$this->emit('error', array(new \InvalidArgumentException('Only chunked-encoding is allowed for Transfer-Encoding')));
149+
return $this->writeError($conn, 501);
155150
}
151+
152+
$stream = new ChunkedDecoder($stream);
153+
154+
$request = $request->withoutHeader('Transfer-Encoding');
155+
$request = $request->withoutHeader('Content-Length');
156+
157+
$contentLength = null;
156158
} elseif ($request->hasHeader('Content-Length')) {
157159
$string = $request->getHeaderLine('Content-Length');
158160

tests/ServerTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,42 @@ function ($data) use (&$buffer) {
14281428
$this->assertContains("\r\n\r\n", $buffer);
14291429
}
14301430

1431+
public function testOnlyChunkedEncodingIsAllowedForTransferEncoding()
1432+
{
1433+
$error = null;
1434+
1435+
$server = new Server($this->socket);
1436+
$server->on('request', $this->expectCallableNever());
1437+
$server->on('error', function ($exception) use (&$error) {
1438+
$error = $exception;
1439+
});
1440+
1441+
$buffer = '';
1442+
$this->connection
1443+
->expects($this->any())
1444+
->method('write')
1445+
->will(
1446+
$this->returnCallback(
1447+
function ($data) use (&$buffer) {
1448+
$buffer .= $data;
1449+
}
1450+
)
1451+
);
1452+
$this->socket->emit('connection', array($this->connection));
1453+
1454+
$data = "GET / HTTP/1.1\r\n";
1455+
$data .= "Host: example.com:80\r\n";
1456+
$data .= "Connection: close\r\n";
1457+
$data .= "Transfer-Encoding: custom\r\n";
1458+
$data .= "\r\n";
1459+
1460+
$this->connection->emit('data', array($data));
1461+
1462+
$this->assertContains("HTTP/1.1 501 Not Implemented\r\n", $buffer);
1463+
$this->assertContains("\r\n\r\nError 501: Not Implemented", $buffer);
1464+
$this->assertInstanceOf('InvalidArgumentException', $error);
1465+
}
1466+
14311467
private function createGetRequest()
14321468
{
14331469
$data = "GET / HTTP/1.1\r\n";

0 commit comments

Comments
 (0)