Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/node_http2.h
1 #ifndef SRC_NODE_HTTP2_H_ 2 #define SRC_NODE_HTTP2_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 // clang-format off 7 #include "node.h" // nghttp2.h needs ssize_t 8 // clang-format on 9 #include "nghttp2/nghttp2.h" 10 11 #include "env.h" 12 #include "aliased_struct.h" 13 #include "node_http2_state.h" 14 #include "node_http_common.h" 15 #include "node_mem.h" 16 #include "node_perf.h" 17 #include "stream_base.h" 18 #include "string_bytes.h" 19 20 #include <algorithm> 21 #include <queue> 22 23 namespace node { 24 namespace http2 { 25 26 // Constants in all caps are exported as user-facing constants 27 // in JavaScript. Constants using the kName pattern are internal 28 // only. 29 30 // We strictly limit the number of outstanding unacknowledged PINGS a user 31 // may send in order to prevent abuse. The current default cap is 10. The 32 // user may set a different limit using a per Http2Session configuration 33 // option. 34 constexpr size_t kDefaultMaxPings = 10; 35 36 // Also strictly limit the number of outstanding SETTINGS frames a user sends 37 constexpr size_t kDefaultMaxSettings = 10; 38 39 // Default maximum total memory cap for Http2Session. 40 constexpr uint64_t kDefaultMaxSessionMemory = 10000000; 41 42 // These are the standard HTTP/2 defaults as specified by the RFC 43 constexpr uint32_t DEFAULT_SETTINGS_HEADER_TABLE_SIZE = 4096; 44 constexpr uint32_t DEFAULT_SETTINGS_ENABLE_PUSH = 1; 45 constexpr uint32_t DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS = 0xffffffffu; 46 constexpr uint32_t DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE = 65535; 47 constexpr uint32_t DEFAULT_SETTINGS_MAX_FRAME_SIZE = 16384; 48 constexpr uint32_t DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE = 65535; 49 constexpr uint32_t DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0; 50 constexpr uint32_t MAX_MAX_FRAME_SIZE = 16777215; 51 constexpr uint32_t MIN_MAX_FRAME_SIZE = DEFAULT_SETTINGS_MAX_FRAME_SIZE; 52 constexpr uint32_t MAX_INITIAL_WINDOW_SIZE = 2147483647; 53 54 // Stream is not going to have any DATA frames 55 constexpr int STREAM_OPTION_EMPTY_PAYLOAD = 0x1; 56 57 // Stream might have trailing headers 58 constexpr int STREAM_OPTION_GET_TRAILERS = 0x2; 59 60 // Http2Stream internal states 61 constexpr int kStreamStateNone = 0x0; 62 constexpr int kStreamStateShut = 0x1; 63 constexpr int kStreamStateReadStart = 0x2; 64 constexpr int kStreamStateReadPaused = 0x4; 65 constexpr int kStreamStateClosed = 0x8; 66 constexpr int kStreamStateDestroyed = 0x10; 67 constexpr int kStreamStateTrailers = 0x20; 68 69 // Http2Session internal states 70 constexpr int kSessionStateNone = 0x0; 71 constexpr int kSessionStateHasScope = 0x1; 72 constexpr int kSessionStateWriteScheduled = 0x2; 73 constexpr int kSessionStateClosed = 0x4; 74 constexpr int kSessionStateClosing = 0x8; 75 constexpr int kSessionStateSending = 0x10; 76 constexpr int kSessionStateWriteInProgress = 0x20; 77 constexpr int kSessionStateReadingStopped = 0x40; 78 constexpr int kSessionStateReceivePaused = 0x80; 79 80 // The Padding Strategy determines the method by which extra padding is 81 // selected for HEADERS and DATA frames. These are configurable via the 82 // options passed in to a Http2Session object. 83 enum PaddingStrategy { 84 // No padding strategy. This is the default. 85 PADDING_STRATEGY_NONE, 86 // Attempts to ensure that the frame is 8-byte aligned 87 PADDING_STRATEGY_ALIGNED, 88 // Padding will ensure all data frames are maxFrameSize 89 PADDING_STRATEGY_MAX, 90 // Removed and turned into an alias because it is unreasonably expensive for 91 // very little benefit. 92 PADDING_STRATEGY_CALLBACK = PADDING_STRATEGY_ALIGNED 93 }; 94 95 enum SessionType { 96 NGHTTP2_SESSION_SERVER, 97 NGHTTP2_SESSION_CLIENT 98 }; 99 100 template <typename T, void(*fn)(T*)> 101 struct Nghttp2Deleter { 102 void operator()(T* ptr) const noexcept { fn(ptr); } 103 }; 104 105 using Nghttp2OptionPointer = 106 std::unique_ptr<nghttp2_option, 107 Nghttp2Deleter<nghttp2_option, nghttp2_option_del>>; 108 109 using Nghttp2SessionPointer = 110 std::unique_ptr<nghttp2_session, 111 Nghttp2Deleter<nghttp2_session, nghttp2_session_del>>; 112 113 using Nghttp2SessionCallbacksPointer = 114 std::unique_ptr<nghttp2_session_callbacks, 115 Nghttp2Deleter<nghttp2_session_callbacks, 116 nghttp2_session_callbacks_del>>; 117 118 struct Http2HeadersTraits { 119 typedef nghttp2_nv nv_t; 120 }; 121 122 struct Http2RcBufferPointerTraits { 123 typedef nghttp2_rcbuf rcbuf_t; 124 typedef nghttp2_vec vector_t; 125 126 static void inc(rcbuf_t* buf) { 127 CHECK_NOT_NULL(buf); 128 nghttp2_rcbuf_incref(buf); 129 } 130 static void dec(rcbuf_t* buf) { 131 CHECK_NOT_NULL(buf); 132 nghttp2_rcbuf_decref(buf); 133 } 134 static vector_t get_vec(rcbuf_t* buf) { 135 CHECK_NOT_NULL(buf); 136 return nghttp2_rcbuf_get_buf(buf); 137 } 138 static bool is_static(const rcbuf_t* buf) { 139 CHECK_NOT_NULL(buf); 140 return nghttp2_rcbuf_is_static(buf); 141 } 142 }; 143 144 using Http2Headers = NgHeaders<Http2HeadersTraits>; 145 using Http2RcBufferPointer = NgRcBufPointer<Http2RcBufferPointerTraits>; 146 147 struct NgHttp2StreamWrite : public MemoryRetainer { 148 BaseObjectPtr<AsyncWrap> req_wrap; 149 uv_buf_t buf; 150 151 inline explicit NgHttp2StreamWrite(uv_buf_t buf_) : buf(buf_) {} 152 inline NgHttp2StreamWrite(BaseObjectPtr<AsyncWrap> req_wrap, uv_buf_t buf_) : 153 req_wrap(std::move(req_wrap)), buf(buf_) {} 154 155 void MemoryInfo(MemoryTracker* tracker) const override; 156 SET_MEMORY_INFO_NAME(NgHttp2StreamWrite) 157 SET_SELF_SIZE(NgHttp2StreamWrite) 158 }; 159 160 typedef uint32_t(*get_setting)(nghttp2_session* session, 161 nghttp2_settings_id id); 162 163 class Http2Ping; 164 class Http2Session; 165 class Http2Settings; 166 class Http2Stream; 167 class Origins; 168 169 // This scope should be present when any call into nghttp2 that may schedule 170 // data to be written to the underlying transport is made, and schedules 171 // such a write automatically once the scope is exited. 172 class Http2Scope { 173 public: 174 explicit Http2Scope(Http2Stream* stream); 175 explicit Http2Scope(Http2Session* session); 176 ~Http2Scope(); 177 178 private: 179 BaseObjectPtr<Http2Session> session_; 180 }; 181 182 // The Http2Options class is used to parse the options object passed in to 183 // a Http2Session object and convert those into an appropriate nghttp2_option 184 // struct. This is the primary mechanism by which the Http2Session object is 185 // configured. 186 class Http2Options { 187 public: 188 Http2Options(Http2State* http2_state, 189 SessionType type); 190 191 ~Http2Options() = default; 192 193 nghttp2_option* operator*() const { 194 return options_.get(); 195 } 196 197 void set_max_header_pairs(uint32_t max) { 198 max_header_pairs_ = max; 199 } 200 201 uint32_t max_header_pairs() const { 202 return max_header_pairs_; 203 } 204 205 void set_padding_strategy(PaddingStrategy val) { 206 padding_strategy_ = val; 207 } 208 209 PaddingStrategy padding_strategy() const { 210 return padding_strategy_; 211 } 212 213 void set_max_outstanding_pings(size_t max) { 214 max_outstanding_pings_ = max; 215 } 216 217 size_t max_outstanding_pings() const { 218 return max_outstanding_pings_; 219 } 220 221 void set_max_outstanding_settings(size_t max) { 222 max_outstanding_settings_ = max; 223 } 224 225 size_t max_outstanding_settings() const { 226 return max_outstanding_settings_; 227 } 228 229 void set_max_session_memory(uint64_t max) { 230 max_session_memory_ = max; 231 } 232 233 uint64_t max_session_memory() const { 234 return max_session_memory_; 235 } 236 237 private: 238 Nghttp2OptionPointer options_; 239 uint64_t max_session_memory_ = kDefaultMaxSessionMemory; 240 uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; 241 PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE; 242 size_t max_outstanding_pings_ = kDefaultMaxPings; 243 size_t max_outstanding_settings_ = kDefaultMaxSettings; 244 }; 245 246 struct Http2Priority : public nghttp2_priority_spec { 247 Http2Priority(Environment* env, 248 v8::Local<v8::Value> parent, 249 v8::Local<v8::Value> weight, 250 v8::Local<v8::Value> exclusive); 251 }; 252 253 class Http2StreamListener : public StreamListener { 254 public: 255 uv_buf_t OnStreamAlloc(size_t suggested_size) override; 256 void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override; 257 }; 258 259 struct Http2HeaderTraits { 260 typedef Http2RcBufferPointer rcbufferpointer_t; 261 typedef Http2Session allocator_t; 262 263 // HTTP/2 does not support identifying header names by token id. 264 // HTTP/3 will, however, so we prepare for that now. 265 static const char* ToHttpHeaderName(int32_t token) { return nullptr; } 266 }; 267 268 using Http2Header = NgHeader<Http2HeaderTraits>; 269 270 class Http2Stream : public AsyncWrap, 271 public StreamBase { 272 public: 273 static Http2Stream* New( 274 Http2Session* session, 275 int32_t id, 276 nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS, 277 int options = 0); 278 ~Http2Stream() override; 279 280 nghttp2_stream* operator*() const; 281 282 nghttp2_stream* stream() const; 283 284 Http2Session* session() { return session_.get(); } 285 const Http2Session* session() const { return session_.get(); } 286 287 // Required for StreamBase 288 int ReadStart() override; 289 290 // Required for StreamBase 291 int ReadStop() override; 292 293 // Required for StreamBase 294 ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override; 295 int DoShutdown(ShutdownWrap* req_wrap) override; 296 297 bool HasWantsWrite() const override { return true; } 298 299 // Initiate a response on this stream. 300 int SubmitResponse(const Http2Headers& headers, int options); 301 302 // Submit informational headers for this stream 303 int SubmitInfo(const Http2Headers& headers); 304 305 // Submit trailing headers for this stream 306 int SubmitTrailers(const Http2Headers& headers); 307 void OnTrailers(); 308 309 // Submit a PRIORITY frame for this stream 310 int SubmitPriority(const Http2Priority& priority, bool silent = false); 311 312 // Submits an RST_STREAM frame using the given code 313 void SubmitRstStream(const uint32_t code); 314 315 void FlushRstStream(); 316 317 // Submits a PUSH_PROMISE frame with this stream as the parent. 318 Http2Stream* SubmitPushPromise( 319 const Http2Headers& headers, 320 int32_t* ret, 321 int options = 0); 322 323 324 void Close(int32_t code); 325 326 // Destroy this stream instance and free all held memory. 327 void Destroy(); 328 329 bool is_destroyed() const { 330 return flags_ & kStreamStateDestroyed; 331 } 332 333 bool is_writable() const { 334 return !(flags_ & kStreamStateShut); 335 } 336 337 bool is_paused() const { 338 return flags_ & kStreamStateReadPaused; 339 } 340 341 bool is_closed() const { 342 return flags_ & kStreamStateClosed; 343 } 344 345 bool has_trailers() const { 346 return flags_ & kStreamStateTrailers; 347 } 348 349 void set_has_trailers(bool on = true) { 350 if (on) 351 flags_ |= kStreamStateTrailers; 352 else 353 flags_ &= ~kStreamStateTrailers; 354 } 355 356 void set_closed() { 357 flags_ |= kStreamStateClosed; 358 } 359 360 void set_destroyed() { 361 flags_ |= kStreamStateDestroyed; 362 } 363 364 void set_not_writable() { 365 flags_ |= kStreamStateShut; 366 } 367 368 void set_reading(bool on = true) { 369 if (on) { 370 flags_ |= kStreamStateReadStart; 371 set_paused(false); 372 } else {} 373 } 374 375 void set_paused(bool on = true) { 376 if (on) 377 flags_ |= kStreamStateReadPaused; 378 else 379 flags_ &= ~kStreamStateReadPaused; 380 } 381 382 // Returns true if this stream is in the reading state, which occurs when 383 // the kStreamStateReadStart flag has been set and the 384 // kStreamStateReadPaused flag is *not* set. 385 bool is_reading() const { 386 return flags_ & kStreamStateReadStart && !is_paused(); 387 } 388 389 // Returns the RST_STREAM code used to close this stream 390 int32_t code() const { return code_; } 391 392 // Returns the stream identifier for this stream 393 int32_t id() const { return id_; } 394 395 void IncrementAvailableOutboundLength(size_t amount); 396 void DecrementAvailableOutboundLength(size_t amount); 397 398 bool AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags); 399 400 template <typename Fn> 401 void TransferHeaders(Fn&& fn) { 402 size_t i = 0; 403 for (const auto& header : current_headers_ ) 404 fn(header, i++); 405 ClearHeaders(); 406 } 407 408 void ClearHeaders() { 409 current_headers_.clear(); 410 } 411 412 size_t headers_count() const { 413 return current_headers_.size(); 414 } 415 416 nghttp2_headers_category headers_category() const { 417 return current_headers_category_; 418 } 419 420 void StartHeaders(nghttp2_headers_category category); 421 422 // Required for StreamBase 423 bool IsAlive() override { 424 return true; 425 } 426 427 // Required for StreamBase 428 bool IsClosing() override { 429 return false; 430 } 431 432 AsyncWrap* GetAsyncWrap() override { return this; } 433 434 int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count, 435 uv_stream_t* send_handle) override; 436 437 void MemoryInfo(MemoryTracker* tracker) const override; 438 SET_MEMORY_INFO_NAME(Http2Stream) 439 SET_SELF_SIZE(Http2Stream) 440 441 std::string diagnostic_name() const override; 442 443 // JavaScript API 444 static void GetID(const v8::FunctionCallbackInfo<v8::Value>& args); 445 static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args); 446 static void Priority(const v8::FunctionCallbackInfo<v8::Value>& args); 447 static void PushPromise(const v8::FunctionCallbackInfo<v8::Value>& args); 448 static void RefreshState(const v8::FunctionCallbackInfo<v8::Value>& args); 449 static void Info(const v8::FunctionCallbackInfo<v8::Value>& args); 450 static void Trailers(const v8::FunctionCallbackInfo<v8::Value>& args); 451 static void Respond(const v8::FunctionCallbackInfo<v8::Value>& args); 452 static void RstStream(const v8::FunctionCallbackInfo<v8::Value>& args); 453 454 class Provider; 455 456 struct Statistics { 457 uint64_t start_time; 458 uint64_t end_time; 459 uint64_t first_header; // Time first header was received 460 uint64_t first_byte; // Time first DATA frame byte was received 461 uint64_t first_byte_sent; // Time first DATA frame byte was sent 462 uint64_t sent_bytes; 463 uint64_t received_bytes; 464 uint64_t id; 465 }; 466 467 Statistics statistics_ = {}; 468 469 private: 470 Http2Stream(Http2Session* session, 471 v8::Local<v8::Object> obj, 472 int32_t id, 473 nghttp2_headers_category category, 474 int options); 475 476 void EmitStatistics(); 477 478 BaseObjectWeakPtr<Http2Session> session_; // The Parent HTTP/2 Session 479 int32_t id_ = 0; // The Stream Identifier 480 int32_t code_ = NGHTTP2_NO_ERROR; // The RST_STREAM code (if any) 481 int flags_ = kStreamStateNone; // Internal state flags 482 483 uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; 484 uint32_t max_header_length_ = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE; 485 486 // The Current Headers block... As headers are received for this stream, 487 // they are temporarily stored here until the OnFrameReceived is called 488 // signalling the end of the HEADERS frame 489 nghttp2_headers_category current_headers_category_ = NGHTTP2_HCAT_HEADERS; 490 uint32_t current_headers_length_ = 0; // total number of octets 491 std::vector<Http2Header> current_headers_; 492 493 // This keeps track of the amount of data read from the socket while the 494 // socket was in paused mode. When `ReadStart()` is called (and not before 495 // then), we tell nghttp2 that we consumed that data to get proper 496 // backpressure handling. 497 size_t inbound_consumed_data_while_paused_ = 0; 498 499 // Outbound Data... This is the data written by the JS layer that is 500 // waiting to be written out to the socket. 501 std::queue<NgHttp2StreamWrite> queue_; 502 size_t available_outbound_length_ = 0; 503 504 Http2StreamListener stream_listener_; 505 506 friend class Http2Session; 507 }; 508 509 class Http2Stream::Provider { 510 public: 511 Provider(Http2Stream* stream, int options); 512 explicit Provider(int options); 513 virtual ~Provider(); 514 515 nghttp2_data_provider* operator*() { 516 return !empty_ ? &provider_ : nullptr; 517 } 518 519 class FD; 520 class Stream; 521 protected: 522 nghttp2_data_provider provider_; 523 524 private: 525 bool empty_ = false; 526 }; 527 528 class Http2Stream::Provider::Stream : public Http2Stream::Provider { 529 public: 530 Stream(Http2Stream* stream, int options); 531 explicit Stream(int options); 532 533 static ssize_t OnRead(nghttp2_session* session, 534 int32_t id, 535 uint8_t* buf, 536 size_t length, 537 uint32_t* flags, 538 nghttp2_data_source* source, 539 void* user_data); 540 }; 541 542 struct SessionJSFields { 543 uint8_t bitfield; 544 uint8_t priority_listener_count; 545 uint8_t frame_error_listener_count; 546 uint32_t max_invalid_frames = 1000; 547 uint32_t max_rejected_streams = 100; 548 }; 549 550 // Indices for js_fields_, which serves as a way to communicate data with JS 551 // land fast. In particular, we store information about the number/presence 552 // of certain event listeners in JS, and skip calls from C++ into JS if they 553 // are missing. 554 enum SessionUint8Fields { 555 kBitfield = offsetof(SessionJSFields, bitfield), // See below 556 kSessionPriorityListenerCount = 557 offsetof(SessionJSFields, priority_listener_count), 558 kSessionFrameErrorListenerCount = 559 offsetof(SessionJSFields, frame_error_listener_count), 560 kSessionMaxInvalidFrames = offsetof(SessionJSFields, max_invalid_frames), 561 kSessionMaxRejectedStreams = offsetof(SessionJSFields, max_rejected_streams), 562 kSessionUint8FieldCount = sizeof(SessionJSFields) 563 }; 564 565 enum SessionBitfieldFlags { 566 kSessionHasRemoteSettingsListeners, 567 kSessionRemoteSettingsIsUpToDate, 568 kSessionHasPingListeners, 569 kSessionHasAltsvcListeners 570 }; 571 572 class Http2Session : public AsyncWrap, 573 public StreamListener, 574 public mem::NgLibMemoryManager<Http2Session, nghttp2_mem> { 575 public: 576 Http2Session(Http2State* http2_state, 577 v8::Local<v8::Object> wrap, 578 SessionType type = NGHTTP2_SESSION_SERVER); 579 ~Http2Session() override; 580 581 StreamBase* underlying_stream() { 582 return static_cast<StreamBase*>(stream_); 583 } 584 585 void Close(uint32_t code = NGHTTP2_NO_ERROR, 586 bool socket_closed = false); 587 588 void Consume(v8::Local<v8::Object> stream); 589 590 void Goaway(uint32_t code, int32_t lastStreamID, 591 const uint8_t* data, size_t len); 592 593 void AltSvc(int32_t id, 594 uint8_t* origin, 595 size_t origin_len, 596 uint8_t* value, 597 size_t value_len); 598 599 void Origin(const Origins& origins); 600 601 uint8_t SendPendingData(); 602 603 // Submits a new request. If the request is a success, assigned 604 // will be a pointer to the Http2Stream instance assigned. 605 // This only works if the session is a client session. 606 Http2Stream* SubmitRequest( 607 const Http2Priority& priority, 608 const Http2Headers& headers, 609 int32_t* ret, 610 int options = 0); 611 612 SessionType type() const { return session_type_; } 613 614 nghttp2_session* session() const { return session_.get(); } 615 616 nghttp2_session* operator*() { return session_.get(); } 617 618 uint32_t max_header_pairs() const { return max_header_pairs_; } 619 620 const char* TypeName() const; 621 622 bool is_destroyed() { 623 return (flags_ & kSessionStateClosed) || session_ == nullptr; 624 } 625 626 void set_destroyed() { 627 flags_ |= kSessionStateClosed; 628 } 629 630 struct custom_settings_state { 631 size_t number; 632 nghttp2_settings_entry entries[MAX_ADDITIONAL_SETTINGS]; 633 }; 634 635 custom_settings_state& custom_settings(bool local) { 636 return local ? local_custom_settings_ : remote_custom_settings_; 637 } 638 639 #define IS_FLAG(name, flag) \ 640 bool is_##name() const { return flags_ & flag; } \ 641 void set_##name(bool on = true) { \ 642 if (on) \ 643 flags_ |= flag; \ 644 else \ 645 flags_ &= ~flag; \ 646 } 647 648 IS_FLAG(in_scope, kSessionStateHasScope) 649 IS_FLAG(write_scheduled, kSessionStateWriteScheduled) 650 IS_FLAG(closing, kSessionStateClosing) 651 IS_FLAG(sending, kSessionStateSending) 652 IS_FLAG(write_in_progress, kSessionStateWriteInProgress) 653 IS_FLAG(reading_stopped, kSessionStateReadingStopped) 654 IS_FLAG(receive_paused, kSessionStateReceivePaused) 655 656 #undef IS_FLAG 657 658 // Schedule a write if nghttp2 indicates it wants to write to the socket. 659 void MaybeScheduleWrite(); 660 661 // Stop reading if nghttp2 doesn't want to anymore. 662 void MaybeStopReading(); 663 664 // Returns pointer to the stream, or nullptr if stream does not exist 665 BaseObjectPtr<Http2Stream> FindStream(int32_t id); 666 667 bool CanAddStream(); 668 669 // Adds a stream instance to this session 670 void AddStream(Http2Stream* stream); 671 672 // Removes a stream instance from this session 673 BaseObjectPtr<Http2Stream> RemoveStream(int32_t id); 674 675 // Indicates whether there currently exist outgoing buffers for this stream. 676 bool HasWritesOnSocketForStream(Http2Stream* stream); 677 678 // Write data from stream_buf_ to the session. 679 // This will call the error callback if an error occurs. 680 void ConsumeHTTP2Data(); 681 682 void MemoryInfo(MemoryTracker* tracker) const override; 683 SET_MEMORY_INFO_NAME(Http2Session) 684 SET_SELF_SIZE(Http2Session) 685 686 std::string diagnostic_name() const override; 687 688 // Schedule an RstStream for after the current write finishes. 689 void AddPendingRstStream(int32_t stream_id) { 690 pending_rst_streams_.emplace_back(stream_id); 691 } 692 693 bool has_pending_rststream(int32_t stream_id) { 694 return pending_rst_streams_.end() != 695 std::find(pending_rst_streams_.begin(), 696 pending_rst_streams_.end(), 697 stream_id); 698 } 699 700 // Handle reads/writes from the underlying network transport. 701 uv_buf_t OnStreamAlloc(size_t suggested_size) override; 702 void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override; 703 void OnStreamAfterWrite(WriteWrap* w, int status) override; 704 705 // Implementation for mem::NgLibMemoryManager 706 void CheckAllocatedSize(size_t previous_size) const; 707 void IncreaseAllocatedSize(size_t size); 708 void DecreaseAllocatedSize(size_t size); 709 710 // The JavaScript API 711 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 712 static void Consume(const v8::FunctionCallbackInfo<v8::Value>& args); 713 static void Receive(const v8::FunctionCallbackInfo<v8::Value>& args); 714 static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args); 715 static void HasPendingData(const v8::FunctionCallbackInfo<v8::Value>& args); 716 static void Settings(const v8::FunctionCallbackInfo<v8::Value>& args); 717 static void Request(const v8::FunctionCallbackInfo<v8::Value>& args); 718 static void SetNextStreamID(const v8::FunctionCallbackInfo<v8::Value>& args); 719 static void SetLocalWindowSize( 720 const v8::FunctionCallbackInfo<v8::Value>& args); 721 static void Goaway(const v8::FunctionCallbackInfo<v8::Value>& args); 722 static void UpdateChunksSent(const v8::FunctionCallbackInfo<v8::Value>& args); 723 static void RefreshState(const v8::FunctionCallbackInfo<v8::Value>& args); 724 static void Ping(const v8::FunctionCallbackInfo<v8::Value>& args); 725 static void AltSvc(const v8::FunctionCallbackInfo<v8::Value>& args); 726 static void Origin(const v8::FunctionCallbackInfo<v8::Value>& args); 727 static void SetGracefulClose(const v8::FunctionCallbackInfo<v8::Value>& args); 728 729 template <get_setting fn, bool local> 730 static void RefreshSettings(const v8::FunctionCallbackInfo<v8::Value>& args); 731 732 uv_loop_t* event_loop() const { 733 return env()->event_loop(); 734 } 735 736 Http2State* http2_state() const { return http2_state_.get(); } 737 738 BaseObjectPtr<Http2Ping> PopPing(); 739 bool AddPing(const uint8_t* data, v8::Local<v8::Function> callback); 740 bool HasPendingData() const; 741 742 BaseObjectPtr<Http2Settings> PopSettings(); 743 bool AddSettings(v8::Local<v8::Function> callback); 744 745 void IncrementCurrentSessionMemory(uint64_t amount) { 746 current_session_memory_ += amount; 747 } 748 749 void DecrementCurrentSessionMemory(uint64_t amount) { 750 DCHECK_LE(amount, current_session_memory_); 751 current_session_memory_ -= amount; 752 } 753 754 void UpdateLocalCustomSettings(size_t count_, 755 nghttp2_settings_entry* entries_); 756 757 // Tell our custom memory allocator that this rcbuf is independent of 758 // this session now, and may outlive it. 759 void StopTrackingRcbuf(nghttp2_rcbuf* buf); 760 761 // Returns the current session memory including memory allocated by nghttp2, 762 // the current outbound storage queue, and pending writes. 763 uint64_t current_session_memory() const { 764 uint64_t total = current_session_memory_ + sizeof(Http2Session); 765 total += current_nghttp2_memory_; 766 total += outgoing_storage_.size(); 767 return total; 768 } 769 770 // Return true if current_session_memory + amount is less than the max 771 bool has_available_session_memory(uint64_t amount) const { 772 return current_session_memory() + amount <= max_session_memory_; 773 } 774 775 struct Statistics { 776 uint64_t start_time; 777 uint64_t end_time; 778 uint64_t ping_rtt; 779 uint64_t data_sent; 780 uint64_t data_received; 781 uint32_t frame_count; 782 uint32_t frame_sent; 783 int32_t stream_count; 784 size_t max_concurrent_streams; 785 double stream_average_duration; 786 SessionType session_type; 787 }; 788 789 Statistics statistics_ = {}; 790 791 bool IsGracefulCloseInitiated() const { 792 return graceful_close_initiated_; 793 } 794 void SetGracefulCloseInitiated(bool value) { 795 graceful_close_initiated_ = value; 796 } 797 798 private: 799 void EmitStatistics(); 800 801 void FetchAllowedRemoteCustomSettings(); 802 803 // Frame Padding Strategies 804 ssize_t OnDWordAlignedPadding(size_t frameLength, 805 size_t maxPayloadLen); 806 ssize_t OnMaxFrameSizePadding(size_t frameLength, 807 size_t maxPayloadLen); 808 809 // Frame Handler 810 int HandleDataFrame(const nghttp2_frame* frame); 811 void HandleGoawayFrame(const nghttp2_frame* frame); 812 void HandleHeadersFrame(const nghttp2_frame* frame); 813 void HandlePriorityFrame(const nghttp2_frame* frame); 814 void HandleSettingsFrame(const nghttp2_frame* frame); 815 void HandlePingFrame(const nghttp2_frame* frame); 816 void HandleAltSvcFrame(const nghttp2_frame* frame); 817 void HandleOriginFrame(const nghttp2_frame* frame); 818 819 void DecrefHeaders(const nghttp2_frame* frame); 820 821 // nghttp2 callbacks 822 static int OnBeginHeadersCallback( 823 nghttp2_session* session, 824 const nghttp2_frame* frame, 825 void* user_data); 826 static int OnHeaderCallback( 827 nghttp2_session* session, 828 const nghttp2_frame* frame, 829 nghttp2_rcbuf* name, 830 nghttp2_rcbuf* value, 831 uint8_t flags, 832 void* user_data); 833 static int OnFrameReceive( 834 nghttp2_session* session, 835 const nghttp2_frame* frame, 836 void* user_data); 837 static int OnFrameNotSent( 838 nghttp2_session* session, 839 const nghttp2_frame* frame, 840 int error_code, 841 void* user_data); 842 static int OnFrameSent( 843 nghttp2_session* session, 844 const nghttp2_frame* frame, 845 void* user_data); 846 static int OnStreamClose( 847 nghttp2_session* session, 848 int32_t id, 849 uint32_t code, 850 void* user_data); 851 static int OnInvalidHeader( 852 nghttp2_session* session, 853 const nghttp2_frame* frame, 854 nghttp2_rcbuf* name, 855 nghttp2_rcbuf* value, 856 uint8_t flags, 857 void* user_data); 858 static int OnDataChunkReceived( 859 nghttp2_session* session, 860 uint8_t flags, 861 int32_t id, 862 const uint8_t* data, 863 size_t len, 864 void* user_data); 865 static ssize_t OnSelectPadding( 866 nghttp2_session* session, 867 const nghttp2_frame* frame, 868 size_t maxPayloadLen, 869 void* user_data); 870 static int OnNghttpError(nghttp2_session* session, 871 int lib_error_code, 872 const char* message, 873 size_t len, 874 void* user_data); 875 static int OnSendData( 876 nghttp2_session* session, 877 nghttp2_frame* frame, 878 const uint8_t* framehd, 879 size_t length, 880 nghttp2_data_source* source, 881 void* user_data); 882 static int OnInvalidFrame( 883 nghttp2_session* session, 884 const nghttp2_frame* frame, 885 int lib_error_code, 886 void* user_data); 887 888 struct Callbacks { 889 explicit Callbacks(bool kHasGetPaddingCallback); 890 891 Nghttp2SessionCallbacksPointer callbacks; 892 }; 893 894 /* Use callback_struct_saved[kHasGetPaddingCallback ? 1 : 0] */ 895 static const Callbacks callback_struct_saved[2]; 896 897 // The underlying nghttp2_session handle 898 Nghttp2SessionPointer session_; 899 900 // JS-accessible numeric fields, as indexed by SessionUint8Fields. 901 AliasedStruct<SessionJSFields> js_fields_; 902 903 // The session type: client or server 904 SessionType session_type_; 905 906 // The maximum number of header pairs permitted for streams on this session 907 uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; 908 909 // The maximum amount of memory allocated for this session 910 uint64_t max_session_memory_ = kDefaultMaxSessionMemory; 911 uint64_t current_session_memory_ = 0; 912 // The amount of memory allocated by nghttp2 internals 913 uint64_t current_nghttp2_memory_ = 0; 914 915 // The collection of active Http2Streams associated with this session 916 std::unordered_map<int32_t, BaseObjectPtr<Http2Stream>> streams_; 917 918 int flags_ = kSessionStateNone; 919 920 // The StreamBase instance being used for i/o 921 PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE; 922 923 // use this to allow timeout tracking during long-lasting writes 924 uint32_t chunks_sent_since_last_write_ = 0; 925 926 uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0); 927 // When processing input data, either stream_buf_ab_ or stream_buf_allocation_ 928 // will be set. stream_buf_ab_ is lazily created from stream_buf_allocation_. 929 v8::Global<v8::ArrayBuffer> stream_buf_ab_; 930 std::unique_ptr<v8::BackingStore> stream_buf_allocation_; 931 size_t stream_buf_offset_ = 0; 932 // Custom error code for errors that originated inside one of the callbacks 933 // called by nghttp2_session_mem_recv. 934 const char* custom_recv_error_code_ = nullptr; 935 936 size_t max_outstanding_pings_ = kDefaultMaxPings; 937 std::queue<BaseObjectPtr<Http2Ping>> outstanding_pings_; 938 939 size_t max_outstanding_settings_ = kDefaultMaxSettings; 940 std::queue<BaseObjectPtr<Http2Settings>> outstanding_settings_; 941 942 struct custom_settings_state local_custom_settings_; 943 struct custom_settings_state remote_custom_settings_; 944 945 std::vector<NgHttp2StreamWrite> outgoing_buffers_; 946 std::vector<uint8_t> outgoing_storage_; 947 size_t outgoing_length_ = 0; 948 std::vector<int32_t> pending_rst_streams_; 949 // Count streams that have been rejected while being opened. Exceeding a fixed 950 // limit will result in the session being destroyed, as an indication of a 951 // misbehaving peer. This counter is reset once new streams are being 952 // accepted again. 953 uint32_t rejected_stream_count_ = 0; 954 // Also use the invalid frame count as a measure for rejecting input frames. 955 uint32_t invalid_frame_count_ = 0; 956 957 void PushOutgoingBuffer(NgHttp2StreamWrite&& write); 958 959 BaseObjectPtr<Http2State> http2_state_; 960 961 void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); 962 void ClearOutgoing(int status); 963 964 void MaybeNotifyGracefulCloseComplete(); 965 966 friend class Http2Scope; 967 friend class Http2StreamListener; 968 969 // Flag to indicate that JavaScript has initiated a graceful closure 970 bool graceful_close_initiated_ = false; 971 }; 972 973 struct Http2SessionPerformanceEntryTraits { 974 static constexpr performance::PerformanceEntryType kType = 975 performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2; 976 977 using Details = Http2Session::Statistics; 978 979 static v8::MaybeLocal<v8::Object> GetDetails( 980 Environment* env, 981 const performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>& 982 entry); 983 }; 984 985 struct Http2StreamPerformanceEntryTraits { 986 static constexpr performance::PerformanceEntryType kType = 987 performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2; 988 989 using Details = Http2Stream::Statistics; 990 991 static v8::MaybeLocal<v8::Object> GetDetails( 992 Environment* env, 993 const performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>& 994 entry); 995 }; 996 997 using Http2SessionPerformanceEntry = 998 performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>; 999 using Http2StreamPerformanceEntry = 1000 performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>; 1001 1002 class Http2Ping : public AsyncWrap { 1003 public: 1004 explicit Http2Ping( 1005 Http2Session* session, 1006 v8::Local<v8::Object> obj, 1007 v8::Local<v8::Function> callback); 1008 1009 void MemoryInfo(MemoryTracker* tracker) const override; 1010 SET_MEMORY_INFO_NAME(Http2Ping) 1011 SET_SELF_SIZE(Http2Ping) 1012 1013 void Send(const uint8_t* payload); 1014 void Done(bool ack, const uint8_t* payload = nullptr); 1015 void DetachFromSession(); 1016 1017 v8::Local<v8::Function> callback() const; 1018 1019 private: 1020 BaseObjectWeakPtr<Http2Session> session_; 1021 v8::Global<v8::Function> callback_; 1022 uint64_t startTime_; 1023 }; 1024 1025 // The Http2Settings class is used to parse the settings passed in for 1026 // an Http2Session, converting those into an array of nghttp2_settings_entry 1027 // structs. 1028 class Http2Settings : public AsyncWrap { 1029 public: 1030 Http2Settings(Http2Session* session, 1031 v8::Local<v8::Object> obj, 1032 v8::Local<v8::Function> callback, 1033 uint64_t start_time = uv_hrtime()); 1034 1035 void MemoryInfo(MemoryTracker* tracker) const override; 1036 SET_MEMORY_INFO_NAME(Http2Settings) 1037 SET_SELF_SIZE(Http2Settings) 1038 1039 void Send(); 1040 void Done(bool ack); 1041 1042 v8::Local<v8::Function> callback() const; 1043 1044 // Returns a Buffer instance with the serialized SETTINGS payload 1045 v8::Local<v8::Value> Pack(); 1046 1047 static v8::Local<v8::Value> Pack(Http2State* state); 1048 1049 // Resets the default values in the settings buffer 1050 static void RefreshDefaults(Http2State* http2_state); 1051 1052 // Update the local or remote settings for the given session 1053 static void Update(Http2Session* session, get_setting fn, bool local); 1054 1055 private: 1056 static size_t Init( 1057 Http2State* http2_state, 1058 nghttp2_settings_entry* entries); 1059 1060 static v8::Local<v8::Value> Pack( 1061 Environment* env, 1062 size_t count, 1063 const nghttp2_settings_entry* entries); 1064 1065 BaseObjectWeakPtr<Http2Session> session_; 1066 v8::Global<v8::Function> callback_; 1067 uint64_t startTime_; 1068 size_t count_ = 0; 1069 nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT + MAX_ADDITIONAL_SETTINGS]; 1070 }; 1071 1072 class Origins { 1073 public: 1074 Origins(Environment* env, 1075 v8::Local<v8::String> origin_string, 1076 size_t origin_count); 1077 ~Origins() = default; 1078 1079 const nghttp2_origin_entry* operator*() const { 1080 return static_cast<const nghttp2_origin_entry*>(bs_->Data()); 1081 } 1082 1083 size_t length() const { 1084 return count_; 1085 } 1086 1087 private: 1088 size_t count_; 1089 std::unique_ptr<v8::BackingStore> bs_; 1090 }; 1091 1092 #define HTTP2_HIDDEN_CONSTANTS(V) \ 1093 V(NGHTTP2_HCAT_REQUEST) \ 1094 V(NGHTTP2_HCAT_RESPONSE) \ 1095 V(NGHTTP2_HCAT_PUSH_RESPONSE) \ 1096 V(NGHTTP2_HCAT_HEADERS) \ 1097 V(NGHTTP2_NV_FLAG_NONE) \ 1098 V(NGHTTP2_NV_FLAG_NO_INDEX) \ 1099 V(NGHTTP2_ERR_DEFERRED) \ 1100 V(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE) \ 1101 V(NGHTTP2_ERR_INVALID_ARGUMENT) \ 1102 V(NGHTTP2_ERR_STREAM_CLOSED) \ 1103 V(NGHTTP2_ERR_NOMEM) \ 1104 V(STREAM_OPTION_EMPTY_PAYLOAD) \ 1105 V(STREAM_OPTION_GET_TRAILERS) 1106 1107 #define HTTP2_ERROR_CODES(V) \ 1108 V(NGHTTP2_NO_ERROR) \ 1109 V(NGHTTP2_PROTOCOL_ERROR) \ 1110 V(NGHTTP2_INTERNAL_ERROR) \ 1111 V(NGHTTP2_FLOW_CONTROL_ERROR) \ 1112 V(NGHTTP2_SETTINGS_TIMEOUT) \ 1113 V(NGHTTP2_STREAM_CLOSED) \ 1114 V(NGHTTP2_FRAME_SIZE_ERROR) \ 1115 V(NGHTTP2_REFUSED_STREAM) \ 1116 V(NGHTTP2_CANCEL) \ 1117 V(NGHTTP2_COMPRESSION_ERROR) \ 1118 V(NGHTTP2_CONNECT_ERROR) \ 1119 V(NGHTTP2_ENHANCE_YOUR_CALM) \ 1120 V(NGHTTP2_INADEQUATE_SECURITY) \ 1121 V(NGHTTP2_HTTP_1_1_REQUIRED) \ 1122 1123 #define HTTP2_CONSTANTS(V) \ 1124 V(NGHTTP2_ERR_FRAME_SIZE_ERROR) \ 1125 V(NGHTTP2_SESSION_SERVER) \ 1126 V(NGHTTP2_SESSION_CLIENT) \ 1127 V(NGHTTP2_STREAM_STATE_IDLE) \ 1128 V(NGHTTP2_STREAM_STATE_OPEN) \ 1129 V(NGHTTP2_STREAM_STATE_RESERVED_LOCAL) \ 1130 V(NGHTTP2_STREAM_STATE_RESERVED_REMOTE) \ 1131 V(NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) \ 1132 V(NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE) \ 1133 V(NGHTTP2_STREAM_STATE_CLOSED) \ 1134 V(NGHTTP2_FLAG_NONE) \ 1135 V(NGHTTP2_FLAG_END_STREAM) \ 1136 V(NGHTTP2_FLAG_END_HEADERS) \ 1137 V(NGHTTP2_FLAG_ACK) \ 1138 V(NGHTTP2_FLAG_PADDED) \ 1139 V(NGHTTP2_FLAG_PRIORITY) \ 1140 V(DEFAULT_SETTINGS_HEADER_TABLE_SIZE) \ 1141 V(DEFAULT_SETTINGS_ENABLE_PUSH) \ 1142 V(DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS) \ 1143 V(DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE) \ 1144 V(DEFAULT_SETTINGS_MAX_FRAME_SIZE) \ 1145 V(DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE) \ 1146 V(DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL) \ 1147 V(MAX_MAX_FRAME_SIZE) \ 1148 V(MIN_MAX_FRAME_SIZE) \ 1149 V(MAX_INITIAL_WINDOW_SIZE) \ 1150 V(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) \ 1151 V(NGHTTP2_SETTINGS_ENABLE_PUSH) \ 1152 V(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) \ 1153 V(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE) \ 1154 V(NGHTTP2_SETTINGS_MAX_FRAME_SIZE) \ 1155 V(NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) \ 1156 V(NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) \ 1157 V(PADDING_STRATEGY_NONE) \ 1158 V(PADDING_STRATEGY_ALIGNED) \ 1159 V(PADDING_STRATEGY_MAX) \ 1160 V(PADDING_STRATEGY_CALLBACK) \ 1161 HTTP2_ERROR_CODES(V) 1162 1163 #define HTTP2_SETTINGS(V) \ 1164 V(HEADER_TABLE_SIZE) \ 1165 V(ENABLE_PUSH) \ 1166 V(MAX_CONCURRENT_STREAMS) \ 1167 V(INITIAL_WINDOW_SIZE) \ 1168 V(MAX_FRAME_SIZE) \ 1169 V(MAX_HEADER_LIST_SIZE) \ 1170 V(ENABLE_CONNECT_PROTOCOL) \ 1171 1172 } // namespace http2 1173 } // namespace node 1174 1175 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 1176 1177 #endif // SRC_NODE_HTTP2_H_