Skip to content

Commit

Permalink
Expose settings on Http2Driver
Browse files Browse the repository at this point in the history
  • Loading branch information
bwoebi committed Feb 23, 2024
1 parent f9fb034 commit b9c63cf
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 38 deletions.
17 changes: 17 additions & 0 deletions src/Driver/Http1Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ private static function makeHeaderReduceClosure(string $search): \Closure

private readonly DeferredCancellation $deferredCancellation;

/** @var list<callable(Http2Driver): void> */
private array $onHttp2Upgrade = [];

public function __construct(
RequestHandler $requestHandler,
ErrorHandler $errorHandler,
Expand All @@ -78,6 +81,12 @@ public function __construct(
$this->deferredCancellation = new DeferredCancellation();
}

/** @param \Closure(Http2Driver): void $closure */
public function onHttp2Upgrade(\Closure $closure): void
{
$this->onHttp2Upgrade[] = $closure;
}

public function handleClient(
Client $client,
ReadableStream $readableStream,
Expand Down Expand Up @@ -174,6 +183,10 @@ public function handleClient(
pushEnabled: false,
);

foreach ($this->onHttp2Upgrade as $callback) {
$callback($this->http2driver);
}

$this->http2driver->handleClient(
$this->client,
new ReadableStreamChain(
Expand Down Expand Up @@ -381,6 +394,10 @@ public function handleClient(
settings: $h2cSettings,
);

foreach ($this->onHttp2Upgrade as $callback) {
$callback($this->http2driver);
}

$this->http2driver->initializeWriting($this->client, $this->writableStream);

// Remove headers that are not related to the HTTP/2 request.
Expand Down
75 changes: 41 additions & 34 deletions src/Driver/Http2Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ final class Http2Driver extends StreamHttpDriver implements Http2Processor

private int $pinged = 0;

/** @var array<int, int> */
private array $serverSettings;
/** @var DeferredFuture<array<int, int>|null> */
private DeferredFuture $clientSettings;

private readonly HPack $hpack;

public function __construct(
Expand All @@ -129,6 +134,27 @@ public function __construct(
$this->allowsPush = $pushEnabled;

$this->hpack = new HPack;

$this->serverSettings = [
Http2Parser::INITIAL_WINDOW_SIZE => self::DEFAULT_WINDOW_SIZE,
Http2Parser::MAX_CONCURRENT_STREAMS => $concurrentStreamLimit,
Http2Parser::MAX_HEADER_LIST_SIZE => $headerSizeLimit,
Http2Parser::MAX_FRAME_SIZE => self::DEFAULT_MAX_FRAME_SIZE,
0x8 => 1, // TODO move to Http2Parser::ENABLE_CONNECT_PROTOCOL
];

$this->clientSettings = new DeferredFuture;
}

/** @return Future<array<int, int>|null> */
public function getSettings(): Future
{
return $this->clientSettings->getFuture();
}

public function addSetting(int $setting, int $value): void
{
$this->serverSettings[$setting] = $value;
}

public function handleClient(
Expand Down Expand Up @@ -177,21 +203,7 @@ public function initializeWriting(
$this->remainingStreams--;

// Initial settings frame, sent immediately for upgraded connections.
$this->writeFrame(
\pack(
"nNnNnNnN",
Http2Parser::INITIAL_WINDOW_SIZE,
self::DEFAULT_WINDOW_SIZE,
Http2Parser::MAX_CONCURRENT_STREAMS,
$this->concurrentStreamLimit,
Http2Parser::MAX_HEADER_LIST_SIZE,
$this->headerSizeLimit,
Http2Parser::MAX_FRAME_SIZE,
self::DEFAULT_MAX_FRAME_SIZE
),
Http2Parser::SETTINGS,
Http2Parser::NO_FLAG
);
$this->writeInitialSettingsFrame();
}
}

Expand Down Expand Up @@ -486,6 +498,8 @@ private function shutdown(?ClientException $reason = null): void
}
}

$this->clientSettings->complete();

$this->client->close();
$this->readableStream->close();
$this->writableStream->close();
Expand Down Expand Up @@ -714,6 +728,15 @@ private function updateTimeout(int $id): void
}
}

private function writeInitialSettingsFrame(): void
{
$frame = "";
foreach ($this->serverSettings as $key => $value) {
$frame .= \pack("nN", $key, $value);
}
$this->writeFrame($frame, Http2Parser::SETTINGS, Http2Parser::NO_FLAG);
}

private function readPreface(): string
{
$buffer = $this->readableStream->read();
Expand All @@ -738,23 +761,7 @@ private function readPreface(): string

if ($this->settings === null) {
// Initial settings frame, delayed until after the preface is read for non-upgraded connections.
$this->writeFrame(
\pack(
"nNnNnNnNnN",
Http2Parser::INITIAL_WINDOW_SIZE,
self::DEFAULT_WINDOW_SIZE,
Http2Parser::MAX_CONCURRENT_STREAMS,
$this->concurrentStreamLimit,
Http2Parser::MAX_HEADER_LIST_SIZE,
$this->headerSizeLimit,
Http2Parser::MAX_FRAME_SIZE,
self::DEFAULT_MAX_FRAME_SIZE,
0x8, // TODO move to Http2Parser::ENABLE_CONNECT_PROTOCOL
1
),
Http2Parser::SETTINGS,
Http2Parser::NO_FLAG
);
$this->writeInitialSettingsFrame();
}

return $buffer;
Expand Down Expand Up @@ -1405,6 +1412,8 @@ public function handleStreamReset(int $streamId, int $errorCode): void

public function handleSettings(array $settings): void
{
$this->clientSettings->complete($settings);

foreach ($settings as $key => $value) {
switch ($key) {
case Http2Parser::INITIAL_WINDOW_SIZE:
Expand Down Expand Up @@ -1484,6 +1493,4 @@ public function getApplicationLayerProtocols(): array
{
return ['h2'];
}

// TODO add necessary functions to implement webtransport over HTTP/2 - have a closer read of the draft RFC... Needs new stream handlers.
}
9 changes: 6 additions & 3 deletions src/Driver/Http3Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Amp\CancelledException;
use Amp\DeferredCancellation;
use Amp\DeferredFuture;
use Amp\Future;
use Amp\Http\Http2\Http2Parser;
use Amp\Http\InvalidHeaderException;
use Amp\Http\Server\ClientException;
Expand Down Expand Up @@ -87,10 +88,10 @@ public function __construct(
$this->parsedSettings = new DeferredFuture;
}

/** @return array<int, int> */
public function getSettings(): \array
/** @return Future<array<int, int>|null> */
public function getSettings(): Future
{
return $this->parsedSettings->getFuture()->await();
return $this->parsedSettings->getFuture();
}

public function addSetting(Http3Settings|int $setting, int $value): void
Expand Down Expand Up @@ -606,6 +607,8 @@ function (int $bodySize) use (&$bodySizeLimit, &$dataSuspension) {
'address' => $this->client->getRemoteAddress()->toString(),
'message' => $e->getMessage(),
]);
} finally {
$this->parsedSettings->complete();
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/Middleware/Internal/MiddlewareRequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

namespace Amp\Http\Server\Middleware\Internal;

use Amp\Http\Server\Driver\Client;
use Amp\Http\Server\Driver\HttpDriver;
use Amp\Http\Server\Driver\HttpDriverFactory;
use Amp\Http\Server\Driver\HttpDriverMiddleware;
use Amp\Http\Server\ErrorHandler;
use Amp\Http\Server\Middleware;
use Amp\Http\Server\Request;
use Amp\Http\Server\RequestHandler;
Expand All @@ -13,7 +18,7 @@
* @see stackMiddleware()
* @internal
*/
final class MiddlewareRequestHandler implements RequestHandler
final class MiddlewareRequestHandler implements RequestHandler, HttpDriverMiddleware
{
public function __construct(
private readonly Middleware $middleware,
Expand All @@ -25,4 +30,12 @@ public function handleRequest(Request $request): Response
{
return $this->middleware->handleRequest($request, $this->requestHandler);
}

public function createHttpDriver(HttpDriverFactory $factory, RequestHandler $requestHandler, ErrorHandler $errorHandler, Client $client): HttpDriver
{
if ($this->requestHandler instanceof HttpDriverMiddleware) {
return $this->requestHandler->createHttpDriver($factory, $requestHandler, $errorHandler, $client);
}
return $factory->createHttpDriver($requestHandler, $errorHandler, $client);
}
}

0 comments on commit b9c63cf

Please sign in to comment.