• 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 // FIXME(joyeecheung): nghttp2.h needs stdint.h to compile on Windows
7 #include <cstdint>
8 #include "nghttp2/nghttp2.h"
9 
10 #include "node_http2_state.h"
11 #include "node_mem.h"
12 #include "node_perf.h"
13 #include "stream_base-inl.h"
14 #include "string_bytes.h"
15 
16 #include <algorithm>
17 #include <queue>
18 
19 namespace node {
20 namespace http2 {
21 
22 using v8::Array;
23 using v8::Context;
24 using v8::Isolate;
25 using v8::MaybeLocal;
26 
27 using performance::PerformanceEntry;
28 
29 // We strictly limit the number of outstanding unacknowledged PINGS a user
30 // may send in order to prevent abuse. The current default cap is 10. The
31 // user may set a different limit using a per Http2Session configuration
32 // option.
33 #define DEFAULT_MAX_PINGS 10
34 
35 // Also strictly limit the number of outstanding SETTINGS frames a user sends
36 #define DEFAULT_MAX_SETTINGS 10
37 
38 // Default maximum total memory cap for Http2Session.
39 #define DEFAULT_MAX_SESSION_MEMORY 1e7
40 
41 // These are the standard HTTP/2 defaults as specified by the RFC
42 #define DEFAULT_SETTINGS_HEADER_TABLE_SIZE 4096
43 #define DEFAULT_SETTINGS_ENABLE_PUSH 1
44 #define DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS 0xffffffffu
45 #define DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE 65535
46 #define DEFAULT_SETTINGS_MAX_FRAME_SIZE 16384
47 #define DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE 65535
48 #define DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL 0
49 #define MAX_MAX_FRAME_SIZE 16777215
50 #define MIN_MAX_FRAME_SIZE DEFAULT_SETTINGS_MAX_FRAME_SIZE
51 #define MAX_INITIAL_WINDOW_SIZE 2147483647
52 
53 #define MAX_MAX_HEADER_LIST_SIZE 16777215u
54 #define DEFAULT_MAX_HEADER_LIST_PAIRS 128u
55 
56 enum nghttp2_session_type {
57   NGHTTP2_SESSION_SERVER,
58   NGHTTP2_SESSION_CLIENT
59 };
60 
61 enum nghttp2_stream_flags {
62   NGHTTP2_STREAM_FLAG_NONE = 0x0,
63   // Writable side has ended
64   NGHTTP2_STREAM_FLAG_SHUT = 0x1,
65   // Reading has started
66   NGHTTP2_STREAM_FLAG_READ_START = 0x2,
67   // Reading is paused
68   NGHTTP2_STREAM_FLAG_READ_PAUSED = 0x4,
69   // Stream is closed
70   NGHTTP2_STREAM_FLAG_CLOSED = 0x8,
71   // Stream is destroyed
72   NGHTTP2_STREAM_FLAG_DESTROYED = 0x10,
73   // Stream has trailers
74   NGHTTP2_STREAM_FLAG_TRAILERS = 0x20,
75   // Stream has received all the data it can
76   NGHTTP2_STREAM_FLAG_EOS = 0x40
77 };
78 
79 enum nghttp2_stream_options {
80   // Stream is not going to have any DATA frames
81   STREAM_OPTION_EMPTY_PAYLOAD = 0x1,
82   // Stream might have trailing headers
83   STREAM_OPTION_GET_TRAILERS = 0x2,
84 };
85 
86 struct nghttp2_stream_write : public MemoryRetainer {
87   WriteWrap* req_wrap = nullptr;
88   uv_buf_t buf;
89 
nghttp2_stream_writenghttp2_stream_write90   inline explicit nghttp2_stream_write(uv_buf_t buf_) : buf(buf_) {}
nghttp2_stream_writenghttp2_stream_write91   inline nghttp2_stream_write(WriteWrap* req, uv_buf_t buf_) :
92       req_wrap(req), buf(buf_) {}
93 
94   void MemoryInfo(MemoryTracker* tracker) const override;
95   SET_MEMORY_INFO_NAME(nghttp2_stream_write)
96   SET_SELF_SIZE(nghttp2_stream_write)
97 };
98 
99 struct nghttp2_header : public MemoryRetainer {
100   nghttp2_rcbuf* name = nullptr;
101   nghttp2_rcbuf* value = nullptr;
102   uint8_t flags = 0;
103 
104   void MemoryInfo(MemoryTracker* tracker) const override;
105   SET_MEMORY_INFO_NAME(nghttp2_header)
106   SET_SELF_SIZE(nghttp2_header)
107 };
108 
109 
110 // Unlike the HTTP/1 implementation, the HTTP/2 implementation is not limited
111 // to a fixed number of known supported HTTP methods. These constants, therefore
112 // are provided strictly as a convenience to users and are exposed via the
113 // require('http2').constants object.
114 #define HTTP_KNOWN_METHODS(V)                                                 \
115   V(ACL, "ACL")                                                               \
116   V(BASELINE_CONTROL, "BASELINE-CONTROL")                                     \
117   V(BIND, "BIND")                                                             \
118   V(CHECKIN, "CHECKIN")                                                       \
119   V(CHECKOUT, "CHECKOUT")                                                     \
120   V(CONNECT, "CONNECT")                                                       \
121   V(COPY, "COPY")                                                             \
122   V(DELETE, "DELETE")                                                         \
123   V(GET, "GET")                                                               \
124   V(HEAD, "HEAD")                                                             \
125   V(LABEL, "LABEL")                                                           \
126   V(LINK, "LINK")                                                             \
127   V(LOCK, "LOCK")                                                             \
128   V(MERGE, "MERGE")                                                           \
129   V(MKACTIVITY, "MKACTIVITY")                                                 \
130   V(MKCALENDAR, "MKCALENDAR")                                                 \
131   V(MKCOL, "MKCOL")                                                           \
132   V(MKREDIRECTREF, "MKREDIRECTREF")                                           \
133   V(MKWORKSPACE, "MKWORKSPACE")                                               \
134   V(MOVE, "MOVE")                                                             \
135   V(OPTIONS, "OPTIONS")                                                       \
136   V(ORDERPATCH, "ORDERPATCH")                                                 \
137   V(PATCH, "PATCH")                                                           \
138   V(POST, "POST")                                                             \
139   V(PRI, "PRI")                                                               \
140   V(PROPFIND, "PROPFIND")                                                     \
141   V(PROPPATCH, "PROPPATCH")                                                   \
142   V(PUT, "PUT")                                                               \
143   V(REBIND, "REBIND")                                                         \
144   V(REPORT, "REPORT")                                                         \
145   V(SEARCH, "SEARCH")                                                         \
146   V(TRACE, "TRACE")                                                           \
147   V(UNBIND, "UNBIND")                                                         \
148   V(UNCHECKOUT, "UNCHECKOUT")                                                 \
149   V(UNLINK, "UNLINK")                                                         \
150   V(UNLOCK, "UNLOCK")                                                         \
151   V(UPDATE, "UPDATE")                                                         \
152   V(UPDATEREDIRECTREF, "UPDATEREDIRECTREF")                                   \
153   V(VERSION_CONTROL, "VERSION-CONTROL")
154 
155 // These are provided strictly as a convenience to users and are exposed via the
156 // require('http2').constants objects
157 #define HTTP_KNOWN_HEADERS(V)                                                 \
158   V(STATUS, ":status")                                                        \
159   V(METHOD, ":method")                                                        \
160   V(AUTHORITY, ":authority")                                                  \
161   V(SCHEME, ":scheme")                                                        \
162   V(PATH, ":path")                                                            \
163   V(PROTOCOL, ":protocol")                                                    \
164   V(ACCEPT_CHARSET, "accept-charset")                                         \
165   V(ACCEPT_ENCODING, "accept-encoding")                                       \
166   V(ACCEPT_LANGUAGE, "accept-language")                                       \
167   V(ACCEPT_RANGES, "accept-ranges")                                           \
168   V(ACCEPT, "accept")                                                         \
169   V(ACCESS_CONTROL_ALLOW_CREDENTIALS, "access-control-allow-credentials")     \
170   V(ACCESS_CONTROL_ALLOW_HEADERS, "access-control-allow-headers")             \
171   V(ACCESS_CONTROL_ALLOW_METHODS, "access-control-allow-methods")             \
172   V(ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin")               \
173   V(ACCESS_CONTROL_EXPOSE_HEADERS, "access-control-expose-headers")           \
174   V(ACCESS_CONTROL_MAX_AGE, "access-control-max-age")                         \
175   V(ACCESS_CONTROL_REQUEST_HEADERS, "access-control-request-headers")         \
176   V(ACCESS_CONTROL_REQUEST_METHOD, "access-control-request-method")           \
177   V(AGE, "age")                                                               \
178   V(ALLOW, "allow")                                                           \
179   V(AUTHORIZATION, "authorization")                                           \
180   V(CACHE_CONTROL, "cache-control")                                           \
181   V(CONNECTION, "connection")                                                 \
182   V(CONTENT_DISPOSITION, "content-disposition")                               \
183   V(CONTENT_ENCODING, "content-encoding")                                     \
184   V(CONTENT_LANGUAGE, "content-language")                                     \
185   V(CONTENT_LENGTH, "content-length")                                         \
186   V(CONTENT_LOCATION, "content-location")                                     \
187   V(CONTENT_MD5, "content-md5")                                               \
188   V(CONTENT_RANGE, "content-range")                                           \
189   V(CONTENT_TYPE, "content-type")                                             \
190   V(COOKIE, "cookie")                                                         \
191   V(DATE, "date")                                                             \
192   V(DNT, "dnt")                                                               \
193   V(ETAG, "etag")                                                             \
194   V(EXPECT, "expect")                                                         \
195   V(EXPIRES, "expires")                                                       \
196   V(FORWARDED, "forwarded")                                                   \
197   V(FROM, "from")                                                             \
198   V(HOST, "host")                                                             \
199   V(IF_MATCH, "if-match")                                                     \
200   V(IF_MODIFIED_SINCE, "if-modified-since")                                   \
201   V(IF_NONE_MATCH, "if-none-match")                                           \
202   V(IF_RANGE, "if-range")                                                     \
203   V(IF_UNMODIFIED_SINCE, "if-unmodified-since")                               \
204   V(LAST_MODIFIED, "last-modified")                                           \
205   V(LINK, "link")                                                             \
206   V(LOCATION, "location")                                                     \
207   V(MAX_FORWARDS, "max-forwards")                                             \
208   V(PREFER, "prefer")                                                         \
209   V(PROXY_AUTHENTICATE, "proxy-authenticate")                                 \
210   V(PROXY_AUTHORIZATION, "proxy-authorization")                               \
211   V(RANGE, "range")                                                           \
212   V(REFERER, "referer")                                                       \
213   V(REFRESH, "refresh")                                                       \
214   V(RETRY_AFTER, "retry-after")                                               \
215   V(SERVER, "server")                                                         \
216   V(SET_COOKIE, "set-cookie")                                                 \
217   V(STRICT_TRANSPORT_SECURITY, "strict-transport-security")                   \
218   V(TRAILER, "trailer")                                                       \
219   V(TRANSFER_ENCODING, "transfer-encoding")                                   \
220   V(TE, "te")                                                                 \
221   V(TK, "tk")                                                                 \
222   V(UPGRADE_INSECURE_REQUESTS, "upgrade-insecure-requests")                   \
223   V(UPGRADE, "upgrade")                                                       \
224   V(USER_AGENT, "user-agent")                                                 \
225   V(VARY, "vary")                                                             \
226   V(VIA, "via")                                                               \
227   V(WARNING, "warning")                                                       \
228   V(WWW_AUTHENTICATE, "www-authenticate")                                     \
229   V(X_CONTENT_TYPE_OPTIONS, "x-content-type-options")                         \
230   V(X_FRAME_OPTIONS, "x-frame-options")                                       \
231   V(HTTP2_SETTINGS, "http2-settings")                                         \
232   V(KEEP_ALIVE, "keep-alive")                                                 \
233   V(PROXY_CONNECTION, "proxy-connection")
234 
235 enum http_known_headers {
236   HTTP_KNOWN_HEADER_MIN,
237 #define V(name, value) HTTP_HEADER_##name,
238   HTTP_KNOWN_HEADERS(V)
239 #undef V
240   HTTP_KNOWN_HEADER_MAX
241 };
242 
243 // While some of these codes are used within the HTTP/2 implementation in
244 // core, they are provided strictly as a convenience to users and are exposed
245 // via the require('http2').constants object.
246 #define HTTP_STATUS_CODES(V)                                                  \
247   V(CONTINUE, 100)                                                            \
248   V(SWITCHING_PROTOCOLS, 101)                                                 \
249   V(PROCESSING, 102)                                                          \
250   V(EARLY_HINTS, 103)                                                         \
251   V(OK, 200)                                                                  \
252   V(CREATED, 201)                                                             \
253   V(ACCEPTED, 202)                                                            \
254   V(NON_AUTHORITATIVE_INFORMATION, 203)                                       \
255   V(NO_CONTENT, 204)                                                          \
256   V(RESET_CONTENT, 205)                                                       \
257   V(PARTIAL_CONTENT, 206)                                                     \
258   V(MULTI_STATUS, 207)                                                        \
259   V(ALREADY_REPORTED, 208)                                                    \
260   V(IM_USED, 226)                                                             \
261   V(MULTIPLE_CHOICES, 300)                                                    \
262   V(MOVED_PERMANENTLY, 301)                                                   \
263   V(FOUND, 302)                                                               \
264   V(SEE_OTHER, 303)                                                           \
265   V(NOT_MODIFIED, 304)                                                        \
266   V(USE_PROXY, 305)                                                           \
267   V(TEMPORARY_REDIRECT, 307)                                                  \
268   V(PERMANENT_REDIRECT, 308)                                                  \
269   V(BAD_REQUEST, 400)                                                         \
270   V(UNAUTHORIZED, 401)                                                        \
271   V(PAYMENT_REQUIRED, 402)                                                    \
272   V(FORBIDDEN, 403)                                                           \
273   V(NOT_FOUND, 404)                                                           \
274   V(METHOD_NOT_ALLOWED, 405)                                                  \
275   V(NOT_ACCEPTABLE, 406)                                                      \
276   V(PROXY_AUTHENTICATION_REQUIRED, 407)                                       \
277   V(REQUEST_TIMEOUT, 408)                                                     \
278   V(CONFLICT, 409)                                                            \
279   V(GONE, 410)                                                                \
280   V(LENGTH_REQUIRED, 411)                                                     \
281   V(PRECONDITION_FAILED, 412)                                                 \
282   V(PAYLOAD_TOO_LARGE, 413)                                                   \
283   V(URI_TOO_LONG, 414)                                                        \
284   V(UNSUPPORTED_MEDIA_TYPE, 415)                                              \
285   V(RANGE_NOT_SATISFIABLE, 416)                                               \
286   V(EXPECTATION_FAILED, 417)                                                  \
287   V(TEAPOT, 418)                                                              \
288   V(MISDIRECTED_REQUEST, 421)                                                 \
289   V(UNPROCESSABLE_ENTITY, 422)                                                \
290   V(LOCKED, 423)                                                              \
291   V(FAILED_DEPENDENCY, 424)                                                   \
292   V(UNORDERED_COLLECTION, 425)                                                \
293   V(UPGRADE_REQUIRED, 426)                                                    \
294   V(PRECONDITION_REQUIRED, 428)                                               \
295   V(TOO_MANY_REQUESTS, 429)                                                   \
296   V(REQUEST_HEADER_FIELDS_TOO_LARGE, 431)                                     \
297   V(UNAVAILABLE_FOR_LEGAL_REASONS, 451)                                       \
298   V(INTERNAL_SERVER_ERROR, 500)                                               \
299   V(NOT_IMPLEMENTED, 501)                                                     \
300   V(BAD_GATEWAY, 502)                                                         \
301   V(SERVICE_UNAVAILABLE, 503)                                                 \
302   V(GATEWAY_TIMEOUT, 504)                                                     \
303   V(HTTP_VERSION_NOT_SUPPORTED, 505)                                          \
304   V(VARIANT_ALSO_NEGOTIATES, 506)                                             \
305   V(INSUFFICIENT_STORAGE, 507)                                                \
306   V(LOOP_DETECTED, 508)                                                       \
307   V(BANDWIDTH_LIMIT_EXCEEDED, 509)                                            \
308   V(NOT_EXTENDED, 510)                                                        \
309   V(NETWORK_AUTHENTICATION_REQUIRED, 511)
310 
311 enum http_status_codes {
312 #define V(name, code) HTTP_STATUS_##name = code,
313   HTTP_STATUS_CODES(V)
314 #undef V
315 };
316 
317 // The Padding Strategy determines the method by which extra padding is
318 // selected for HEADERS and DATA frames. These are configurable via the
319 // options passed in to a Http2Session object.
320 enum padding_strategy_type {
321   // No padding strategy. This is the default.
322   PADDING_STRATEGY_NONE,
323   // Attempts to ensure that the frame is 8-byte aligned
324   PADDING_STRATEGY_ALIGNED,
325   // Padding will ensure all data frames are maxFrameSize
326   PADDING_STRATEGY_MAX,
327   // Padding will be determined via a JS callback. Note that this can be
328   // expensive because the callback is called once for every DATA and
329   // HEADERS frame. For performance reasons, this strategy should be
330   // avoided.
331   PADDING_STRATEGY_CALLBACK
332 };
333 
334 enum session_state_flags {
335   SESSION_STATE_NONE = 0x0,
336   SESSION_STATE_HAS_SCOPE = 0x1,
337   SESSION_STATE_WRITE_SCHEDULED = 0x2,
338   SESSION_STATE_CLOSED = 0x4,
339   SESSION_STATE_CLOSING = 0x8,
340   SESSION_STATE_SENDING = 0x10,
341   SESSION_STATE_WRITE_IN_PROGRESS = 0x20,
342   SESSION_STATE_READING_STOPPED = 0x40,
343   SESSION_STATE_NGHTTP2_RECV_PAUSED = 0x80
344 };
345 
346 typedef uint32_t(*get_setting)(nghttp2_session* session,
347                                nghttp2_settings_id id);
348 
349 class Http2Session;
350 class Http2Stream;
351 
352 // This scope should be present when any call into nghttp2 that may schedule
353 // data to be written to the underlying transport is made, and schedules
354 // such a write automatically once the scope is exited.
355 class Http2Scope {
356  public:
357   explicit Http2Scope(Http2Stream* stream);
358   explicit Http2Scope(Http2Session* session);
359   ~Http2Scope();
360 
361  private:
362   Http2Session* session_ = nullptr;
363   Local<Object> session_handle_;
364 };
365 
366 // The Http2Options class is used to parse the options object passed in to
367 // a Http2Session object and convert those into an appropriate nghttp2_option
368 // struct. This is the primary mechanism by which the Http2Session object is
369 // configured.
370 class Http2Options {
371  public:
372   Http2Options(Environment* env, nghttp2_session_type type);
373 
~Http2Options()374   ~Http2Options() {
375     nghttp2_option_del(options_);
376   }
377 
378   nghttp2_option* operator*() const {
379     return options_;
380   }
381 
SetMaxHeaderPairs(uint32_t max)382   void SetMaxHeaderPairs(uint32_t max) {
383     max_header_pairs_ = max;
384   }
385 
GetMaxHeaderPairs()386   uint32_t GetMaxHeaderPairs() const {
387     return max_header_pairs_;
388   }
389 
SetPaddingStrategy(padding_strategy_type val)390   void SetPaddingStrategy(padding_strategy_type val) {
391     padding_strategy_ = val;
392   }
393 
GetPaddingStrategy()394   padding_strategy_type GetPaddingStrategy() const {
395     return padding_strategy_;
396   }
397 
SetMaxOutstandingPings(size_t max)398   void SetMaxOutstandingPings(size_t max) {
399     max_outstanding_pings_ = max;
400   }
401 
GetMaxOutstandingPings()402   size_t GetMaxOutstandingPings() {
403     return max_outstanding_pings_;
404   }
405 
SetMaxOutstandingSettings(size_t max)406   void SetMaxOutstandingSettings(size_t max) {
407     max_outstanding_settings_ = max;
408   }
409 
GetMaxOutstandingSettings()410   size_t GetMaxOutstandingSettings() {
411     return max_outstanding_settings_;
412   }
413 
SetMaxSessionMemory(uint64_t max)414   void SetMaxSessionMemory(uint64_t max) {
415     max_session_memory_ = max;
416   }
417 
GetMaxSessionMemory()418   uint64_t GetMaxSessionMemory() {
419     return max_session_memory_;
420   }
421 
422  private:
423   nghttp2_option* options_;
424   uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY;
425   uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
426   padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
427   size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
428   size_t max_outstanding_settings_ = DEFAULT_MAX_SETTINGS;
429 };
430 
431 class Http2Priority {
432  public:
433   Http2Priority(Environment* env,
434                 Local<Value> parent,
435                 Local<Value> weight,
436                 Local<Value> exclusive);
437 
438   nghttp2_priority_spec* operator*() {
439     return &spec;
440   }
441  private:
442   nghttp2_priority_spec spec;
443 };
444 
445 class Http2StreamListener : public StreamListener {
446  public:
447   uv_buf_t OnStreamAlloc(size_t suggested_size) override;
448   void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
449 };
450 
451 class Http2Stream : public AsyncWrap,
452                     public StreamBase {
453  public:
454   static Http2Stream* New(
455       Http2Session* session,
456       int32_t id,
457       nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,
458       int options = 0);
459   ~Http2Stream() override;
460 
461   nghttp2_stream* operator*();
462 
session()463   Http2Session* session() { return session_.get(); }
session()464   const Http2Session* session() const { return session_.get(); }
465 
466   void EmitStatistics();
467 
468   // Required for StreamBase
469   int ReadStart() override;
470 
471   // Required for StreamBase
472   int ReadStop() override;
473 
474   // Required for StreamBase
475   ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
476   int DoShutdown(ShutdownWrap* req_wrap) override;
477 
HasWantsWrite()478   bool HasWantsWrite() const override { return true; }
479 
480   // Initiate a response on this stream.
481   int SubmitResponse(nghttp2_nv* nva, size_t len, int options);
482 
483   // Submit informational headers for this stream
484   int SubmitInfo(nghttp2_nv* nva, size_t len);
485 
486   // Submit trailing headers for this stream
487   int SubmitTrailers(nghttp2_nv* nva, size_t len);
488   void OnTrailers();
489 
490   // Submit a PRIORITY frame for this stream
491   int SubmitPriority(nghttp2_priority_spec* prispec, bool silent = false);
492 
493   // Submits an RST_STREAM frame using the given code
494   void SubmitRstStream(const uint32_t code);
495 
496   void FlushRstStream();
497 
498   // Submits a PUSH_PROMISE frame with this stream as the parent.
499   Http2Stream* SubmitPushPromise(
500       nghttp2_nv* nva,
501       size_t len,
502       int32_t* ret,
503       int options = 0);
504 
505 
506   void Close(int32_t code);
507 
508   // Destroy this stream instance and free all held memory.
509   void Destroy();
510 
IsDestroyed()511   inline bool IsDestroyed() const {
512     return flags_ & NGHTTP2_STREAM_FLAG_DESTROYED;
513   }
514 
IsWritable()515   inline bool IsWritable() const {
516     return !(flags_ & NGHTTP2_STREAM_FLAG_SHUT);
517   }
518 
IsPaused()519   inline bool IsPaused() const {
520     return flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED;
521   }
522 
IsClosed()523   inline bool IsClosed() const {
524     return flags_ & NGHTTP2_STREAM_FLAG_CLOSED;
525   }
526 
HasTrailers()527   inline bool HasTrailers() const {
528     return flags_ & NGHTTP2_STREAM_FLAG_TRAILERS;
529   }
530 
531   // Returns true if this stream is in the reading state, which occurs when
532   // the NGHTTP2_STREAM_FLAG_READ_START flag has been set and the
533   // NGHTTP2_STREAM_FLAG_READ_PAUSED flag is *not* set.
IsReading()534   inline bool IsReading() const {
535     return flags_ & NGHTTP2_STREAM_FLAG_READ_START &&
536            !(flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED);
537   }
538 
539   // Returns the RST_STREAM code used to close this stream
code()540   inline int32_t code() const { return code_; }
541 
542   // Returns the stream identifier for this stream
id()543   inline int32_t id() const { return id_; }
544 
545   inline void IncrementAvailableOutboundLength(size_t amount);
546   inline void DecrementAvailableOutboundLength(size_t amount);
547 
548   bool AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags);
549 
move_headers()550   inline std::vector<nghttp2_header> move_headers() {
551     return std::move(current_headers_);
552   }
553 
headers_category()554   inline nghttp2_headers_category headers_category() const {
555     return current_headers_category_;
556   }
557 
558   void StartHeaders(nghttp2_headers_category category);
559 
560   // Required for StreamBase
IsAlive()561   bool IsAlive() override {
562     return true;
563   }
564 
565   // Required for StreamBase
IsClosing()566   bool IsClosing() override {
567     return false;
568   }
569 
GetAsyncWrap()570   AsyncWrap* GetAsyncWrap() override { return this; }
571 
572   int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
573               uv_stream_t* send_handle) override;
574 
MemoryInfo(MemoryTracker * tracker)575   void MemoryInfo(MemoryTracker* tracker) const override {
576     tracker->TrackField("current_headers", current_headers_);
577     tracker->TrackField("queue", queue_);
578   }
579 
580   SET_MEMORY_INFO_NAME(Http2Stream)
581   SET_SELF_SIZE(Http2Stream)
582 
583   std::string diagnostic_name() const override;
584 
585   // JavaScript API
586   static void GetID(const FunctionCallbackInfo<Value>& args);
587   static void Destroy(const FunctionCallbackInfo<Value>& args);
588   static void Priority(const FunctionCallbackInfo<Value>& args);
589   static void PushPromise(const FunctionCallbackInfo<Value>& args);
590   static void RefreshState(const FunctionCallbackInfo<Value>& args);
591   static void Info(const FunctionCallbackInfo<Value>& args);
592   static void Trailers(const FunctionCallbackInfo<Value>& args);
593   static void Respond(const FunctionCallbackInfo<Value>& args);
594   static void RstStream(const FunctionCallbackInfo<Value>& args);
595 
596   class Provider;
597 
598   struct Statistics {
599     uint64_t start_time;
600     uint64_t end_time;
601     uint64_t first_header;     // Time first header was received
602     uint64_t first_byte;       // Time first DATA frame byte was received
603     uint64_t first_byte_sent;  // Time first DATA frame byte was sent
604     uint64_t sent_bytes;
605     uint64_t received_bytes;
606   };
607 
608   Statistics statistics_ = {};
609 
610  private:
611   Http2Stream(Http2Session* session,
612               v8::Local<v8::Object> obj,
613               int32_t id,
614               nghttp2_headers_category category,
615               int options);
616 
617   BaseObjectWeakPtr<Http2Session> session_;     // The Parent HTTP/2 Session
618   int32_t id_ = 0;                              // The Stream Identifier
619   int32_t code_ = NGHTTP2_NO_ERROR;             // The RST_STREAM code (if any)
620   int flags_ = NGHTTP2_STREAM_FLAG_NONE;        // Internal state flags
621 
622   uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
623   uint32_t max_header_length_ = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE;
624 
625   // The Current Headers block... As headers are received for this stream,
626   // they are temporarily stored here until the OnFrameReceived is called
627   // signalling the end of the HEADERS frame
628   nghttp2_headers_category current_headers_category_ = NGHTTP2_HCAT_HEADERS;
629   uint32_t current_headers_length_ = 0;  // total number of octets
630   std::vector<nghttp2_header> current_headers_;
631 
632   // This keeps track of the amount of data read from the socket while the
633   // socket was in paused mode. When `ReadStart()` is called (and not before
634   // then), we tell nghttp2 that we consumed that data to get proper
635   // backpressure handling.
636   size_t inbound_consumed_data_while_paused_ = 0;
637 
638   // Outbound Data... This is the data written by the JS layer that is
639   // waiting to be written out to the socket.
640   std::queue<nghttp2_stream_write> queue_;
641   size_t available_outbound_length_ = 0;
642 
643   Http2StreamListener stream_listener_;
644 
645   friend class Http2Session;
646 };
647 
648 class Http2Stream::Provider {
649  public:
650   Provider(Http2Stream* stream, int options);
651   explicit Provider(int options);
652   virtual ~Provider();
653 
654   nghttp2_data_provider* operator*() {
655     return !empty_ ? &provider_ : nullptr;
656   }
657 
658   class FD;
659   class Stream;
660  protected:
661   nghttp2_data_provider provider_;
662 
663  private:
664   bool empty_ = false;
665 };
666 
667 class Http2Stream::Provider::Stream : public Http2Stream::Provider {
668  public:
669   Stream(Http2Stream* stream, int options);
670   explicit Stream(int options);
671 
672   static ssize_t OnRead(nghttp2_session* session,
673                         int32_t id,
674                         uint8_t* buf,
675                         size_t length,
676                         uint32_t* flags,
677                         nghttp2_data_source* source,
678                         void* user_data);
679 };
680 
681 struct SessionJSFields {
682   uint8_t bitfield;
683   uint8_t priority_listener_count;
684   uint8_t frame_error_listener_count;
685   uint32_t max_invalid_frames = 1000;
686   uint32_t max_rejected_streams = 100;
687 };
688 
689 // Indices for js_fields_, which serves as a way to communicate data with JS
690 // land fast. In particular, we store information about the number/presence
691 // of certain event listeners in JS, and skip calls from C++ into JS if they
692 // are missing.
693 enum SessionUint8Fields {
694   kBitfield = offsetof(SessionJSFields, bitfield),  // See below
695   kSessionPriorityListenerCount =
696       offsetof(SessionJSFields, priority_listener_count),
697   kSessionFrameErrorListenerCount =
698       offsetof(SessionJSFields, frame_error_listener_count),
699   kSessionMaxInvalidFrames = offsetof(SessionJSFields, max_invalid_frames),
700   kSessionMaxRejectedStreams = offsetof(SessionJSFields, max_rejected_streams),
701   kSessionUint8FieldCount = sizeof(SessionJSFields)
702 };
703 
704 enum SessionBitfieldFlags {
705   kSessionHasRemoteSettingsListeners,
706   kSessionRemoteSettingsIsUpToDate,
707   kSessionHasPingListeners,
708   kSessionHasAltsvcListeners
709 };
710 
711 class Http2Session : public AsyncWrap,
712                      public StreamListener,
713                      public mem::NgLibMemoryManager<Http2Session, nghttp2_mem> {
714  public:
715   Http2Session(Environment* env,
716                Local<Object> wrap,
717                nghttp2_session_type type = NGHTTP2_SESSION_SERVER);
718   ~Http2Session() override;
719 
720   class Http2Ping;
721   class Http2Settings;
722 
723   void EmitStatistics();
724 
underlying_stream()725   inline StreamBase* underlying_stream() {
726     return static_cast<StreamBase*>(stream_);
727   }
728 
729   void Close(uint32_t code = NGHTTP2_NO_ERROR,
730              bool socket_closed = false);
731   void Consume(Local<Object> stream);
732   void Goaway(uint32_t code, int32_t lastStreamID,
733               const uint8_t* data, size_t len);
734   void AltSvc(int32_t id,
735               uint8_t* origin,
736               size_t origin_len,
737               uint8_t* value,
738               size_t value_len);
739   void Origin(nghttp2_origin_entry* ov, size_t count);
740 
741   uint8_t SendPendingData();
742 
743   // Submits a new request. If the request is a success, assigned
744   // will be a pointer to the Http2Stream instance assigned.
745   // This only works if the session is a client session.
746   Http2Stream* SubmitRequest(
747       nghttp2_priority_spec* prispec,
748       nghttp2_nv* nva,
749       size_t len,
750       int32_t* ret,
751       int options = 0);
752 
type()753   inline nghttp2_session_type type() const { return session_type_; }
754 
session()755   inline nghttp2_session* session() const { return session_; }
756 
757   inline nghttp2_session* operator*() { return session_; }
758 
GetMaxHeaderPairs()759   inline uint32_t GetMaxHeaderPairs() const { return max_header_pairs_; }
760 
761   inline const char* TypeName() const;
762 
IsDestroyed()763   inline bool IsDestroyed() {
764     return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr;
765   }
766 
767   // Schedule a write if nghttp2 indicates it wants to write to the socket.
768   void MaybeScheduleWrite();
769 
770   // Stop reading if nghttp2 doesn't want to anymore.
771   void MaybeStopReading();
772 
773   // Returns pointer to the stream, or nullptr if stream does not exist
774   inline Http2Stream* FindStream(int32_t id);
775 
776   inline bool CanAddStream();
777 
778   // Adds a stream instance to this session
779   inline void AddStream(Http2Stream* stream);
780 
781   // Removes a stream instance from this session
782   inline void RemoveStream(Http2Stream* stream);
783 
784   // Indicates whether there currently exist outgoing buffers for this stream.
785   bool HasWritesOnSocketForStream(Http2Stream* stream);
786 
787   // Write data from stream_buf_ to the session
788   ssize_t ConsumeHTTP2Data();
789 
MemoryInfo(MemoryTracker * tracker)790   void MemoryInfo(MemoryTracker* tracker) const override {
791     tracker->TrackField("streams", streams_);
792     tracker->TrackField("outstanding_pings", outstanding_pings_);
793     tracker->TrackField("outstanding_settings", outstanding_settings_);
794     tracker->TrackField("outgoing_buffers", outgoing_buffers_);
795     tracker->TrackFieldWithSize("stream_buf", stream_buf_.len);
796     tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size());
797     tracker->TrackFieldWithSize("pending_rst_streams",
798                                 pending_rst_streams_.size() * sizeof(int32_t));
799     tracker->TrackFieldWithSize("nghttp2_memory", current_nghttp2_memory_);
800   }
801 
802   SET_MEMORY_INFO_NAME(Http2Session)
803   SET_SELF_SIZE(Http2Session)
804 
805   std::string diagnostic_name() const override;
806 
807   // Schedule an RstStream for after the current write finishes.
AddPendingRstStream(int32_t stream_id)808   inline void AddPendingRstStream(int32_t stream_id) {
809     pending_rst_streams_.emplace_back(stream_id);
810   }
811 
HasPendingRstStream(int32_t stream_id)812   inline bool HasPendingRstStream(int32_t stream_id) {
813     return pending_rst_streams_.end() != std::find(pending_rst_streams_.begin(),
814                                                    pending_rst_streams_.end(),
815                                                    stream_id);
816   }
817 
818   // Handle reads/writes from the underlying network transport.
819   uv_buf_t OnStreamAlloc(size_t suggested_size) override;
820   void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
821   void OnStreamAfterWrite(WriteWrap* w, int status) override;
822 
823   // Implementation for mem::NgLibMemoryManager
824   void CheckAllocatedSize(size_t previous_size) const;
825   void IncreaseAllocatedSize(size_t size);
826   void DecreaseAllocatedSize(size_t size);
827 
828   // The JavaScript API
829   static void New(const FunctionCallbackInfo<Value>& args);
830   static void Consume(const FunctionCallbackInfo<Value>& args);
831   static void Destroy(const FunctionCallbackInfo<Value>& args);
832   static void Settings(const FunctionCallbackInfo<Value>& args);
833   static void Request(const FunctionCallbackInfo<Value>& args);
834   static void SetNextStreamID(const FunctionCallbackInfo<Value>& args);
835   static void Goaway(const FunctionCallbackInfo<Value>& args);
836   static void UpdateChunksSent(const FunctionCallbackInfo<Value>& args);
837   static void RefreshState(const FunctionCallbackInfo<Value>& args);
838   static void Ping(const FunctionCallbackInfo<Value>& args);
839   static void AltSvc(const FunctionCallbackInfo<Value>& args);
840   static void Origin(const FunctionCallbackInfo<Value>& args);
841 
842   template <get_setting fn>
843   static void RefreshSettings(const FunctionCallbackInfo<Value>& args);
844 
event_loop()845   uv_loop_t* event_loop() const {
846     return env()->event_loop();
847   }
848 
849   BaseObjectPtr<Http2Ping> PopPing();
850   Http2Ping* AddPing(BaseObjectPtr<Http2Ping> ping);
851 
852   BaseObjectPtr<Http2Settings> PopSettings();
853   Http2Settings* AddSettings(BaseObjectPtr<Http2Settings> settings);
854 
IncrementCurrentSessionMemory(uint64_t amount)855   void IncrementCurrentSessionMemory(uint64_t amount) {
856     current_session_memory_ += amount;
857   }
858 
DecrementCurrentSessionMemory(uint64_t amount)859   void DecrementCurrentSessionMemory(uint64_t amount) {
860     DCHECK_LE(amount, current_session_memory_);
861     current_session_memory_ -= amount;
862   }
863 
864   // Tell our custom memory allocator that this rcbuf is independent of
865   // this session now, and may outlive it.
866   void StopTrackingRcbuf(nghttp2_rcbuf* buf);
867 
868   // Returns the current session memory including memory allocated by nghttp2,
869   // the current outbound storage queue, and pending writes.
GetCurrentSessionMemory()870   uint64_t GetCurrentSessionMemory() {
871     uint64_t total = current_session_memory_ + sizeof(Http2Session);
872     total += current_nghttp2_memory_;
873     total += outgoing_storage_.size();
874     return total;
875   }
876 
877   // Return true if current_session_memory + amount is less than the max
IsAvailableSessionMemory(uint64_t amount)878   bool IsAvailableSessionMemory(uint64_t amount) {
879     return GetCurrentSessionMemory() + amount <= max_session_memory_;
880   }
881 
882   struct Statistics {
883     uint64_t start_time;
884     uint64_t end_time;
885     uint64_t ping_rtt;
886     uint64_t data_sent;
887     uint64_t data_received;
888     uint32_t frame_count;
889     uint32_t frame_sent;
890     int32_t stream_count;
891     size_t max_concurrent_streams;
892     double stream_average_duration;
893   };
894 
895   Statistics statistics_ = {};
896 
897  private:
898   // Frame Padding Strategies
899   ssize_t OnDWordAlignedPadding(size_t frameLength,
900                                 size_t maxPayloadLen);
901   ssize_t OnMaxFrameSizePadding(size_t frameLength,
902                                 size_t maxPayloadLen);
903   ssize_t OnCallbackPadding(size_t frameLength,
904                             size_t maxPayloadLen);
905 
906   // Frame Handler
907   int HandleDataFrame(const nghttp2_frame* frame);
908   void HandleGoawayFrame(const nghttp2_frame* frame);
909   void HandleHeadersFrame(const nghttp2_frame* frame);
910   void HandlePriorityFrame(const nghttp2_frame* frame);
911   void HandleSettingsFrame(const nghttp2_frame* frame);
912   void HandlePingFrame(const nghttp2_frame* frame);
913   void HandleAltSvcFrame(const nghttp2_frame* frame);
914   void HandleOriginFrame(const nghttp2_frame* frame);
915 
916   // nghttp2 callbacks
917   static int OnBeginHeadersCallback(
918       nghttp2_session* session,
919       const nghttp2_frame* frame,
920       void* user_data);
921   static int OnHeaderCallback(
922       nghttp2_session* session,
923       const nghttp2_frame* frame,
924       nghttp2_rcbuf* name,
925       nghttp2_rcbuf* value,
926       uint8_t flags,
927       void* user_data);
928   static int OnFrameReceive(
929       nghttp2_session* session,
930       const nghttp2_frame* frame,
931       void* user_data);
932   static int OnFrameNotSent(
933       nghttp2_session* session,
934       const nghttp2_frame* frame,
935       int error_code,
936       void* user_data);
937   static int OnFrameSent(
938       nghttp2_session* session,
939       const nghttp2_frame* frame,
940       void* user_data);
941   static int OnStreamClose(
942       nghttp2_session* session,
943       int32_t id,
944       uint32_t code,
945       void* user_data);
946   static int OnInvalidHeader(
947       nghttp2_session* session,
948       const nghttp2_frame* frame,
949       nghttp2_rcbuf* name,
950       nghttp2_rcbuf* value,
951       uint8_t flags,
952       void* user_data);
953   static int OnDataChunkReceived(
954       nghttp2_session* session,
955       uint8_t flags,
956       int32_t id,
957       const uint8_t* data,
958       size_t len,
959       void* user_data);
960   static ssize_t OnSelectPadding(
961       nghttp2_session* session,
962       const nghttp2_frame* frame,
963       size_t maxPayloadLen,
964       void* user_data);
965   static int OnNghttpError(
966       nghttp2_session* session,
967       const char* message,
968       size_t len,
969       void* user_data);
970   static int OnSendData(
971       nghttp2_session* session,
972       nghttp2_frame* frame,
973       const uint8_t* framehd,
974       size_t length,
975       nghttp2_data_source* source,
976       void* user_data);
977   static int OnInvalidFrame(
978       nghttp2_session* session,
979       const nghttp2_frame* frame,
980       int lib_error_code,
981       void* user_data);
982 
983   struct Callbacks {
984     inline explicit Callbacks(bool kHasGetPaddingCallback);
985     inline ~Callbacks();
986 
987     nghttp2_session_callbacks* callbacks;
988   };
989 
990   /* Use callback_struct_saved[kHasGetPaddingCallback ? 1 : 0] */
991   static const Callbacks callback_struct_saved[2];
992 
993   // The underlying nghttp2_session handle
994   nghttp2_session* session_;
995 
996   // JS-accessible numeric fields, as indexed by SessionUint8Fields.
997   SessionJSFields js_fields_ = {};
998 
999   // The session type: client or server
1000   nghttp2_session_type session_type_;
1001 
1002   // The maximum number of header pairs permitted for streams on this session
1003   uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
1004 
1005   // The maximum amount of memory allocated for this session
1006   uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY;
1007   uint64_t current_session_memory_ = 0;
1008   // The amount of memory allocated by nghttp2 internals
1009   uint64_t current_nghttp2_memory_ = 0;
1010 
1011   // The collection of active Http2Streams associated with this session
1012   std::unordered_map<int32_t, Http2Stream*> streams_;
1013 
1014   int flags_ = SESSION_STATE_NONE;
1015 
1016   // The StreamBase instance being used for i/o
1017   padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
1018 
1019   // use this to allow timeout tracking during long-lasting writes
1020   uint32_t chunks_sent_since_last_write_ = 0;
1021 
1022   uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0);
1023   // When processing input data, either stream_buf_ab_ or stream_buf_allocation_
1024   // will be set. stream_buf_ab_ is lazily created from stream_buf_allocation_.
1025   v8::Global<v8::ArrayBuffer> stream_buf_ab_;
1026   AllocatedBuffer stream_buf_allocation_;
1027   size_t stream_buf_offset_ = 0;
1028 
1029   size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
1030   std::queue<BaseObjectPtr<Http2Ping>> outstanding_pings_;
1031 
1032   size_t max_outstanding_settings_ = DEFAULT_MAX_SETTINGS;
1033   std::queue<BaseObjectPtr<Http2Settings>> outstanding_settings_;
1034 
1035   std::vector<nghttp2_stream_write> outgoing_buffers_;
1036   std::vector<uint8_t> outgoing_storage_;
1037   size_t outgoing_length_ = 0;
1038   std::vector<int32_t> pending_rst_streams_;
1039   // Count streams that have been rejected while being opened. Exceeding a fixed
1040   // limit will result in the session being destroyed, as an indication of a
1041   // misbehaving peer. This counter is reset once new streams are being
1042   // accepted again.
1043   uint32_t rejected_stream_count_ = 0;
1044   // Also use the invalid frame count as a measure for rejecting input frames.
1045   uint32_t invalid_frame_count_ = 0;
1046 
1047   void PushOutgoingBuffer(nghttp2_stream_write&& write);
1048   void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);
1049   void ClearOutgoing(int status);
1050 
1051   friend class Http2Scope;
1052   friend class Http2StreamListener;
1053 };
1054 
1055 class Http2SessionPerformanceEntry : public PerformanceEntry {
1056  public:
Http2SessionPerformanceEntry(Environment * env,const Http2Session::Statistics & stats,nghttp2_session_type type)1057   Http2SessionPerformanceEntry(
1058       Environment* env,
1059       const Http2Session::Statistics& stats,
1060       nghttp2_session_type type) :
1061           PerformanceEntry(env, "Http2Session", "http2",
1062                            stats.start_time,
1063                            stats.end_time),
1064           ping_rtt_(stats.ping_rtt),
1065           data_sent_(stats.data_sent),
1066           data_received_(stats.data_received),
1067           frame_count_(stats.frame_count),
1068           frame_sent_(stats.frame_sent),
1069           stream_count_(stats.stream_count),
1070           max_concurrent_streams_(stats.max_concurrent_streams),
1071           stream_average_duration_(stats.stream_average_duration),
1072           session_type_(type) { }
1073 
ping_rtt()1074   uint64_t ping_rtt() const { return ping_rtt_; }
data_sent()1075   uint64_t data_sent() const { return data_sent_; }
data_received()1076   uint64_t data_received() const { return data_received_; }
frame_count()1077   uint32_t frame_count() const { return frame_count_; }
frame_sent()1078   uint32_t frame_sent() const { return frame_sent_; }
stream_count()1079   int32_t stream_count() const { return stream_count_; }
max_concurrent_streams()1080   size_t max_concurrent_streams() const { return max_concurrent_streams_; }
stream_average_duration()1081   double stream_average_duration() const { return stream_average_duration_; }
type()1082   nghttp2_session_type type() const { return session_type_; }
1083 
Notify(Local<Value> obj)1084   void Notify(Local<Value> obj) {
1085     PerformanceEntry::Notify(env(), kind(), obj);
1086   }
1087 
1088  private:
1089   uint64_t ping_rtt_;
1090   uint64_t data_sent_;
1091   uint64_t data_received_;
1092   uint32_t frame_count_;
1093   uint32_t frame_sent_;
1094   int32_t stream_count_;
1095   size_t max_concurrent_streams_;
1096   double stream_average_duration_;
1097   nghttp2_session_type session_type_;
1098 };
1099 
1100 class Http2StreamPerformanceEntry : public PerformanceEntry {
1101  public:
Http2StreamPerformanceEntry(Environment * env,int32_t id,const Http2Stream::Statistics & stats)1102   Http2StreamPerformanceEntry(
1103       Environment* env,
1104       int32_t id,
1105       const Http2Stream::Statistics& stats) :
1106           PerformanceEntry(env, "Http2Stream", "http2",
1107                            stats.start_time,
1108                            stats.end_time),
1109           id_(id),
1110           first_header_(stats.first_header),
1111           first_byte_(stats.first_byte),
1112           first_byte_sent_(stats.first_byte_sent),
1113           sent_bytes_(stats.sent_bytes),
1114           received_bytes_(stats.received_bytes) { }
1115 
id()1116   int32_t id() const { return id_; }
first_header()1117   uint64_t first_header() const { return first_header_; }
first_byte()1118   uint64_t first_byte() const { return first_byte_; }
first_byte_sent()1119   uint64_t first_byte_sent() const { return first_byte_sent_; }
sent_bytes()1120   uint64_t sent_bytes() const { return sent_bytes_; }
received_bytes()1121   uint64_t received_bytes() const { return received_bytes_; }
1122 
Notify(Local<Value> obj)1123   void Notify(Local<Value> obj) {
1124     PerformanceEntry::Notify(env(), kind(), obj);
1125   }
1126 
1127  private:
1128   int32_t id_;
1129   uint64_t first_header_;
1130   uint64_t first_byte_;
1131   uint64_t first_byte_sent_;
1132   uint64_t sent_bytes_;
1133   uint64_t received_bytes_;
1134 };
1135 
1136 class Http2Session::Http2Ping : public AsyncWrap {
1137  public:
1138   explicit Http2Ping(Http2Session* session, v8::Local<v8::Object> obj);
1139 
MemoryInfo(MemoryTracker * tracker)1140   void MemoryInfo(MemoryTracker* tracker) const override {
1141     tracker->TrackField("session", session_);
1142   }
1143 
1144   SET_MEMORY_INFO_NAME(Http2Ping)
1145   SET_SELF_SIZE(Http2Ping)
1146 
1147   void Send(const uint8_t* payload);
1148   void Done(bool ack, const uint8_t* payload = nullptr);
1149   void DetachFromSession();
1150 
1151  private:
1152   Http2Session* session_;
1153   uint64_t startTime_;
1154 };
1155 
1156 // The Http2Settings class is used to parse the settings passed in for
1157 // an Http2Session, converting those into an array of nghttp2_settings_entry
1158 // structs.
1159 class Http2Session::Http2Settings : public AsyncWrap {
1160  public:
1161   Http2Settings(Environment* env,
1162                 Http2Session* session,
1163                 v8::Local<v8::Object> obj,
1164                 uint64_t start_time = uv_hrtime());
1165 
MemoryInfo(MemoryTracker * tracker)1166   void MemoryInfo(MemoryTracker* tracker) const override {
1167     tracker->TrackField("session", session_);
1168   }
1169 
1170   SET_MEMORY_INFO_NAME(Http2Settings)
1171   SET_SELF_SIZE(Http2Settings)
1172 
1173   void Send();
1174   void Done(bool ack);
1175 
1176   // Returns a Buffer instance with the serialized SETTINGS payload
1177   Local<Value> Pack();
1178 
1179   // Resets the default values in the settings buffer
1180   static void RefreshDefaults(Environment* env);
1181 
1182   // Update the local or remote settings for the given session
1183   static void Update(Environment* env,
1184                      Http2Session* session,
1185                      get_setting fn);
1186 
1187  private:
1188   void Init();
1189   Http2Session* session_;
1190   uint64_t startTime_;
1191   size_t count_ = 0;
1192   nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT];
1193 };
1194 
1195 class ExternalHeader :
1196     public String::ExternalOneByteStringResource {
1197  public:
ExternalHeader(nghttp2_rcbuf * buf)1198   explicit ExternalHeader(nghttp2_rcbuf* buf)
1199      : buf_(buf), vec_(nghttp2_rcbuf_get_buf(buf)) {
1200   }
1201 
~ExternalHeader()1202   ~ExternalHeader() override {
1203     nghttp2_rcbuf_decref(buf_);
1204     buf_ = nullptr;
1205   }
1206 
data()1207   const char* data() const override {
1208     return const_cast<const char*>(reinterpret_cast<char*>(vec_.base));
1209   }
1210 
length()1211   size_t length() const override {
1212     return vec_.len;
1213   }
1214 
1215   static inline
GetInternalizedString(Environment * env,const nghttp2_vec & vec)1216   MaybeLocal<String> GetInternalizedString(Environment* env,
1217                                            const nghttp2_vec& vec) {
1218     return String::NewFromOneByte(env->isolate(),
1219                                   vec.base,
1220                                   v8::NewStringType::kInternalized,
1221                                   vec.len);
1222   }
1223 
1224   template <bool may_internalize>
New(Http2Session * session,nghttp2_rcbuf * buf)1225   static MaybeLocal<String> New(Http2Session* session, nghttp2_rcbuf* buf) {
1226     Environment* env = session->env();
1227     if (nghttp2_rcbuf_is_static(buf)) {
1228       auto& static_str_map = env->isolate_data()->http2_static_strs;
1229       v8::Eternal<v8::String>& eternal = static_str_map[buf];
1230       if (eternal.IsEmpty()) {
1231         Local<String> str =
1232             GetInternalizedString(env, nghttp2_rcbuf_get_buf(buf))
1233                 .ToLocalChecked();
1234         eternal.Set(env->isolate(), str);
1235         return str;
1236       }
1237       return eternal.Get(env->isolate());
1238     }
1239 
1240     nghttp2_vec vec = nghttp2_rcbuf_get_buf(buf);
1241     if (vec.len == 0) {
1242       nghttp2_rcbuf_decref(buf);
1243       return String::Empty(env->isolate());
1244     }
1245 
1246     if (may_internalize && vec.len < 64) {
1247       nghttp2_rcbuf_decref(buf);
1248       // This is a short header name, so there is a good chance V8 already has
1249       // it internalized.
1250       return GetInternalizedString(env, vec);
1251     }
1252 
1253     session->StopTrackingRcbuf(buf);
1254     ExternalHeader* h_str = new ExternalHeader(buf);
1255     MaybeLocal<String> str = String::NewExternalOneByte(env->isolate(), h_str);
1256     if (str.IsEmpty())
1257       delete h_str;
1258 
1259     return str;
1260   }
1261 
1262  private:
1263   nghttp2_rcbuf* buf_;
1264   nghttp2_vec vec_;
1265 };
1266 
1267 class Headers {
1268  public:
1269   Headers(Isolate* isolate, Local<Context> context, Local<Array> headers);
1270   ~Headers() = default;
1271 
1272   nghttp2_nv* operator*() {
1273     return reinterpret_cast<nghttp2_nv*>(*buf_);
1274   }
1275 
length()1276   size_t length() const {
1277     return count_;
1278   }
1279 
1280  private:
1281   size_t count_;
1282   MaybeStackBuffer<char, 3000> buf_;
1283 };
1284 
1285 class Origins {
1286  public:
1287   Origins(Isolate* isolate,
1288           Local<Context> context,
1289           Local<v8::String> origin_string,
1290           size_t origin_count);
1291   ~Origins() = default;
1292 
1293   nghttp2_origin_entry* operator*() {
1294     return reinterpret_cast<nghttp2_origin_entry*>(*buf_);
1295   }
1296 
length()1297   size_t length() const {
1298     return count_;
1299   }
1300 
1301  private:
1302   size_t count_;
1303   MaybeStackBuffer<char, 512> buf_;
1304 };
1305 
1306 }  // namespace http2
1307 }  // namespace node
1308 
1309 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1310 
1311 #endif  // SRC_NODE_HTTP2_H_
1312