@@ -27,22 +27,25 @@ namespace quic {
2727
2828// ============================================================================
2929// Session::Application_Options
30- const Session::Application_Options Session::Application_Options::kDefault = {};
30+ const Session::Application::Options Session::Application::Options::kDefault =
31+ {};
3132
32- Session::Application_Options ::operator const nghttp3_settings () const {
33- // In theory, Application_Options might contain options for more than just
33+ Session::Application::Options ::operator const nghttp3_settings () const {
34+ // In theory, Application::Options might contain options for more than just
3435 // HTTP/3. Here we extract only the properties that are relevant to HTTP/3.
3536 return nghttp3_settings{
36- max_field_section_size,
37- static_cast <size_t >(qpack_max_dtable_capacity),
38- static_cast <size_t >(qpack_encoder_max_dtable_capacity),
39- static_cast <size_t >(qpack_blocked_streams),
40- enable_connect_protocol,
41- enable_datagrams,
37+ .max_field_section_size = max_field_section_size,
38+ .qpack_max_dtable_capacity =
39+ static_cast <size_t >(qpack_max_dtable_capacity),
40+ .qpack_encoder_max_dtable_capacity =
41+ static_cast <size_t >(qpack_encoder_max_dtable_capacity),
42+ .qpack_blocked_streams = static_cast <size_t >(qpack_blocked_streams),
43+ .enable_connect_protocol = enable_connect_protocol,
44+ .h3_datagram = enable_datagrams,
4245 };
4346}
4447
45- std::string Session::Application_Options ::ToString () const {
48+ std::string Session::Application::Options ::ToString () const {
4649 DebugIndentScope indent;
4750 auto prefix = indent.Prefix ();
4851 std::string res (" {" );
@@ -64,48 +67,58 @@ std::string Session::Application_Options::ToString() const {
6467 return res;
6568}
6669
67- Maybe<Session::Application_Options > Session::Application_Options ::From (
70+ Maybe<Session::Application::Options > Session::Application::Options ::From (
6871 Environment* env, Local<Value> value) {
69- if (value.IsEmpty () || (!value-> IsUndefined () && !value-> IsObject ())) {
72+ if (value.IsEmpty ()) [[unlikely]] {
7073 THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
71- return Nothing<Application_Options >();
74+ return Nothing<Application::Options >();
7275 }
7376
74- Application_Options options;
77+ Application::Options options;
7578 auto & state = BindingData::Get (env);
76- if (value->IsUndefined ()) {
77- return Just<Application_Options>(options);
78- }
79-
80- auto params = value.As <Object>();
8179
8280#define SET (name ) \
83- SetOption<Session::Application_Options, \
84- &Session::Application_Options:: name>( \
81+ SetOption<Session::Application::Options, \
82+ &Session::Application::Options:: name>( \
8583 env, &options, params, state.name ##_string ())
8684
87- if (!SET (max_header_pairs) || !SET (max_header_length) ||
88- !SET (max_field_section_size) || !SET (qpack_max_dtable_capacity) ||
89- !SET (qpack_encoder_max_dtable_capacity) || !SET (qpack_blocked_streams) ||
90- !SET (enable_connect_protocol) || !SET (enable_datagrams)) {
91- return Nothing<Application_Options>();
85+ if (!value->IsUndefined ()) {
86+ if (!value->IsObject ()) {
87+ THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
88+ return Nothing<Application::Options>();
89+ }
90+ auto params = value.As <Object>();
91+ if (!SET (max_header_pairs) || !SET (max_header_length) ||
92+ !SET (max_field_section_size) || !SET (qpack_max_dtable_capacity) ||
93+ !SET (qpack_encoder_max_dtable_capacity) ||
94+ !SET (qpack_blocked_streams) || !SET (enable_connect_protocol) ||
95+ !SET (enable_datagrams)) {
96+ // The call to SetOption should have scheduled an exception to be thrown.
97+ return Nothing<Application::Options>();
98+ }
9299 }
93100
94101#undef SET
95102
96- return Just<Application_Options >(options);
103+ return Just<Application::Options >(options);
97104}
98105
99106// ============================================================================
100107
101108std::string Session::Application::StreamData::ToString () const {
102109 DebugIndentScope indent;
110+
111+ size_t total_bytes = 0 ;
112+ for (size_t n = 0 ; n < count; n++) {
113+ total_bytes += data[n].len ;
114+ }
115+
103116 auto prefix = indent.Prefix ();
104117 std::string res (" {" );
105118 res += prefix + " count: " + std::to_string (count);
106- res += prefix + " remaining: " + std::to_string (remaining);
107119 res += prefix + " id: " + std::to_string (id);
108120 res += prefix + " fin: " + std::to_string (fin);
121+ res += prefix + " total: " + std::to_string (total_bytes);
109122 res += indent.Close ();
110123 return res;
111124}
@@ -120,14 +133,16 @@ bool Session::Application::Start() {
120133 return true ;
121134}
122135
123- void Session::Application::AcknowledgeStreamData (Stream* stream ,
136+ bool Session::Application::AcknowledgeStreamData (int64_t stream_id ,
124137 size_t datalen) {
125138 Debug (session_,
126139 " Application acknowledging stream %" PRIi64 " data: %zu" ,
127- stream-> id () ,
140+ stream_id ,
128141 datalen);
129- DCHECK_NOT_NULL (stream);
142+ auto stream = session ().FindStream (stream_id);
143+ if (!stream) return false ;
130144 stream->Acknowledge (datalen);
145+ return true ;
131146}
132147
133148void Session::Application::BlockStream (int64_t id) {
@@ -241,6 +256,14 @@ void Session::Application::SendPendingData() {
241256 PathStorage path;
242257 StreamData stream_data;
243258
259+ auto update_stats = OnScopeLeave ([&] {
260+ auto & s = session ();
261+ s.UpdateDataStats ();
262+ if (!s.is_destroyed ()) {
263+ s.UpdateTimer ();
264+ }
265+ });
266+
244267 // The maximum size of packet to create.
245268 const size_t max_packet_size = session_->max_packet_size ();
246269
@@ -296,7 +319,15 @@ void Session::Application::SendPendingData() {
296319 // Awesome, let's write our packet!
297320 ssize_t nwrite =
298321 WriteVStream (&path, pos, &ndatalen, max_packet_size, stream_data);
299- Debug (session_, " Application accepted %zu bytes into packet" , ndatalen);
322+
323+ if (ndatalen > 0 ) {
324+ Debug (session_,
325+ " Application accepted %zu bytes from stream into packet" ,
326+ ndatalen);
327+ } else {
328+ Debug (session_,
329+ " Application did not accept any bytes from stream into packet" );
330+ }
300331
301332 // A negative nwrite value indicates either an error or that there is more
302333 // data to write into the packet.
@@ -309,7 +340,6 @@ void Session::Application::SendPendingData() {
309340 // ndatalen = -1 means that no stream data was accepted into the
310341 // packet, which is what we want here.
311342 DCHECK_EQ (ndatalen, -1 );
312- DCHECK (stream_data.stream );
313343 session_->StreamDataBlocked (stream_data.id );
314344 continue ;
315345 }
@@ -323,8 +353,7 @@ void Session::Application::SendPendingData() {
323353 // ndatalen = -1 means that no stream data was accepted into the
324354 // packet, which is what we want here.
325355 DCHECK_EQ (ndatalen, -1 );
326- DCHECK (stream_data.stream );
327- stream_data.stream ->EndWritable ();
356+ if (stream_data.stream ) stream_data.stream ->EndWritable ();
328357 continue ;
329358 }
330359 case NGTCP2_ERR_WRITE_MORE: {
@@ -406,16 +435,16 @@ ssize_t Session::Application::WriteVStream(PathStorage* path,
406435 DCHECK_LE (stream_data.count , kMaxVectorCount );
407436 uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
408437 if (stream_data.fin ) flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
409- ngtcp2_pkt_info pi;
438+
410439 return ngtcp2_conn_writev_stream (*session_,
411440 &path->path ,
412- &pi ,
441+ nullptr ,
413442 dest,
414443 max_packet_size,
415444 ndatalen,
416445 flags,
417446 stream_data.id ,
418- stream_data. buf ,
447+ stream_data,
419448 stream_data.count ,
420449 uv_hrtime ());
421450}
@@ -536,39 +565,20 @@ class DefaultApplication final : public Session::Application {
536565 }
537566
538567 bool ShouldSetFin (const StreamData& stream_data) override {
539- auto const is_empty = [](auto vec, size_t cnt) {
540- size_t i;
541- for (i = 0 ; i < cnt && vec[i].len == 0 ; ++i) {
542- }
543- return i == cnt;
568+ auto const is_empty = [](const ngtcp2_vec* vec, size_t cnt) {
569+ size_t i = 0 ;
570+ for (size_t n = 0 ; n < cnt; n++) i += vec[n].len ;
571+ return i > 0 ;
544572 };
545573
546- return stream_data.stream && is_empty (stream_data. buf , stream_data.count );
574+ return stream_data.stream && is_empty (stream_data, stream_data.count );
547575 }
548576
549577 bool StreamCommit (StreamData* stream_data, size_t datalen) override {
550578 Debug (&session (), " Default application committing stream data" );
551579 DCHECK_NOT_NULL (stream_data);
552- const auto consume = [](ngtcp2_vec** pvec, size_t * pcnt, size_t len) {
553- ngtcp2_vec* v = *pvec;
554- size_t cnt = *pcnt;
555-
556- for (; cnt > 0 ; --cnt, ++v) {
557- if (v->len > len) {
558- v->len -= len;
559- v->base += len;
560- break ;
561- }
562- len -= v->len ;
563- }
564-
565- *pvec = v;
566- *pcnt = cnt;
567- };
568580
569581 CHECK (stream_data->stream );
570- stream_data->remaining -= datalen;
571- consume (&stream_data->buf , &stream_data->count , datalen);
572582 stream_data->stream ->Commit (datalen);
573583 return true ;
574584 }
0 commit comments