• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
operatorNghttp2Deleter102   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 
incHttp2RcBufferPointerTraits126   static void inc(rcbuf_t* buf) {
127     CHECK_NOT_NULL(buf);
128     nghttp2_rcbuf_incref(buf);
129   }
decHttp2RcBufferPointerTraits130   static void dec(rcbuf_t* buf) {
131     CHECK_NOT_NULL(buf);
132     nghttp2_rcbuf_decref(buf);
133   }
get_vecHttp2RcBufferPointerTraits134   static vector_t get_vec(rcbuf_t* buf) {
135     CHECK_NOT_NULL(buf);
136     return nghttp2_rcbuf_get_buf(buf);
137   }
is_staticHttp2RcBufferPointerTraits138   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 
NgHttp2StreamWriteNgHttp2StreamWrite151   inline explicit NgHttp2StreamWrite(uv_buf_t buf_) : buf(buf_) {}
NgHttp2StreamWriteNgHttp2StreamWrite152   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 
set_max_header_pairs(uint32_t max)197   void set_max_header_pairs(uint32_t max) {
198     max_header_pairs_ = max;
199   }
200 
max_header_pairs()201   uint32_t max_header_pairs() const {
202     return max_header_pairs_;
203   }
204 
set_padding_strategy(PaddingStrategy val)205   void set_padding_strategy(PaddingStrategy val) {
206     padding_strategy_ = val;
207   }
208 
padding_strategy()209   PaddingStrategy padding_strategy() const {
210     return padding_strategy_;
211   }
212 
set_max_outstanding_pings(size_t max)213   void set_max_outstanding_pings(size_t max) {
214     max_outstanding_pings_ = max;
215   }
216 
max_outstanding_pings()217   size_t max_outstanding_pings() const {
218     return max_outstanding_pings_;
219   }
220 
set_max_outstanding_settings(size_t max)221   void set_max_outstanding_settings(size_t max) {
222     max_outstanding_settings_ = max;
223   }
224 
max_outstanding_settings()225   size_t max_outstanding_settings() const {
226     return max_outstanding_settings_;
227   }
228 
set_max_session_memory(uint64_t max)229   void set_max_session_memory(uint64_t max) {
230     max_session_memory_ = max;
231   }
232 
max_session_memory()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.
ToHttpHeaderNameHttp2HeaderTraits265   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 
session()284   Http2Session* session() { return session_.get(); }
session()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 
HasWantsWrite()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 
is_destroyed()329   bool is_destroyed() const {
330     return flags_ & kStreamStateDestroyed;
331   }
332 
is_writable()333   bool is_writable() const {
334     return !(flags_ & kStreamStateShut);
335   }
336 
is_paused()337   bool is_paused() const {
338     return flags_ & kStreamStateReadPaused;
339   }
340 
is_closed()341   bool is_closed() const {
342     return flags_ & kStreamStateClosed;
343   }
344 
has_trailers()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 
set_closed()356   void set_closed() {
357     flags_ |= kStreamStateClosed;
358   }
359 
set_destroyed()360   void set_destroyed() {
361     flags_ |= kStreamStateDestroyed;
362   }
363 
set_not_writable()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.
is_reading()385   bool is_reading() const {
386     return flags_ & kStreamStateReadStart && !is_paused();
387   }
388 
389   // Returns the RST_STREAM code used to close this stream
code()390   int32_t code() const { return code_; }
391 
392   // Returns the stream identifier for this stream
id()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>
TransferHeaders(Fn && 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 
ClearHeaders()408   void ClearHeaders() {
409     current_headers_.clear();
410   }
411 
headers_count()412   size_t headers_count() const {
413     return current_headers_.size();
414   }
415 
headers_category()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
IsAlive()423   bool IsAlive() override {
424     return true;
425   }
426 
427   // Required for StreamBase
IsClosing()428   bool IsClosing() override {
429     return false;
430   }
431 
GetAsyncWrap()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 
underlying_stream()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 
type()612   SessionType type() const { return session_type_; }
613 
session()614   nghttp2_session* session() const { return session_.get(); }
615 
616   nghttp2_session* operator*() { return session_.get(); }
617 
max_header_pairs()618   uint32_t max_header_pairs() const { return max_header_pairs_; }
619 
620   const char* TypeName() const;
621 
is_destroyed()622   bool is_destroyed() {
623     return (flags_ & kSessionStateClosed) || session_ == nullptr;
624   }
625 
set_destroyed()626   void set_destroyed() {
627     flags_ |= kSessionStateClosed;
628   }
629 
630 #define IS_FLAG(name, flag)                                                    \
631   bool is_##name() const { return flags_ & flag; }                             \
632   void set_##name(bool on = true) {                                            \
633     if (on)                                                                    \
634       flags_ |= flag;                                                          \
635     else                                                                       \
636       flags_ &= ~flag;                                                         \
637   }
638 
639   IS_FLAG(in_scope, kSessionStateHasScope)
640   IS_FLAG(write_scheduled, kSessionStateWriteScheduled)
641   IS_FLAG(closing, kSessionStateClosing)
642   IS_FLAG(sending, kSessionStateSending)
643   IS_FLAG(write_in_progress, kSessionStateWriteInProgress)
644   IS_FLAG(reading_stopped, kSessionStateReadingStopped)
645   IS_FLAG(receive_paused, kSessionStateReceivePaused)
646 
647 #undef IS_FLAG
648 
649   // Schedule a write if nghttp2 indicates it wants to write to the socket.
650   void MaybeScheduleWrite();
651 
652   // Stop reading if nghttp2 doesn't want to anymore.
653   void MaybeStopReading();
654 
655   // Returns pointer to the stream, or nullptr if stream does not exist
656   BaseObjectPtr<Http2Stream> FindStream(int32_t id);
657 
658   bool CanAddStream();
659 
660   // Adds a stream instance to this session
661   void AddStream(Http2Stream* stream);
662 
663   // Removes a stream instance from this session
664   BaseObjectPtr<Http2Stream> RemoveStream(int32_t id);
665 
666   // Indicates whether there currently exist outgoing buffers for this stream.
667   bool HasWritesOnSocketForStream(Http2Stream* stream);
668 
669   // Write data from stream_buf_ to the session.
670   // This will call the error callback if an error occurs.
671   void ConsumeHTTP2Data();
672 
673   void MemoryInfo(MemoryTracker* tracker) const override;
674   SET_MEMORY_INFO_NAME(Http2Session)
675   SET_SELF_SIZE(Http2Session)
676 
677   std::string diagnostic_name() const override;
678 
679   // Schedule an RstStream for after the current write finishes.
AddPendingRstStream(int32_t stream_id)680   void AddPendingRstStream(int32_t stream_id) {
681     pending_rst_streams_.emplace_back(stream_id);
682   }
683 
has_pending_rststream(int32_t stream_id)684   bool has_pending_rststream(int32_t stream_id) {
685     return pending_rst_streams_.end() !=
686         std::find(pending_rst_streams_.begin(),
687             pending_rst_streams_.end(),
688             stream_id);
689   }
690 
691   // Handle reads/writes from the underlying network transport.
692   uv_buf_t OnStreamAlloc(size_t suggested_size) override;
693   void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
694   void OnStreamAfterWrite(WriteWrap* w, int status) override;
695 
696   // Implementation for mem::NgLibMemoryManager
697   void CheckAllocatedSize(size_t previous_size) const;
698   void IncreaseAllocatedSize(size_t size);
699   void DecreaseAllocatedSize(size_t size);
700 
701   // The JavaScript API
702   static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
703   static void Consume(const v8::FunctionCallbackInfo<v8::Value>& args);
704   static void Receive(const v8::FunctionCallbackInfo<v8::Value>& args);
705   static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);
706   static void Settings(const v8::FunctionCallbackInfo<v8::Value>& args);
707   static void Request(const v8::FunctionCallbackInfo<v8::Value>& args);
708   static void SetNextStreamID(const v8::FunctionCallbackInfo<v8::Value>& args);
709   static void SetLocalWindowSize(
710       const v8::FunctionCallbackInfo<v8::Value>& args);
711   static void Goaway(const v8::FunctionCallbackInfo<v8::Value>& args);
712   static void UpdateChunksSent(const v8::FunctionCallbackInfo<v8::Value>& args);
713   static void RefreshState(const v8::FunctionCallbackInfo<v8::Value>& args);
714   static void Ping(const v8::FunctionCallbackInfo<v8::Value>& args);
715   static void AltSvc(const v8::FunctionCallbackInfo<v8::Value>& args);
716   static void Origin(const v8::FunctionCallbackInfo<v8::Value>& args);
717 
718   template <get_setting fn>
719   static void RefreshSettings(const v8::FunctionCallbackInfo<v8::Value>& args);
720 
event_loop()721   uv_loop_t* event_loop() const {
722     return env()->event_loop();
723   }
724 
http2_state()725   Http2State* http2_state() const { return http2_state_.get(); }
726 
727   BaseObjectPtr<Http2Ping> PopPing();
728   bool AddPing(const uint8_t* data, v8::Local<v8::Function> callback);
729 
730   BaseObjectPtr<Http2Settings> PopSettings();
731   bool AddSettings(v8::Local<v8::Function> callback);
732 
IncrementCurrentSessionMemory(uint64_t amount)733   void IncrementCurrentSessionMemory(uint64_t amount) {
734     current_session_memory_ += amount;
735   }
736 
DecrementCurrentSessionMemory(uint64_t amount)737   void DecrementCurrentSessionMemory(uint64_t amount) {
738     DCHECK_LE(amount, current_session_memory_);
739     current_session_memory_ -= amount;
740   }
741 
742   // Tell our custom memory allocator that this rcbuf is independent of
743   // this session now, and may outlive it.
744   void StopTrackingRcbuf(nghttp2_rcbuf* buf);
745 
746   // Returns the current session memory including memory allocated by nghttp2,
747   // the current outbound storage queue, and pending writes.
current_session_memory()748   uint64_t current_session_memory() const {
749     uint64_t total = current_session_memory_ + sizeof(Http2Session);
750     total += current_nghttp2_memory_;
751     total += outgoing_storage_.size();
752     return total;
753   }
754 
755   // Return true if current_session_memory + amount is less than the max
has_available_session_memory(uint64_t amount)756   bool has_available_session_memory(uint64_t amount) const {
757     return current_session_memory() + amount <= max_session_memory_;
758   }
759 
760   struct Statistics {
761     uint64_t start_time;
762     uint64_t end_time;
763     uint64_t ping_rtt;
764     uint64_t data_sent;
765     uint64_t data_received;
766     uint32_t frame_count;
767     uint32_t frame_sent;
768     int32_t stream_count;
769     size_t max_concurrent_streams;
770     double stream_average_duration;
771     SessionType session_type;
772   };
773 
774   Statistics statistics_ = {};
775 
776  private:
777   void EmitStatistics();
778 
779   // Frame Padding Strategies
780   ssize_t OnDWordAlignedPadding(size_t frameLength,
781                                 size_t maxPayloadLen);
782   ssize_t OnMaxFrameSizePadding(size_t frameLength,
783                                 size_t maxPayloadLen);
784 
785   // Frame Handler
786   int HandleDataFrame(const nghttp2_frame* frame);
787   void HandleGoawayFrame(const nghttp2_frame* frame);
788   void HandleHeadersFrame(const nghttp2_frame* frame);
789   void HandlePriorityFrame(const nghttp2_frame* frame);
790   void HandleSettingsFrame(const nghttp2_frame* frame);
791   void HandlePingFrame(const nghttp2_frame* frame);
792   void HandleAltSvcFrame(const nghttp2_frame* frame);
793   void HandleOriginFrame(const nghttp2_frame* frame);
794 
795   void DecrefHeaders(const nghttp2_frame* frame);
796 
797   // nghttp2 callbacks
798   static int OnBeginHeadersCallback(
799       nghttp2_session* session,
800       const nghttp2_frame* frame,
801       void* user_data);
802   static int OnHeaderCallback(
803       nghttp2_session* session,
804       const nghttp2_frame* frame,
805       nghttp2_rcbuf* name,
806       nghttp2_rcbuf* value,
807       uint8_t flags,
808       void* user_data);
809   static int OnFrameReceive(
810       nghttp2_session* session,
811       const nghttp2_frame* frame,
812       void* user_data);
813   static int OnFrameNotSent(
814       nghttp2_session* session,
815       const nghttp2_frame* frame,
816       int error_code,
817       void* user_data);
818   static int OnFrameSent(
819       nghttp2_session* session,
820       const nghttp2_frame* frame,
821       void* user_data);
822   static int OnStreamClose(
823       nghttp2_session* session,
824       int32_t id,
825       uint32_t code,
826       void* user_data);
827   static int OnInvalidHeader(
828       nghttp2_session* session,
829       const nghttp2_frame* frame,
830       nghttp2_rcbuf* name,
831       nghttp2_rcbuf* value,
832       uint8_t flags,
833       void* user_data);
834   static int OnDataChunkReceived(
835       nghttp2_session* session,
836       uint8_t flags,
837       int32_t id,
838       const uint8_t* data,
839       size_t len,
840       void* user_data);
841   static ssize_t OnSelectPadding(
842       nghttp2_session* session,
843       const nghttp2_frame* frame,
844       size_t maxPayloadLen,
845       void* user_data);
846   static int OnNghttpError(nghttp2_session* session,
847                            int lib_error_code,
848                            const char* message,
849                            size_t len,
850                            void* user_data);
851   static int OnSendData(
852       nghttp2_session* session,
853       nghttp2_frame* frame,
854       const uint8_t* framehd,
855       size_t length,
856       nghttp2_data_source* source,
857       void* user_data);
858   static int OnInvalidFrame(
859       nghttp2_session* session,
860       const nghttp2_frame* frame,
861       int lib_error_code,
862       void* user_data);
863 
864   struct Callbacks {
865     explicit Callbacks(bool kHasGetPaddingCallback);
866 
867     Nghttp2SessionCallbacksPointer callbacks;
868   };
869 
870   /* Use callback_struct_saved[kHasGetPaddingCallback ? 1 : 0] */
871   static const Callbacks callback_struct_saved[2];
872 
873   // The underlying nghttp2_session handle
874   Nghttp2SessionPointer session_;
875 
876   // JS-accessible numeric fields, as indexed by SessionUint8Fields.
877   AliasedStruct<SessionJSFields> js_fields_;
878 
879   // The session type: client or server
880   SessionType session_type_;
881 
882   // The maximum number of header pairs permitted for streams on this session
883   uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
884 
885   // The maximum amount of memory allocated for this session
886   uint64_t max_session_memory_ = kDefaultMaxSessionMemory;
887   uint64_t current_session_memory_ = 0;
888   // The amount of memory allocated by nghttp2 internals
889   uint64_t current_nghttp2_memory_ = 0;
890 
891   // The collection of active Http2Streams associated with this session
892   std::unordered_map<int32_t, BaseObjectPtr<Http2Stream>> streams_;
893 
894   int flags_ = kSessionStateNone;
895 
896   // The StreamBase instance being used for i/o
897   PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE;
898 
899   // use this to allow timeout tracking during long-lasting writes
900   uint32_t chunks_sent_since_last_write_ = 0;
901 
902   uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0);
903   // When processing input data, either stream_buf_ab_ or stream_buf_allocation_
904   // will be set. stream_buf_ab_ is lazily created from stream_buf_allocation_.
905   v8::Global<v8::ArrayBuffer> stream_buf_ab_;
906   std::unique_ptr<v8::BackingStore> stream_buf_allocation_;
907   size_t stream_buf_offset_ = 0;
908   // Custom error code for errors that originated inside one of the callbacks
909   // called by nghttp2_session_mem_recv.
910   const char* custom_recv_error_code_ = nullptr;
911 
912   size_t max_outstanding_pings_ = kDefaultMaxPings;
913   std::queue<BaseObjectPtr<Http2Ping>> outstanding_pings_;
914 
915   size_t max_outstanding_settings_ = kDefaultMaxSettings;
916   std::queue<BaseObjectPtr<Http2Settings>> outstanding_settings_;
917 
918   std::vector<NgHttp2StreamWrite> outgoing_buffers_;
919   std::vector<uint8_t> outgoing_storage_;
920   size_t outgoing_length_ = 0;
921   std::vector<int32_t> pending_rst_streams_;
922   // Count streams that have been rejected while being opened. Exceeding a fixed
923   // limit will result in the session being destroyed, as an indication of a
924   // misbehaving peer. This counter is reset once new streams are being
925   // accepted again.
926   uint32_t rejected_stream_count_ = 0;
927   // Also use the invalid frame count as a measure for rejecting input frames.
928   uint32_t invalid_frame_count_ = 0;
929 
930   void PushOutgoingBuffer(NgHttp2StreamWrite&& write);
931 
932   BaseObjectPtr<Http2State> http2_state_;
933 
934   void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);
935   void ClearOutgoing(int status);
936 
937   friend class Http2Scope;
938   friend class Http2StreamListener;
939 };
940 
941 struct Http2SessionPerformanceEntryTraits {
942   static constexpr performance::PerformanceEntryType kType =
943       performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2;
944 
945   using Details = Http2Session::Statistics;
946 
947   static v8::MaybeLocal<v8::Object> GetDetails(
948       Environment* env,
949       const performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>&
950           entry);
951 };
952 
953 struct Http2StreamPerformanceEntryTraits {
954   static constexpr performance::PerformanceEntryType kType =
955       performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2;
956 
957   using Details = Http2Stream::Statistics;
958 
959   static v8::MaybeLocal<v8::Object> GetDetails(
960       Environment* env,
961       const performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>&
962           entry);
963 };
964 
965 using Http2SessionPerformanceEntry =
966     performance::PerformanceEntry<Http2SessionPerformanceEntryTraits>;
967 using Http2StreamPerformanceEntry =
968     performance::PerformanceEntry<Http2StreamPerformanceEntryTraits>;
969 
970 class Http2Ping : public AsyncWrap {
971  public:
972   explicit Http2Ping(
973       Http2Session* session,
974       v8::Local<v8::Object> obj,
975       v8::Local<v8::Function> callback);
976 
977   void MemoryInfo(MemoryTracker* tracker) const override;
978   SET_MEMORY_INFO_NAME(Http2Ping)
979   SET_SELF_SIZE(Http2Ping)
980 
981   void Send(const uint8_t* payload);
982   void Done(bool ack, const uint8_t* payload = nullptr);
983   void DetachFromSession();
984 
985   v8::Local<v8::Function> callback() const;
986 
987  private:
988   BaseObjectWeakPtr<Http2Session> session_;
989   v8::Global<v8::Function> callback_;
990   uint64_t startTime_;
991 };
992 
993 // The Http2Settings class is used to parse the settings passed in for
994 // an Http2Session, converting those into an array of nghttp2_settings_entry
995 // structs.
996 class Http2Settings : public AsyncWrap {
997  public:
998   Http2Settings(Http2Session* session,
999                 v8::Local<v8::Object> obj,
1000                 v8::Local<v8::Function> callback,
1001                 uint64_t start_time = uv_hrtime());
1002 
1003   void MemoryInfo(MemoryTracker* tracker) const override;
1004   SET_MEMORY_INFO_NAME(Http2Settings)
1005   SET_SELF_SIZE(Http2Settings)
1006 
1007   void Send();
1008   void Done(bool ack);
1009 
1010   v8::Local<v8::Function> callback() const;
1011 
1012   // Returns a Buffer instance with the serialized SETTINGS payload
1013   v8::Local<v8::Value> Pack();
1014 
1015   static v8::Local<v8::Value> Pack(Http2State* state);
1016 
1017   // Resets the default values in the settings buffer
1018   static void RefreshDefaults(Http2State* http2_state);
1019 
1020   // Update the local or remote settings for the given session
1021   static void Update(Http2Session* session,
1022                      get_setting fn);
1023 
1024  private:
1025   static size_t Init(
1026       Http2State* http2_state,
1027       nghttp2_settings_entry* entries);
1028 
1029   static v8::Local<v8::Value> Pack(
1030       Environment* env,
1031       size_t count,
1032       const nghttp2_settings_entry* entries);
1033 
1034   BaseObjectWeakPtr<Http2Session> session_;
1035   v8::Global<v8::Function> callback_;
1036   uint64_t startTime_;
1037   size_t count_ = 0;
1038   nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT];
1039 };
1040 
1041 class Origins {
1042  public:
1043   Origins(Environment* env,
1044           v8::Local<v8::String> origin_string,
1045           size_t origin_count);
1046   ~Origins() = default;
1047 
1048   const nghttp2_origin_entry* operator*() const {
1049     return static_cast<const nghttp2_origin_entry*>(bs_->Data());
1050   }
1051 
length()1052   size_t length() const {
1053     return count_;
1054   }
1055 
1056  private:
1057   size_t count_;
1058   std::unique_ptr<v8::BackingStore> bs_;
1059 };
1060 
1061 #define HTTP2_HIDDEN_CONSTANTS(V)                                              \
1062   V(NGHTTP2_HCAT_REQUEST)                                                      \
1063   V(NGHTTP2_HCAT_RESPONSE)                                                     \
1064   V(NGHTTP2_HCAT_PUSH_RESPONSE)                                                \
1065   V(NGHTTP2_HCAT_HEADERS)                                                      \
1066   V(NGHTTP2_NV_FLAG_NONE)                                                      \
1067   V(NGHTTP2_NV_FLAG_NO_INDEX)                                                  \
1068   V(NGHTTP2_ERR_DEFERRED)                                                      \
1069   V(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE)                                       \
1070   V(NGHTTP2_ERR_INVALID_ARGUMENT)                                              \
1071   V(NGHTTP2_ERR_STREAM_CLOSED)                                                 \
1072   V(NGHTTP2_ERR_NOMEM)                                                         \
1073   V(STREAM_OPTION_EMPTY_PAYLOAD)                                               \
1074   V(STREAM_OPTION_GET_TRAILERS)
1075 
1076 #define HTTP2_ERROR_CODES(V)                                                   \
1077   V(NGHTTP2_NO_ERROR)                                                          \
1078   V(NGHTTP2_PROTOCOL_ERROR)                                                    \
1079   V(NGHTTP2_INTERNAL_ERROR)                                                    \
1080   V(NGHTTP2_FLOW_CONTROL_ERROR)                                                \
1081   V(NGHTTP2_SETTINGS_TIMEOUT)                                                  \
1082   V(NGHTTP2_STREAM_CLOSED)                                                     \
1083   V(NGHTTP2_FRAME_SIZE_ERROR)                                                  \
1084   V(NGHTTP2_REFUSED_STREAM)                                                    \
1085   V(NGHTTP2_CANCEL)                                                            \
1086   V(NGHTTP2_COMPRESSION_ERROR)                                                 \
1087   V(NGHTTP2_CONNECT_ERROR)                                                     \
1088   V(NGHTTP2_ENHANCE_YOUR_CALM)                                                 \
1089   V(NGHTTP2_INADEQUATE_SECURITY)                                               \
1090   V(NGHTTP2_HTTP_1_1_REQUIRED)                                                 \
1091 
1092 #define HTTP2_CONSTANTS(V)                                                     \
1093   V(NGHTTP2_ERR_FRAME_SIZE_ERROR)                                              \
1094   V(NGHTTP2_SESSION_SERVER)                                                    \
1095   V(NGHTTP2_SESSION_CLIENT)                                                    \
1096   V(NGHTTP2_STREAM_STATE_IDLE)                                                 \
1097   V(NGHTTP2_STREAM_STATE_OPEN)                                                 \
1098   V(NGHTTP2_STREAM_STATE_RESERVED_LOCAL)                                       \
1099   V(NGHTTP2_STREAM_STATE_RESERVED_REMOTE)                                      \
1100   V(NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL)                                    \
1101   V(NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE)                                   \
1102   V(NGHTTP2_STREAM_STATE_CLOSED)                                               \
1103   V(NGHTTP2_FLAG_NONE)                                                         \
1104   V(NGHTTP2_FLAG_END_STREAM)                                                   \
1105   V(NGHTTP2_FLAG_END_HEADERS)                                                  \
1106   V(NGHTTP2_FLAG_ACK)                                                          \
1107   V(NGHTTP2_FLAG_PADDED)                                                       \
1108   V(NGHTTP2_FLAG_PRIORITY)                                                     \
1109   V(DEFAULT_SETTINGS_HEADER_TABLE_SIZE)                                        \
1110   V(DEFAULT_SETTINGS_ENABLE_PUSH)                                              \
1111   V(DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS)                                   \
1112   V(DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE)                                      \
1113   V(DEFAULT_SETTINGS_MAX_FRAME_SIZE)                                           \
1114   V(DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE)                                     \
1115   V(DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL)                                  \
1116   V(MAX_MAX_FRAME_SIZE)                                                        \
1117   V(MIN_MAX_FRAME_SIZE)                                                        \
1118   V(MAX_INITIAL_WINDOW_SIZE)                                                   \
1119   V(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE)                                        \
1120   V(NGHTTP2_SETTINGS_ENABLE_PUSH)                                              \
1121   V(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)                                   \
1122   V(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE)                                      \
1123   V(NGHTTP2_SETTINGS_MAX_FRAME_SIZE)                                           \
1124   V(NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE)                                     \
1125   V(NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL)                                  \
1126   V(PADDING_STRATEGY_NONE)                                                     \
1127   V(PADDING_STRATEGY_ALIGNED)                                                  \
1128   V(PADDING_STRATEGY_MAX)                                                      \
1129   V(PADDING_STRATEGY_CALLBACK)                                                 \
1130   HTTP2_ERROR_CODES(V)
1131 
1132 #define HTTP2_SETTINGS(V)                                                      \
1133   V(HEADER_TABLE_SIZE)                                                         \
1134   V(ENABLE_PUSH)                                                               \
1135   V(MAX_CONCURRENT_STREAMS)                                                    \
1136   V(INITIAL_WINDOW_SIZE)                                                       \
1137   V(MAX_FRAME_SIZE)                                                            \
1138   V(MAX_HEADER_LIST_SIZE)                                                      \
1139   V(ENABLE_CONNECT_PROTOCOL)                                                   \
1140 
1141 }  // namespace http2
1142 }  // namespace node
1143 
1144 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1145 
1146 #endif  // SRC_NODE_HTTP2_H_
1147