Skip to content

Commit 269adc3

Browse files
pimterryaduh95
authored andcommitted
quic: fix two small bugs in HTTP/3 stream internals
Signed-off-by: Tim Perry <pimterry@gmail.com> PR-URL: #65970 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent c0e8274 commit 269adc3

4 files changed

Lines changed: 49 additions & 13 deletions

File tree

‎src/quic/application.cc‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,6 @@ class DefaultApplication final : public Session::Application {
347347
}
348348

349349
int GetStreamData(Session::StreamData* stream_data) override {
350-
// Reset the state of stream_data before proceeding...
351-
stream_data->id = -1;
352-
stream_data->count = 0;
353-
stream_data->fin = false;
354-
stream_data->stream.reset();
355350
Debug(&session(), "Default application getting stream data");
356351
DCHECK_NOT_NULL(stream_data);
357352
// If the queue is empty, there aren't any streams with data yet

‎src/quic/http3.cc‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ class Http3ApplicationImpl final : public Session::Application {
212212

213213
bool Start() override {
214214
if (started_) return true;
215-
started_ = true;
216215
Debug(&session(), "Starting HTTP/3 application.");
217216

218217
const auto params = session().remote_transport_params();
@@ -246,15 +245,15 @@ class Http3ApplicationImpl final : public Session::Application {
246245
}
247246

248247
Debug(&session(), "Creating and binding HTTP/3 control streams");
249-
bool ret =
248+
started_ =
250249
session().OpenUnidirectionalStream(&control_stream_id_) &&
251250
session().OpenUnidirectionalStream(&qpack_enc_stream_id_) &&
252251
session().OpenUnidirectionalStream(&qpack_dec_stream_id_) &&
253252
nghttp3_conn_bind_control_stream(*this, control_stream_id_) == 0 &&
254253
nghttp3_conn_bind_qpack_streams(
255254
*this, qpack_enc_stream_id_, qpack_dec_stream_id_) == 0;
256255

257-
if (env()->enabled_debug_list()->enabled(DebugCategory::QUIC) && ret) {
256+
if (env()->enabled_debug_list()->enabled(DebugCategory::QUIC) && started_) {
258257
Debug(&session(),
259258
"Created and bound control stream %" PRIi64,
260259
control_stream_id_);
@@ -266,7 +265,7 @@ class Http3ApplicationImpl final : public Session::Application {
266265
qpack_dec_stream_id_);
267266
}
268267

269-
return ret;
268+
return started_;
270269
}
271270

272271
void BeginShutdown() override {
@@ -688,18 +687,16 @@ class Http3ApplicationImpl final : public Session::Application {
688687
offsetof(ngtcp2_vec, base) == offsetof(nghttp3_vec, base) &&
689688
offsetof(ngtcp2_vec, len) == offsetof(nghttp3_vec, len),
690689
"ngtcp2_vec and nghttp3_vec must have identical layout");
691-
data->count = kMaxVectorCount;
692-
ssize_t ret = 0;
693690
Debug(&session(), "HTTP/3 application getting stream data");
694691
if (conn_ && session().max_data_left()) {
695692
// nghttp3 reports fin through an int out-param; bridge it to the bool.
696693
int fin = 0;
697-
ret =
694+
ssize_t ret =
698695
nghttp3_conn_writev_stream(*this,
699696
&data->id,
700697
&fin,
701698
reinterpret_cast<nghttp3_vec*>(data->data),
702-
data->count);
699+
kMaxVectorCount);
703700
// A negative return value indicates an error.
704701
if (ret < 0) {
705702
return static_cast<int>(ret);

‎src/quic/session.cc‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,12 @@ void Session::SendPendingData() {
20162016
}
20172017

20182018
// The stream_data is the next block of data from the application stream.
2019+
// It is reused across iterations, so we reset before it's populated:
2020+
stream_data.count = 0;
2021+
stream_data.id = -1;
2022+
stream_data.fin = false;
2023+
stream_data.stream.reset();
2024+
20192025
if (application().GetStreamData(&stream_data) < 0) {
20202026
Debug(this, "Application failed to get stream data");
20212027
SetLastError(QuicError::ForNgtcp2Error(NGTCP2_ERR_INTERNAL));
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Flags: --experimental-quic --no-warnings
2+
3+
// An HTTP/3 session must cleanly fail if the peer advertises fewer than
4+
// the 3 unidirectional streams that HTTP/3 needs for control and QPACK.
5+
6+
import { hasQuic, skip, mustNotCall } from '../common/index.mjs';
7+
import assert from 'node:assert';
8+
import * as fixtures from '../common/fixtures.mjs';
9+
10+
if (!hasQuic) {
11+
skip('QUIC is not enabled');
12+
}
13+
14+
const { listen, connect } = await import('node:quic');
15+
const { createPrivateKey } = await import('node:crypto');
16+
17+
const key = createPrivateKey(fixtures.readKey('agent1-key.pem'));
18+
const cert = fixtures.readKey('agent1-cert.pem');
19+
20+
const serverEndpoint = await listen(async (serverSession) => {
21+
await serverSession.closed;
22+
}, {
23+
sni: { '*': { keys: [key], certs: [cert] } },
24+
// No uni streams allowed:
25+
transportParams: { initialMaxStreamsUni: 0 },
26+
onheaders: mustNotCall(),
27+
});
28+
29+
// Expect the client to cleanly fail - not crash the process
30+
await assert.rejects(async () => {
31+
const clientSession = await connect(serverEndpoint.address, {
32+
servername: 'localhost',
33+
verifyPeer: 'manual',
34+
});
35+
await clientSession.opened;
36+
}, { code: 'ERR_QUIC_TRANSPORT_ERROR' });
37+
38+
await serverEndpoint.close();

0 commit comments

Comments
 (0)