1
1
#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
2
2
3
3
#include " application.h"
4
+ #include < async_wrap-inl.h>
5
+ #include < debug_utils-inl.h>
4
6
#include < node_bob.h>
5
7
#include < node_sockaddr-inl.h>
6
8
#include < uv.h>
7
9
#include < v8.h>
8
10
#include " defs.h"
9
11
#include " endpoint.h"
12
+ #include " http3.h"
10
13
#include " packet.h"
11
14
#include " session.h"
12
15
@@ -21,24 +24,48 @@ using v8::Value;
21
24
22
25
namespace quic {
23
26
24
- struct Session ::Application::StreamData final {
25
- // The actual number of vectors in the struct, up to kMaxVectorCount.
26
- size_t count = 0 ;
27
- size_t remaining = 0 ;
28
- // The stream identifier. If this is a negative value then no stream is
29
- // identified.
30
- int64_t id = -1 ;
31
- int fin = 0 ;
32
- ngtcp2_vec data[kMaxVectorCount ]{};
33
- ngtcp2_vec* buf = data;
34
- BaseObjectPtr<Stream> stream;
35
- };
36
-
27
+ // ============================================================================
28
+ // Session::Application_Options
37
29
const Session::Application_Options Session::Application_Options::kDefault = {};
38
30
31
+ Session::Application_Options::operator const nghttp3_settings () const {
32
+ // In theory, Application_Options might contain options for more than just
33
+ // HTTP/3. Here we extract only the properties that are relevant to HTTP/3.
34
+ return nghttp3_settings{
35
+ max_field_section_size,
36
+ static_cast <size_t >(qpack_max_dtable_capacity),
37
+ static_cast <size_t >(qpack_encoder_max_dtable_capacity),
38
+ static_cast <size_t >(qpack_blocked_streams),
39
+ enable_connect_protocol,
40
+ enable_datagrams,
41
+ };
42
+ }
43
+
44
+ std::string Session::Application_Options::ToString () const {
45
+ DebugIndentScope indent;
46
+ auto prefix = indent.Prefix ();
47
+ std::string res (" {" );
48
+ res += prefix + " max header pairs: " + std::to_string (max_header_pairs);
49
+ res += prefix + " max header length: " + std::to_string (max_header_length);
50
+ res += prefix +
51
+ " max field section size: " + std::to_string (max_field_section_size);
52
+ res += prefix + " qpack max dtable capacity: " +
53
+ std::to_string (qpack_max_dtable_capacity);
54
+ res += prefix + " qpack encoder max dtable capacity: " +
55
+ std::to_string (qpack_encoder_max_dtable_capacity);
56
+ res += prefix +
57
+ " qpack blocked streams: " + std::to_string (qpack_blocked_streams);
58
+ res += prefix + " enable connect protocol: " +
59
+ (enable_connect_protocol ? std::string (" yes" ) : std::string (" no" ));
60
+ res += prefix + " enable datagrams: " +
61
+ (enable_datagrams ? std::string (" yes" ) : std::string (" no" ));
62
+ res += indent.Close ();
63
+ return res;
64
+ }
65
+
39
66
Maybe<Session::Application_Options> Session::Application_Options::From (
40
67
Environment* env, Local<Value> value) {
41
- if (value.IsEmpty ()) {
68
+ if (value.IsEmpty () || (!value-> IsUndefined () && !value-> IsObject ()) ) {
42
69
THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
43
70
return Nothing<Application_Options>();
44
71
}
@@ -49,11 +76,6 @@ Maybe<Session::Application_Options> Session::Application_Options::From(
49
76
return Just<Application_Options>(options);
50
77
}
51
78
52
- if (!value->IsObject ()) {
53
- THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
54
- return Nothing<Application_Options>();
55
- }
56
-
57
79
auto params = value.As <Object>();
58
80
59
81
#define SET (name ) \
@@ -63,7 +85,8 @@ Maybe<Session::Application_Options> Session::Application_Options::From(
63
85
64
86
if (!SET (max_header_pairs) || !SET (max_header_length) ||
65
87
!SET (max_field_section_size) || !SET (qpack_max_dtable_capacity) ||
66
- !SET (qpack_encoder_max_dtable_capacity) || !SET (qpack_blocked_streams)) {
88
+ !SET (qpack_encoder_max_dtable_capacity) || !SET (qpack_blocked_streams) ||
89
+ !SET (enable_connect_protocol) || !SET (enable_datagrams)) {
67
90
return Nothing<Application_Options>();
68
91
}
69
92
@@ -78,16 +101,22 @@ Session::Application::Application(Session* session, const Options& options)
78
101
bool Session::Application::Start () {
79
102
// By default there is nothing to do. Specific implementations may
80
103
// override to perform more actions.
104
+ Debug (session_, " Session application started" );
81
105
return true ;
82
106
}
83
107
84
108
void Session::Application::AcknowledgeStreamData (Stream* stream,
85
109
size_t datalen) {
110
+ Debug (session_,
111
+ " Application acknowledging stream %" PRIi64 " data: %zu" ,
112
+ stream->id (),
113
+ datalen);
86
114
DCHECK_NOT_NULL (stream);
87
115
stream->Acknowledge (datalen);
88
116
}
89
117
90
118
void Session::Application::BlockStream (int64_t id) {
119
+ Debug (session_, " Application blocking stream %" PRIi64, id);
91
120
auto stream = session ().FindStream (id);
92
121
if (stream) stream->EmitBlocked ();
93
122
}
@@ -96,6 +125,7 @@ bool Session::Application::CanAddHeader(size_t current_count,
96
125
size_t current_headers_length,
97
126
size_t this_header_length) {
98
127
// By default headers are not supported.
128
+ Debug (session_, " Application cannot add header" );
99
129
return false ;
100
130
}
101
131
@@ -104,33 +134,39 @@ bool Session::Application::SendHeaders(const Stream& stream,
104
134
const v8::Local<v8::Array>& headers,
105
135
HeadersFlags flags) {
106
136
// By default do nothing.
137
+ Debug (session_, " Application cannot send headers" );
107
138
return false ;
108
139
}
109
140
110
141
void Session::Application::ResumeStream (int64_t id) {
142
+ Debug (session_, " Application resuming stream %" PRIi64, id);
111
143
// By default do nothing.
112
144
}
113
145
114
146
void Session::Application::ExtendMaxStreams (EndpointLabel label,
115
147
Direction direction,
116
148
uint64_t max_streams) {
149
+ Debug (session_, " Application extending max streams" );
117
150
// By default do nothing.
118
151
}
119
152
120
153
void Session::Application::ExtendMaxStreamData (Stream* stream,
121
154
uint64_t max_data) {
155
+ Debug (session_, " Application extending max stream data" );
122
156
// By default do nothing.
123
157
}
124
158
125
159
void Session::Application::CollectSessionTicketAppData (
126
160
SessionTicket::AppData* app_data) const {
161
+ Debug (session_, " Application collecting session ticket app data" );
127
162
// By default do nothing.
128
163
}
129
164
130
165
SessionTicket::AppData::Status
131
166
Session::Application::ExtractSessionTicketAppData (
132
167
const SessionTicket::AppData& app_data,
133
168
SessionTicket::AppData::Source::Flag flag) {
169
+ Debug (session_, " Application extracting session ticket app data" );
134
170
// By default we do not have any application data to retrieve.
135
171
return flag == SessionTicket::AppData::Source::Flag::STATUS_RENEW
136
172
? SessionTicket::AppData::Status::TICKET_USE_RENEW
@@ -140,14 +176,16 @@ Session::Application::ExtractSessionTicketAppData(
140
176
void Session::Application::SetStreamPriority (const Stream& stream,
141
177
StreamPriority priority,
142
178
StreamPriorityFlags flags) {
179
+ Debug (
180
+ session_, " Application setting stream %" PRIi64 " priority" , stream.id ());
143
181
// By default do nothing.
144
182
}
145
183
146
184
StreamPriority Session::Application::GetStreamPriority (const Stream& stream) {
147
185
return StreamPriority::DEFAULT;
148
186
}
149
187
150
- BaseObjectPtr< Packet> Session::Application::CreateStreamDataPacket () {
188
+ Packet* Session::Application::CreateStreamDataPacket () {
151
189
return Packet::Create (env (),
152
190
session_->endpoint_ .get (),
153
191
session_->remote_address_ ,
@@ -156,24 +194,37 @@ BaseObjectPtr<Packet> Session::Application::CreateStreamDataPacket() {
156
194
}
157
195
158
196
void Session::Application::StreamClose (Stream* stream, QuicError error) {
197
+ Debug (session_,
198
+ " Application closing stream %" PRIi64 " with error %s" ,
199
+ stream->id (),
200
+ error);
159
201
stream->Destroy (error);
160
202
}
161
203
162
204
void Session::Application::StreamStopSending (Stream* stream, QuicError error) {
205
+ Debug (session_,
206
+ " Application stopping sending on stream %" PRIi64 " with error %s" ,
207
+ stream->id (),
208
+ error);
163
209
DCHECK_NOT_NULL (stream);
164
210
stream->ReceiveStopSending (error);
165
211
}
166
212
167
213
void Session::Application::StreamReset (Stream* stream,
168
214
uint64_t final_size,
169
215
QuicError error) {
216
+ Debug (session_,
217
+ " Application resetting stream %" PRIi64 " with error %s" ,
218
+ stream->id (),
219
+ error);
170
220
stream->ReceiveStreamReset (final_size, error);
171
221
}
172
222
173
223
void Session::Application::SendPendingData () {
224
+ Debug (session_, " Application sending pending data" );
174
225
PathStorage path;
175
226
176
- BaseObjectPtr< Packet> packet;
227
+ Packet* packet = nullptr ;
177
228
uint8_t * pos = nullptr ;
178
229
int err = 0 ;
179
230
@@ -182,6 +233,7 @@ void Session::Application::SendPendingData() {
182
233
size_t packetSendCount = 0 ;
183
234
184
235
const auto updateTimer = [&] {
236
+ Debug (session_, " Application updating the session timer" );
185
237
ngtcp2_conn_update_pkt_tx_time (*session_, uv_hrtime ());
186
238
session_->UpdateTimer ();
187
239
};
@@ -209,9 +261,9 @@ void Session::Application::SendPendingData() {
209
261
return session_->Close (Session::CloseMethod::SILENT);
210
262
}
211
263
212
- if (! packet) {
264
+ if (packet == nullptr ) {
213
265
packet = CreateStreamDataPacket ();
214
- if (! packet) {
266
+ if (packet == nullptr ) {
215
267
session_->last_error_ = QuicError::ForNgtcp2Error (NGTCP2_ERR_INTERNAL);
216
268
return session_->Close (Session::CloseMethod::SILENT);
217
269
}
@@ -319,12 +371,14 @@ class DefaultApplication final : public Session::Application {
319
371
const uint8_t * data,
320
372
size_t datalen,
321
373
Stream::ReceiveDataFlags flags) override {
374
+ Debug (&session (), " Default application receiving stream data" );
322
375
DCHECK_NOT_NULL (stream);
323
376
if (!stream->is_destroyed ()) stream->ReceiveData (data, datalen, flags);
324
377
return true ;
325
378
}
326
379
327
380
int GetStreamData (StreamData* stream_data) override {
381
+ Debug (&session (), " Default application getting stream data" );
328
382
DCHECK_NOT_NULL (stream_data);
329
383
// If the queue is empty, there aren't any streams with data yet
330
384
if (stream_queue_.IsEmpty ()) return 0 ;
@@ -380,7 +434,10 @@ class DefaultApplication final : public Session::Application {
380
434
return 0 ;
381
435
}
382
436
383
- void ResumeStream (int64_t id) override { ScheduleStream (id); }
437
+ void ResumeStream (int64_t id) override {
438
+ Debug (&session (), " Default application resuming stream %" PRIi64, id);
439
+ ScheduleStream (id);
440
+ }
384
441
385
442
bool ShouldSetFin (const StreamData& stream_data) override {
386
443
auto const is_empty = [](auto vec, size_t cnt) {
@@ -394,6 +451,7 @@ class DefaultApplication final : public Session::Application {
394
451
}
395
452
396
453
bool StreamCommit (StreamData* stream_data, size_t datalen) override {
454
+ Debug (&session (), " Default application committing stream data" );
397
455
DCHECK_NOT_NULL (stream_data);
398
456
const auto consume = [](ngtcp2_vec** pvec, size_t * pcnt, size_t len) {
399
457
ngtcp2_vec* v = *pvec;
@@ -425,13 +483,15 @@ class DefaultApplication final : public Session::Application {
425
483
426
484
private:
427
485
void ScheduleStream (int64_t id) {
486
+ Debug (&session (), " Default application scheduling stream %" PRIi64, id);
428
487
auto stream = session ().FindStream (id);
429
488
if (stream && !stream->is_destroyed ()) {
430
489
stream->Schedule (&stream_queue_);
431
490
}
432
491
}
433
492
434
493
void UnscheduleStream (int64_t id) {
494
+ Debug (&session (), " Default application unscheduling stream %" PRIi64, id);
435
495
auto stream = session ().FindStream (id);
436
496
if (stream && !stream->is_destroyed ()) stream->Unschedule ();
437
497
}
@@ -440,13 +500,15 @@ class DefaultApplication final : public Session::Application {
440
500
};
441
501
442
502
std::unique_ptr<Session::Application> Session::select_application () {
443
- // if (config.options.crypto_options.alpn == NGHTTP3_ALPN_H3)
444
- // return std::make_unique<Http3>(session,
445
- // config.options.application_options);
446
-
447
503
// In the future, we may end up supporting additional QUIC protocols. As they
448
504
// are added, extend the cases here to create and return them.
449
505
506
+ if (config_.options .tls_options .alpn == NGHTTP3_ALPN_H3) {
507
+ Debug (this , " Selecting HTTP/3 application" );
508
+ return createHttp3Application (this , config_.options .application_options );
509
+ }
510
+
511
+ Debug (this , " Selecting default application" );
450
512
return std::make_unique<DefaultApplication>(
451
513
this , config_.options .application_options );
452
514
}
0 commit comments