@@ -144,7 +144,14 @@ class Http3ApplicationImpl final : public Session::Application {
144144 : Application(session, options),
145145 allocator_ (BindingData::Get(env())),
146146 options_(options),
147- conn_(InitializeConnection()) {
147+ conn_(nullptr ) {
148+ // Build the ORIGIN frame payload from the SNI configuration before
149+ // creating the nghttp3 connection, since InitializeConnection needs
150+ // the origin_vec_ to be ready for settings.origin_list.
151+ if (session->is_server ()) {
152+ BuildOriginPayload ();
153+ }
154+ conn_ = InitializeConnection ();
148155 session->set_priority_supported ();
149156 }
150157
@@ -613,9 +620,38 @@ class Http3ApplicationImpl final : public Session::Application {
613620 id == qpack_enc_stream_id_;
614621 }
615622
623+ void BuildOriginPayload () {
624+ // Build the serialized ORIGIN frame payload from the SNI configuration.
625+ // Each origin entry is: 2-byte BE length + origin string.
626+ // Wildcard ('*') entries and entries with authoritative=false are skipped.
627+ auto & sni = session ().config ().options .sni ;
628+ for (auto & [hostname, opts] : sni) {
629+ if (hostname == " *" || !opts.authoritative ) continue ;
630+ std::string origin = " https://" ;
631+ origin += hostname;
632+ if (opts.port != 443 ) {
633+ origin += " :" ;
634+ origin += std::to_string (opts.port );
635+ }
636+ // 2-byte BE length prefix
637+ uint16_t len = static_cast <uint16_t >(origin.size ());
638+ origin_payload_.push_back (static_cast <uint8_t >((len >> 8 ) & 0xff ));
639+ origin_payload_.push_back (static_cast <uint8_t >(len & 0xff ));
640+ // Origin string bytes
641+ origin_payload_.insert (
642+ origin_payload_.end (), origin.begin (), origin.end ());
643+ }
644+ if (!origin_payload_.empty ()) {
645+ origin_vec_ = {origin_payload_.data (), origin_payload_.size ()};
646+ }
647+ }
648+
616649 Http3ConnectionPointer InitializeConnection () {
617650 nghttp3_conn* conn = nullptr ;
618651 nghttp3_settings settings = options_;
652+ if (!origin_payload_.empty ()) {
653+ settings.origin_list = &origin_vec_;
654+ }
619655 if (session ().is_server ()) {
620656 CHECK_EQ (nghttp3_conn_server_new (
621657 &conn, &kCallbacks , &settings, &allocator_, this ),
@@ -803,6 +839,14 @@ class Http3ApplicationImpl final : public Session::Application {
803839 int64_t qpack_dec_stream_id_ = -1 ;
804840 int64_t qpack_enc_stream_id_ = -1 ;
805841
842+ // ORIGIN frame support (RFC 9412).
843+ // origin_payload_ holds the serialized ORIGIN frame payload for sending.
844+ // origin_vec_ points into origin_payload_ for nghttp3_settings.origin_list.
845+ // received_origins_ accumulates origins from received ORIGIN frames.
846+ std::vector<uint8_t > origin_payload_;
847+ nghttp3_vec origin_vec_{nullptr , 0 };
848+ std::vector<std::string> received_origins_;
849+
806850 // ==========================================================================
807851 // Static callbacks
808852
@@ -1083,14 +1127,18 @@ class Http3ApplicationImpl final : public Session::Application {
10831127 const uint8_t * origin,
10841128 size_t originlen,
10851129 void * conn_user_data) {
1086- // ORIGIN frames (RFC 8336) are used for connection coalescing
1087- // across multiple origins. Not yet implemented u2014 requires
1088- // connection pooling and multi-origin reuse support.
1130+ NGHTTP3_CALLBACK_SCOPE (app);
1131+ app. received_origins_ . emplace_back ( reinterpret_cast < const char *>(origin),
1132+ originlen);
10891133 return NGTCP2_SUCCESS;
10901134 }
10911135
10921136 static int on_end_origin (nghttp3_conn* conn, void * conn_user_data) {
1093- // See on_receive_origin above.
1137+ NGHTTP3_CALLBACK_SCOPE (app);
1138+ if (!app.received_origins_ .empty ()) {
1139+ app.session ().EmitOrigins (std::move (app.received_origins_ ));
1140+ app.received_origins_ .clear ();
1141+ }
10941142 return NGTCP2_SUCCESS;
10951143 }
10961144
0 commit comments