GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_http2.h Lines: 181 194 93.3 %
Date: 2019-07-28 22:34:34 Branches: 30 50 60.0 %

Line Branch Exec Source
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_perf.h"
12
#include "stream_base-inl.h"
13
#include "string_bytes.h"
14
15
#include <algorithm>
16
#include <queue>
17
18
namespace node {
19
namespace http2 {
20
21
using v8::Array;
22
using v8::Context;
23
using v8::Isolate;
24
using v8::MaybeLocal;
25
26
using performance::PerformanceEntry;
27
28
// We strictly limit the number of outstanding unacknowledged PINGS a user
29
// may send in order to prevent abuse. The current default cap is 10. The
30
// user may set a different limit using a per Http2Session configuration
31
// option.
32
#define DEFAULT_MAX_PINGS 10
33
34
// Also strictly limit the number of outstanding SETTINGS frames a user sends
35
#define DEFAULT_MAX_SETTINGS 10
36
37
// Default maximum total memory cap for Http2Session.
38
#define DEFAULT_MAX_SESSION_MEMORY 1e7
39
40
// These are the standard HTTP/2 defaults as specified by the RFC
41
#define DEFAULT_SETTINGS_HEADER_TABLE_SIZE 4096
42
#define DEFAULT_SETTINGS_ENABLE_PUSH 1
43
#define DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE 65535
44
#define DEFAULT_SETTINGS_MAX_FRAME_SIZE 16384
45
#define DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE 65535
46
#define MAX_MAX_FRAME_SIZE 16777215
47
#define MIN_MAX_FRAME_SIZE DEFAULT_SETTINGS_MAX_FRAME_SIZE
48
#define MAX_INITIAL_WINDOW_SIZE 2147483647
49
50
#define MAX_MAX_HEADER_LIST_SIZE 16777215u
51
#define DEFAULT_MAX_HEADER_LIST_PAIRS 128u
52
53
enum nghttp2_session_type {
54
  NGHTTP2_SESSION_SERVER,
55
  NGHTTP2_SESSION_CLIENT
56
};
57
58
enum nghttp2_stream_flags {
59
  NGHTTP2_STREAM_FLAG_NONE = 0x0,
60
  // Writable side has ended
61
  NGHTTP2_STREAM_FLAG_SHUT = 0x1,
62
  // Reading has started
63
  NGHTTP2_STREAM_FLAG_READ_START = 0x2,
64
  // Reading is paused
65
  NGHTTP2_STREAM_FLAG_READ_PAUSED = 0x4,
66
  // Stream is closed
67
  NGHTTP2_STREAM_FLAG_CLOSED = 0x8,
68
  // Stream is destroyed
69
  NGHTTP2_STREAM_FLAG_DESTROYED = 0x10,
70
  // Stream has trailers
71
  NGHTTP2_STREAM_FLAG_TRAILERS = 0x20,
72
  // Stream has received all the data it can
73
  NGHTTP2_STREAM_FLAG_EOS = 0x40
74
};
75
76
enum nghttp2_stream_options {
77
  // Stream is not going to have any DATA frames
78
  STREAM_OPTION_EMPTY_PAYLOAD = 0x1,
79
  // Stream might have trailing headers
80
  STREAM_OPTION_GET_TRAILERS = 0x2,
81
};
82
83
463834
struct nghttp2_stream_write : public MemoryRetainer {
84
  WriteWrap* req_wrap = nullptr;
85
  uv_buf_t buf;
86
87
71412
  inline explicit nghttp2_stream_write(uv_buf_t buf_) : buf(buf_) {}
88
20780
  inline nghttp2_stream_write(WriteWrap* req, uv_buf_t buf_) :
89
20780
      req_wrap(req), buf(buf_) {}
90
91
  void MemoryInfo(MemoryTracker* tracker) const override;
92
  SET_MEMORY_INFO_NAME(nghttp2_stream_write)
93
  SET_SELF_SIZE(nghttp2_stream_write)
94
};
95
96
212598
struct nghttp2_header : public MemoryRetainer {
97
  nghttp2_rcbuf* name = nullptr;
98
  nghttp2_rcbuf* value = nullptr;
99
  uint8_t flags = 0;
100
101
  void MemoryInfo(MemoryTracker* tracker) const override;
102
  SET_MEMORY_INFO_NAME(nghttp2_header)
103
  SET_SELF_SIZE(nghttp2_header)
104
};
105
106
107
// Unlike the HTTP/1 implementation, the HTTP/2 implementation is not limited
108
// to a fixed number of known supported HTTP methods. These constants, therefore
109
// are provided strictly as a convenience to users and are exposed via the
110
// require('http2').constants object.
111
#define HTTP_KNOWN_METHODS(V)                                                 \
112
  V(ACL, "ACL")                                                               \
113
  V(BASELINE_CONTROL, "BASELINE-CONTROL")                                     \
114
  V(BIND, "BIND")                                                             \
115
  V(CHECKIN, "CHECKIN")                                                       \
116
  V(CHECKOUT, "CHECKOUT")                                                     \
117
  V(CONNECT, "CONNECT")                                                       \
118
  V(COPY, "COPY")                                                             \
119
  V(DELETE, "DELETE")                                                         \
120
  V(GET, "GET")                                                               \
121
  V(HEAD, "HEAD")                                                             \
122
  V(LABEL, "LABEL")                                                           \
123
  V(LINK, "LINK")                                                             \
124
  V(LOCK, "LOCK")                                                             \
125
  V(MERGE, "MERGE")                                                           \
126
  V(MKACTIVITY, "MKACTIVITY")                                                 \
127
  V(MKCALENDAR, "MKCALENDAR")                                                 \
128
  V(MKCOL, "MKCOL")                                                           \
129
  V(MKREDIRECTREF, "MKREDIRECTREF")                                           \
130
  V(MKWORKSPACE, "MKWORKSPACE")                                               \
131
  V(MOVE, "MOVE")                                                             \
132
  V(OPTIONS, "OPTIONS")                                                       \
133
  V(ORDERPATCH, "ORDERPATCH")                                                 \
134
  V(PATCH, "PATCH")                                                           \
135
  V(POST, "POST")                                                             \
136
  V(PRI, "PRI")                                                               \
137
  V(PROPFIND, "PROPFIND")                                                     \
138
  V(PROPPATCH, "PROPPATCH")                                                   \
139
  V(PUT, "PUT")                                                               \
140
  V(REBIND, "REBIND")                                                         \
141
  V(REPORT, "REPORT")                                                         \
142
  V(SEARCH, "SEARCH")                                                         \
143
  V(TRACE, "TRACE")                                                           \
144
  V(UNBIND, "UNBIND")                                                         \
145
  V(UNCHECKOUT, "UNCHECKOUT")                                                 \
146
  V(UNLINK, "UNLINK")                                                         \
147
  V(UNLOCK, "UNLOCK")                                                         \
148
  V(UPDATE, "UPDATE")                                                         \
149
  V(UPDATEREDIRECTREF, "UPDATEREDIRECTREF")                                   \
150
  V(VERSION_CONTROL, "VERSION-CONTROL")
151
152
// These are provided strictly as a convenience to users and are exposed via the
153
// require('http2').constants objects
154
#define HTTP_KNOWN_HEADERS(V)                                                 \
155
  V(STATUS, ":status")                                                        \
156
  V(METHOD, ":method")                                                        \
157
  V(AUTHORITY, ":authority")                                                  \
158
  V(SCHEME, ":scheme")                                                        \
159
  V(PATH, ":path")                                                            \
160
  V(PROTOCOL, ":protocol")                                                    \
161
  V(ACCEPT_CHARSET, "accept-charset")                                         \
162
  V(ACCEPT_ENCODING, "accept-encoding")                                       \
163
  V(ACCEPT_LANGUAGE, "accept-language")                                       \
164
  V(ACCEPT_RANGES, "accept-ranges")                                           \
165
  V(ACCEPT, "accept")                                                         \
166
  V(ACCESS_CONTROL_ALLOW_CREDENTIALS, "access-control-allow-credentials")     \
167
  V(ACCESS_CONTROL_ALLOW_HEADERS, "access-control-allow-headers")             \
168
  V(ACCESS_CONTROL_ALLOW_METHODS, "access-control-allow-methods")             \
169
  V(ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin")               \
170
  V(ACCESS_CONTROL_EXPOSE_HEADERS, "access-control-expose-headers")           \
171
  V(ACCESS_CONTROL_MAX_AGE, "access-control-max-age")                         \
172
  V(ACCESS_CONTROL_REQUEST_HEADERS, "access-control-request-headers")         \
173
  V(ACCESS_CONTROL_REQUEST_METHOD, "access-control-request-method")           \
174
  V(AGE, "age")                                                               \
175
  V(ALLOW, "allow")                                                           \
176
  V(AUTHORIZATION, "authorization")                                           \
177
  V(CACHE_CONTROL, "cache-control")                                           \
178
  V(CONNECTION, "connection")                                                 \
179
  V(CONTENT_DISPOSITION, "content-disposition")                               \
180
  V(CONTENT_ENCODING, "content-encoding")                                     \
181
  V(CONTENT_LANGUAGE, "content-language")                                     \
182
  V(CONTENT_LENGTH, "content-length")                                         \
183
  V(CONTENT_LOCATION, "content-location")                                     \
184
  V(CONTENT_MD5, "content-md5")                                               \
185
  V(CONTENT_RANGE, "content-range")                                           \
186
  V(CONTENT_TYPE, "content-type")                                             \
187
  V(COOKIE, "cookie")                                                         \
188
  V(DATE, "date")                                                             \
189
  V(DNT, "dnt")                                                               \
190
  V(ETAG, "etag")                                                             \
191
  V(EXPECT, "expect")                                                         \
192
  V(EXPIRES, "expires")                                                       \
193
  V(FORWARDED, "forwarded")                                                   \
194
  V(FROM, "from")                                                             \
195
  V(HOST, "host")                                                             \
196
  V(IF_MATCH, "if-match")                                                     \
197
  V(IF_MODIFIED_SINCE, "if-modified-since")                                   \
198
  V(IF_NONE_MATCH, "if-none-match")                                           \
199
  V(IF_RANGE, "if-range")                                                     \
200
  V(IF_UNMODIFIED_SINCE, "if-unmodified-since")                               \
201
  V(LAST_MODIFIED, "last-modified")                                           \
202
  V(LINK, "link")                                                             \
203
  V(LOCATION, "location")                                                     \
204
  V(MAX_FORWARDS, "max-forwards")                                             \
205
  V(PREFER, "prefer")                                                         \
206
  V(PROXY_AUTHENTICATE, "proxy-authenticate")                                 \
207
  V(PROXY_AUTHORIZATION, "proxy-authorization")                               \
208
  V(RANGE, "range")                                                           \
209
  V(REFERER, "referer")                                                       \
210
  V(REFRESH, "refresh")                                                       \
211
  V(RETRY_AFTER, "retry-after")                                               \
212
  V(SERVER, "server")                                                         \
213
  V(SET_COOKIE, "set-cookie")                                                 \
214
  V(STRICT_TRANSPORT_SECURITY, "strict-transport-security")                   \
215
  V(TRAILER, "trailer")                                                       \
216
  V(TRANSFER_ENCODING, "transfer-encoding")                                   \
217
  V(TE, "te")                                                                 \
218
  V(TK, "tk")                                                                 \
219
  V(UPGRADE_INSECURE_REQUESTS, "upgrade-insecure-requests")                   \
220
  V(UPGRADE, "upgrade")                                                       \
221
  V(USER_AGENT, "user-agent")                                                 \
222
  V(VARY, "vary")                                                             \
223
  V(VIA, "via")                                                               \
224
  V(WARNING, "warning")                                                       \
225
  V(WWW_AUTHENTICATE, "www-authenticate")                                     \
226
  V(X_CONTENT_TYPE_OPTIONS, "x-content-type-options")                         \
227
  V(X_FRAME_OPTIONS, "x-frame-options")                                       \
228
  V(HTTP2_SETTINGS, "http2-settings")                                         \
229
  V(KEEP_ALIVE, "keep-alive")                                                 \
230
  V(PROXY_CONNECTION, "proxy-connection")
231
232
enum http_known_headers {
233
  HTTP_KNOWN_HEADER_MIN,
234
#define V(name, value) HTTP_HEADER_##name,
235
  HTTP_KNOWN_HEADERS(V)
236
#undef V
237
  HTTP_KNOWN_HEADER_MAX
238
};
239
240
// While some of these codes are used within the HTTP/2 implementation in
241
// core, they are provided strictly as a convenience to users and are exposed
242
// via the require('http2').constants object.
243
#define HTTP_STATUS_CODES(V)                                                  \
244
  V(CONTINUE, 100)                                                            \
245
  V(SWITCHING_PROTOCOLS, 101)                                                 \
246
  V(PROCESSING, 102)                                                          \
247
  V(EARLY_HINTS, 103)                                                         \
248
  V(OK, 200)                                                                  \
249
  V(CREATED, 201)                                                             \
250
  V(ACCEPTED, 202)                                                            \
251
  V(NON_AUTHORITATIVE_INFORMATION, 203)                                       \
252
  V(NO_CONTENT, 204)                                                          \
253
  V(RESET_CONTENT, 205)                                                       \
254
  V(PARTIAL_CONTENT, 206)                                                     \
255
  V(MULTI_STATUS, 207)                                                        \
256
  V(ALREADY_REPORTED, 208)                                                    \
257
  V(IM_USED, 226)                                                             \
258
  V(MULTIPLE_CHOICES, 300)                                                    \
259
  V(MOVED_PERMANENTLY, 301)                                                   \
260
  V(FOUND, 302)                                                               \
261
  V(SEE_OTHER, 303)                                                           \
262
  V(NOT_MODIFIED, 304)                                                        \
263
  V(USE_PROXY, 305)                                                           \
264
  V(TEMPORARY_REDIRECT, 307)                                                  \
265
  V(PERMANENT_REDIRECT, 308)                                                  \
266
  V(BAD_REQUEST, 400)                                                         \
267
  V(UNAUTHORIZED, 401)                                                        \
268
  V(PAYMENT_REQUIRED, 402)                                                    \
269
  V(FORBIDDEN, 403)                                                           \
270
  V(NOT_FOUND, 404)                                                           \
271
  V(METHOD_NOT_ALLOWED, 405)                                                  \
272
  V(NOT_ACCEPTABLE, 406)                                                      \
273
  V(PROXY_AUTHENTICATION_REQUIRED, 407)                                       \
274
  V(REQUEST_TIMEOUT, 408)                                                     \
275
  V(CONFLICT, 409)                                                            \
276
  V(GONE, 410)                                                                \
277
  V(LENGTH_REQUIRED, 411)                                                     \
278
  V(PRECONDITION_FAILED, 412)                                                 \
279
  V(PAYLOAD_TOO_LARGE, 413)                                                   \
280
  V(URI_TOO_LONG, 414)                                                        \
281
  V(UNSUPPORTED_MEDIA_TYPE, 415)                                              \
282
  V(RANGE_NOT_SATISFIABLE, 416)                                               \
283
  V(EXPECTATION_FAILED, 417)                                                  \
284
  V(TEAPOT, 418)                                                              \
285
  V(MISDIRECTED_REQUEST, 421)                                                 \
286
  V(UNPROCESSABLE_ENTITY, 422)                                                \
287
  V(LOCKED, 423)                                                              \
288
  V(FAILED_DEPENDENCY, 424)                                                   \
289
  V(UNORDERED_COLLECTION, 425)                                                \
290
  V(UPGRADE_REQUIRED, 426)                                                    \
291
  V(PRECONDITION_REQUIRED, 428)                                               \
292
  V(TOO_MANY_REQUESTS, 429)                                                   \
293
  V(REQUEST_HEADER_FIELDS_TOO_LARGE, 431)                                     \
294
  V(UNAVAILABLE_FOR_LEGAL_REASONS, 451)                                       \
295
  V(INTERNAL_SERVER_ERROR, 500)                                               \
296
  V(NOT_IMPLEMENTED, 501)                                                     \
297
  V(BAD_GATEWAY, 502)                                                         \
298
  V(SERVICE_UNAVAILABLE, 503)                                                 \
299
  V(GATEWAY_TIMEOUT, 504)                                                     \
300
  V(HTTP_VERSION_NOT_SUPPORTED, 505)                                          \
301
  V(VARIANT_ALSO_NEGOTIATES, 506)                                             \
302
  V(INSUFFICIENT_STORAGE, 507)                                                \
303
  V(LOOP_DETECTED, 508)                                                       \
304
  V(BANDWIDTH_LIMIT_EXCEEDED, 509)                                            \
305
  V(NOT_EXTENDED, 510)                                                        \
306
  V(NETWORK_AUTHENTICATION_REQUIRED, 511)
307
308
enum http_status_codes {
309
#define V(name, code) HTTP_STATUS_##name = code,
310
  HTTP_STATUS_CODES(V)
311
#undef V
312
};
313
314
// The Padding Strategy determines the method by which extra padding is
315
// selected for HEADERS and DATA frames. These are configurable via the
316
// options passed in to a Http2Session object.
317
enum padding_strategy_type {
318
  // No padding strategy. This is the default.
319
  PADDING_STRATEGY_NONE,
320
  // Attempts to ensure that the frame is 8-byte aligned
321
  PADDING_STRATEGY_ALIGNED,
322
  // Padding will ensure all data frames are maxFrameSize
323
  PADDING_STRATEGY_MAX,
324
  // Padding will be determined via a JS callback. Note that this can be
325
  // expensive because the callback is called once for every DATA and
326
  // HEADERS frame. For performance reasons, this strategy should be
327
  // avoided.
328
  PADDING_STRATEGY_CALLBACK
329
};
330
331
enum session_state_flags {
332
  SESSION_STATE_NONE = 0x0,
333
  SESSION_STATE_HAS_SCOPE = 0x1,
334
  SESSION_STATE_WRITE_SCHEDULED = 0x2,
335
  SESSION_STATE_CLOSED = 0x4,
336
  SESSION_STATE_CLOSING = 0x8,
337
  SESSION_STATE_SENDING = 0x10,
338
};
339
340
typedef uint32_t(*get_setting)(nghttp2_session* session,
341
                               nghttp2_settings_id id);
342
343
class Http2Session;
344
class Http2Stream;
345
346
// This scope should be present when any call into nghttp2 that may schedule
347
// data to be written to the underlying transport is made, and schedules
348
// such a write automatically once the scope is exited.
349
class Http2Scope {
350
 public:
351
  explicit Http2Scope(Http2Stream* stream);
352
  explicit Http2Scope(Http2Session* session);
353
  ~Http2Scope();
354
355
 private:
356
  Http2Session* session_ = nullptr;
357
  Local<Object> session_handle_;
358
};
359
360
// The Http2Options class is used to parse the options object passed in to
361
// a Http2Session object and convert those into an appropriate nghttp2_option
362
// struct. This is the primary mechanism by which the Http2Session object is
363
// configured.
364
class Http2Options {
365
 public:
366
  Http2Options(Environment* env, nghttp2_session_type type);
367
368
577
  ~Http2Options() {
369
577
    nghttp2_option_del(options_);
370
577
  }
371
372
577
  nghttp2_option* operator*() const {
373
577
    return options_;
374
  }
375
376
3
  void SetMaxHeaderPairs(uint32_t max) {
377
3
    max_header_pairs_ = max;
378
3
  }
379
380
577
  uint32_t GetMaxHeaderPairs() const {
381
577
    return max_header_pairs_;
382
  }
383
384
4
  void SetPaddingStrategy(padding_strategy_type val) {
385
4
    padding_strategy_ = val;
386
4
  }
387
388
577
  padding_strategy_type GetPaddingStrategy() const {
389
577
    return padding_strategy_;
390
  }
391
392
2
  void SetMaxOutstandingPings(size_t max) {
393
2
    max_outstanding_pings_ = max;
394
2
  }
395
396
577
  size_t GetMaxOutstandingPings() {
397
577
    return max_outstanding_pings_;
398
  }
399
400
2
  void SetMaxOutstandingSettings(size_t max) {
401
2
    max_outstanding_settings_ = max;
402
2
  }
403
404
577
  size_t GetMaxOutstandingSettings() {
405
577
    return max_outstanding_settings_;
406
  }
407
408
4
  void SetMaxSessionMemory(uint64_t max) {
409
4
    max_session_memory_ = max;
410
4
  }
411
412
577
  uint64_t GetMaxSessionMemory() {
413
577
    return max_session_memory_;
414
  }
415
416
 private:
417
  nghttp2_option* options_;
418
  uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY;
419
  uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
420
  padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
421
  size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
422
  size_t max_outstanding_settings_ = DEFAULT_MAX_SETTINGS;
423
};
424
425
class Http2Priority {
426
 public:
427
  Http2Priority(Environment* env,
428
                Local<Value> parent,
429
                Local<Value> weight,
430
                Local<Value> exclusive);
431
432
11629
  nghttp2_priority_spec* operator*() {
433
11629
    return &spec;
434
  }
435
 private:
436
  nghttp2_priority_spec spec;
437
};
438
439
46516
class Http2StreamListener : public StreamListener {
440
 public:
441
  uv_buf_t OnStreamAlloc(size_t suggested_size) override;
442
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
443
};
444
445
class Http2Stream : public AsyncWrap,
446
                    public StreamBase {
447
 public:
448
  static Http2Stream* New(
449
      Http2Session* session,
450
      int32_t id,
451
      nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,
452
      int options = 0);
453
  ~Http2Stream() override;
454
455
  nghttp2_stream* operator*();
456
457
130666
  Http2Session* session() { return session_; }
458
17
  const Http2Session* session() const { return session_; }
459
460
  void EmitStatistics();
461
462
  // Required for StreamBase
463
  int ReadStart() override;
464
465
  // Required for StreamBase
466
  int ReadStop() override;
467
468
  // Required for StreamBase
469
  int DoShutdown(ShutdownWrap* req_wrap) override;
470
471
15
  bool HasWantsWrite() const override { return true; }
472
473
  // Initiate a response on this stream.
474
  int SubmitResponse(nghttp2_nv* nva, size_t len, int options);
475
476
  // Submit informational headers for this stream
477
  int SubmitInfo(nghttp2_nv* nva, size_t len);
478
479
  // Submit trailing headers for this stream
480
  int SubmitTrailers(nghttp2_nv* nva, size_t len);
481
  void OnTrailers();
482
483
  // Submit a PRIORITY frame for this stream
484
  int SubmitPriority(nghttp2_priority_spec* prispec, bool silent = false);
485
486
  // Submits an RST_STREAM frame using the given code
487
  void SubmitRstStream(const uint32_t code);
488
489
  void FlushRstStream();
490
491
  // Submits a PUSH_PROMISE frame with this stream as the parent.
492
  Http2Stream* SubmitPushPromise(
493
      nghttp2_nv* nva,
494
      size_t len,
495
      int32_t* ret,
496
      int options = 0);
497
498
499
  void Close(int32_t code);
500
501
  // Destroy this stream instance and free all held memory.
502
  void Destroy();
503
504
364816
  inline bool IsDestroyed() const {
505
364816
    return flags_ & NGHTTP2_STREAM_FLAG_DESTROYED;
506
  }
507
508
47399
  inline bool IsWritable() const {
509
47399
    return !(flags_ & NGHTTP2_STREAM_FLAG_SHUT);
510
  }
511
512
  inline bool IsPaused() const {
513
    return flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED;
514
  }
515
516
  inline bool IsClosed() const {
517
    return flags_ & NGHTTP2_STREAM_FLAG_CLOSED;
518
  }
519
520
12551
  inline bool HasTrailers() const {
521
12551
    return flags_ & NGHTTP2_STREAM_FLAG_TRAILERS;
522
  }
523
524
  // Returns true if this stream is in the reading state, which occurs when
525
  // the NGHTTP2_STREAM_FLAG_READ_START flag has been set and the
526
  // NGHTTP2_STREAM_FLAG_READ_PAUSED flag is *not* set.
527
11728
  inline bool IsReading() const {
528

22420
    return flags_ & NGHTTP2_STREAM_FLAG_READ_START &&
529
22420
           !(flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED);
530
  }
531
532
  // Returns the RST_STREAM code used to close this stream
533
  inline int32_t code() const { return code_; }
534
535
  // Returns the stream identifier for this stream
536
135672
  inline int32_t id() const { return id_; }
537
538
  inline void IncrementAvailableOutboundLength(size_t amount);
539
  inline void DecrementAvailableOutboundLength(size_t amount);
540
541
  bool AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags);
542
543
23146
  inline std::vector<nghttp2_header> move_headers() {
544
23146
    return std::move(current_headers_);
545
  }
546
547
23146
  inline nghttp2_headers_category headers_category() const {
548
23146
    return current_headers_category_;
549
  }
550
551
  void StartHeaders(nghttp2_headers_category category);
552
553
  // Required for StreamBase
554
47812
  bool IsAlive() override {
555
47812
    return true;
556
  }
557
558
  // Required for StreamBase
559
  bool IsClosing() override {
560
    return false;
561
  }
562
563
125729
  AsyncWrap* GetAsyncWrap() override { return this; }
564
565
  int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
566
              uv_stream_t* send_handle) override;
567
568
4
  void MemoryInfo(MemoryTracker* tracker) const override {
569
4
    tracker->TrackField("current_headers", current_headers_);
570
4
    tracker->TrackField("queue", queue_);
571
4
  }
572
573
4
  SET_MEMORY_INFO_NAME(Http2Stream)
574
4
  SET_SELF_SIZE(Http2Stream)
575
576
  std::string diagnostic_name() const override;
577
578
  // JavaScript API
579
  static void GetID(const FunctionCallbackInfo<Value>& args);
580
  static void Destroy(const FunctionCallbackInfo<Value>& args);
581
  static void FlushData(const FunctionCallbackInfo<Value>& args);
582
  static void Priority(const FunctionCallbackInfo<Value>& args);
583
  static void PushPromise(const FunctionCallbackInfo<Value>& args);
584
  static void RefreshState(const FunctionCallbackInfo<Value>& args);
585
  static void Info(const FunctionCallbackInfo<Value>& args);
586
  static void Trailers(const FunctionCallbackInfo<Value>& args);
587
  static void Respond(const FunctionCallbackInfo<Value>& args);
588
  static void RstStream(const FunctionCallbackInfo<Value>& args);
589
590
  class Provider;
591
592
  struct Statistics {
593
    uint64_t start_time;
594
    uint64_t end_time;
595
    uint64_t first_header;     // Time first header was received
596
    uint64_t first_byte;       // Time first DATA frame byte was received
597
    uint64_t first_byte_sent;  // Time first DATA frame byte was sent
598
    uint64_t sent_bytes;
599
    uint64_t received_bytes;
600
  };
601
602
  Statistics statistics_ = {};
603
604
 private:
605
  Http2Stream(Http2Session* session,
606
              v8::Local<v8::Object> obj,
607
              int32_t id,
608
              nghttp2_headers_category category,
609
              int options);
610
611
  Http2Session* session_ = nullptr;             // The Parent HTTP/2 Session
612
  int32_t id_ = 0;                              // The Stream Identifier
613
  int32_t code_ = NGHTTP2_NO_ERROR;             // The RST_STREAM code (if any)
614
  int flags_ = NGHTTP2_STREAM_FLAG_NONE;        // Internal state flags
615
616
  uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
617
  uint32_t max_header_length_ = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE;
618
619
  // The Current Headers block... As headers are received for this stream,
620
  // they are temporarily stored here until the OnFrameReceived is called
621
  // signalling the end of the HEADERS frame
622
  nghttp2_headers_category current_headers_category_ = NGHTTP2_HCAT_HEADERS;
623
  uint32_t current_headers_length_ = 0;  // total number of octets
624
  std::vector<nghttp2_header> current_headers_;
625
626
  // This keeps track of the amount of data read from the socket while the
627
  // socket was in paused mode. When `ReadStart()` is called (and not before
628
  // then), we tell nghttp2 that we consumed that data to get proper
629
  // backpressure handling.
630
  size_t inbound_consumed_data_while_paused_ = 0;
631
632
  // Outbound Data... This is the data written by the JS layer that is
633
  // waiting to be written out to the socket.
634
  std::queue<nghttp2_stream_write> queue_;
635
  size_t available_outbound_length_ = 0;
636
637
  Http2StreamListener stream_listener_;
638
639
  friend class Http2Session;
640
};
641
642
class Http2Stream::Provider {
643
 public:
644
  Provider(Http2Stream* stream, int options);
645
  explicit Provider(int options);
646
  virtual ~Provider();
647
648
23199
  nghttp2_data_provider* operator*() {
649
23199
    return !empty_ ? &provider_ : nullptr;
650
  }
651
652
  class FD;
653
  class Stream;
654
 protected:
655
  nghttp2_data_provider provider_;
656
657
 private:
658
  bool empty_ = false;
659
};
660
661
23199
class Http2Stream::Provider::Stream : public Http2Stream::Provider {
662
 public:
663
  Stream(Http2Stream* stream, int options);
664
  explicit Stream(int options);
665
666
  static ssize_t OnRead(nghttp2_session* session,
667
                        int32_t id,
668
                        uint8_t* buf,
669
                        size_t length,
670
                        uint32_t* flags,
671
                        nghttp2_data_source* source,
672
                        void* user_data);
673
};
674
675
676
class Http2Session : public AsyncWrap, public StreamListener {
677
 public:
678
  Http2Session(Environment* env,
679
               Local<Object> wrap,
680
               nghttp2_session_type type = NGHTTP2_SESSION_SERVER);
681
  ~Http2Session() override;
682
683
  class Http2Ping;
684
  class Http2Settings;
685
  class MemoryAllocatorInfo;
686
687
  void EmitStatistics();
688
689
30736
  inline StreamBase* underlying_stream() {
690
30736
    return static_cast<StreamBase*>(stream_);
691
  }
692
693
  void Close(uint32_t code = NGHTTP2_NO_ERROR,
694
             bool socket_closed = false);
695
  void Consume(Local<Object> stream);
696
  void Goaway(uint32_t code, int32_t lastStreamID,
697
              const uint8_t* data, size_t len);
698
  void AltSvc(int32_t id,
699
              uint8_t* origin,
700
              size_t origin_len,
701
              uint8_t* value,
702
              size_t value_len);
703
  void Origin(nghttp2_origin_entry* ov, size_t count);
704
705
  uint8_t SendPendingData();
706
707
  // Submits a new request. If the request is a success, assigned
708
  // will be a pointer to the Http2Stream instance assigned.
709
  // This only works if the session is a client session.
710
  Http2Stream* SubmitRequest(
711
      nghttp2_priority_spec* prispec,
712
      nghttp2_nv* nva,
713
      size_t len,
714
      int32_t* ret,
715
      int options = 0);
716
717
  inline nghttp2_session_type type() const { return session_type_; }
718
719
23258
  inline nghttp2_session* session() const { return session_; }
720
721
188640
  inline nghttp2_session* operator*() { return session_; }
722
723
23258
  inline uint32_t GetMaxHeaderPairs() const { return max_header_pairs_; }
724
725
  inline const char* TypeName() const;
726
727
61715
  inline bool IsDestroyed() {
728

61715
    return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr;
729
  }
730
731
  // Schedule a write if nghttp2 indicates it wants to write to the socket.
732
  void MaybeScheduleWrite();
733
734
  // Stop reading if nghttp2 doesn't want to anymore.
735
  void MaybeStopReading();
736
737
  // Returns pointer to the stream, or nullptr if stream does not exist
738
  inline Http2Stream* FindStream(int32_t id);
739
740
  inline bool CanAddStream();
741
742
  // Adds a stream instance to this session
743
  inline void AddStream(Http2Stream* stream);
744
745
  // Removes a stream instance from this session
746
  inline void RemoveStream(Http2Stream* stream);
747
748
  // Indicates whether there currently exist outgoing buffers for this stream.
749
  bool HasWritesOnSocketForStream(Http2Stream* stream);
750
751
  // Write data to the session
752
  ssize_t Write(const uv_buf_t* bufs, size_t nbufs);
753
754
9
  void MemoryInfo(MemoryTracker* tracker) const override {
755
9
    tracker->TrackField("streams", streams_);
756
9
    tracker->TrackField("outstanding_pings", outstanding_pings_);
757
9
    tracker->TrackField("outstanding_settings", outstanding_settings_);
758
9
    tracker->TrackField("outgoing_buffers", outgoing_buffers_);
759
9
    tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size());
760
    tracker->TrackFieldWithSize("pending_rst_streams",
761
9
                                pending_rst_streams_.size() * sizeof(int32_t));
762
9
  }
763
764
9
  SET_MEMORY_INFO_NAME(Http2Session)
765
9
  SET_SELF_SIZE(Http2Session)
766
767
  std::string diagnostic_name() const override;
768
769
  // Schedule an RstStream for after the current write finishes.
770
3
  inline void AddPendingRstStream(int32_t stream_id) {
771
3
    pending_rst_streams_.emplace_back(stream_id);
772
3
  }
773
774
23250
  inline bool HasPendingRstStream(int32_t stream_id) {
775
46500
    return pending_rst_streams_.end() != std::find(pending_rst_streams_.begin(),
776
                                                   pending_rst_streams_.end(),
777
69750
                                                   stream_id);
778
  }
779
780
  // Handle reads/writes from the underlying network transport.
781
  uv_buf_t OnStreamAlloc(size_t suggested_size) override;
782
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
783
  void OnStreamAfterWrite(WriteWrap* w, int status) override;
784
785
  // The JavaScript API
786
  static void New(const FunctionCallbackInfo<Value>& args);
787
  static void Consume(const FunctionCallbackInfo<Value>& args);
788
  static void Destroy(const FunctionCallbackInfo<Value>& args);
789
  static void Settings(const FunctionCallbackInfo<Value>& args);
790
  static void Request(const FunctionCallbackInfo<Value>& args);
791
  static void SetNextStreamID(const FunctionCallbackInfo<Value>& args);
792
  static void Goaway(const FunctionCallbackInfo<Value>& args);
793
  static void UpdateChunksSent(const FunctionCallbackInfo<Value>& args);
794
  static void RefreshState(const FunctionCallbackInfo<Value>& args);
795
  static void Ping(const FunctionCallbackInfo<Value>& args);
796
  static void AltSvc(const FunctionCallbackInfo<Value>& args);
797
  static void Origin(const FunctionCallbackInfo<Value>& args);
798
799
  template <get_setting fn>
800
  static void RefreshSettings(const FunctionCallbackInfo<Value>& args);
801
802
  uv_loop_t* event_loop() const {
803
    return env()->event_loop();
804
  }
805
806
  std::unique_ptr<Http2Ping> PopPing();
807
  Http2Ping* AddPing(std::unique_ptr<Http2Ping> ping);
808
809
  std::unique_ptr<Http2Settings> PopSettings();
810
  Http2Settings* AddSettings(std::unique_ptr<Http2Settings> settings);
811
812
74015
  void IncrementCurrentSessionMemory(uint64_t amount) {
813
74015
    current_session_memory_ += amount;
814
74015
  }
815
816
64314
  void DecrementCurrentSessionMemory(uint64_t amount) {
817
64314
    current_session_memory_ -= amount;
818
64314
  }
819
820
  // Tell our custom memory allocator that this rcbuf is independent of
821
  // this session now, and may outlive it.
822
  void StopTrackingRcbuf(nghttp2_rcbuf* buf);
823
824
  // Returns the current session memory including memory allocated by nghttp2,
825
  // the current outbound storage queue, and pending writes.
826
82475
  uint64_t GetCurrentSessionMemory() {
827
82475
    uint64_t total = current_session_memory_ + sizeof(Http2Session);
828
82475
    total += current_nghttp2_memory_;
829
82475
    total += outgoing_storage_.size();
830
82475
    return total;
831
  }
832
833
  // Return true if current_session_memory + amount is less than the max
834
82475
  bool IsAvailableSessionMemory(uint64_t amount) {
835
82475
    return GetCurrentSessionMemory() + amount <= max_session_memory_;
836
  }
837
838
  struct Statistics {
839
    uint64_t start_time;
840
    uint64_t end_time;
841
    uint64_t ping_rtt;
842
    uint64_t data_sent;
843
    uint64_t data_received;
844
    uint32_t frame_count;
845
    uint32_t frame_sent;
846
    int32_t stream_count;
847
    size_t max_concurrent_streams;
848
    double stream_average_duration;
849
  };
850
851
  Statistics statistics_ = {};
852
853
 private:
854
  // Frame Padding Strategies
855
  ssize_t OnDWordAlignedPadding(size_t frameLength,
856
                                size_t maxPayloadLen);
857
  ssize_t OnMaxFrameSizePadding(size_t frameLength,
858
                                size_t maxPayloadLen);
859
  ssize_t OnCallbackPadding(size_t frameLength,
860
                            size_t maxPayloadLen);
861
862
  // Frame Handler
863
  void HandleDataFrame(const nghttp2_frame* frame);
864
  void HandleGoawayFrame(const nghttp2_frame* frame);
865
  void HandleHeadersFrame(const nghttp2_frame* frame);
866
  void HandlePriorityFrame(const nghttp2_frame* frame);
867
  void HandleSettingsFrame(const nghttp2_frame* frame);
868
  void HandlePingFrame(const nghttp2_frame* frame);
869
  void HandleAltSvcFrame(const nghttp2_frame* frame);
870
  void HandleOriginFrame(const nghttp2_frame* frame);
871
872
  // nghttp2 callbacks
873
  static int OnBeginHeadersCallback(
874
      nghttp2_session* session,
875
      const nghttp2_frame* frame,
876
      void* user_data);
877
  static int OnHeaderCallback(
878
      nghttp2_session* session,
879
      const nghttp2_frame* frame,
880
      nghttp2_rcbuf* name,
881
      nghttp2_rcbuf* value,
882
      uint8_t flags,
883
      void* user_data);
884
  static int OnFrameReceive(
885
      nghttp2_session* session,
886
      const nghttp2_frame* frame,
887
      void* user_data);
888
  static int OnFrameNotSent(
889
      nghttp2_session* session,
890
      const nghttp2_frame* frame,
891
      int error_code,
892
      void* user_data);
893
  static int OnFrameSent(
894
      nghttp2_session* session,
895
      const nghttp2_frame* frame,
896
      void* user_data);
897
  static int OnStreamClose(
898
      nghttp2_session* session,
899
      int32_t id,
900
      uint32_t code,
901
      void* user_data);
902
  static int OnInvalidHeader(
903
      nghttp2_session* session,
904
      const nghttp2_frame* frame,
905
      nghttp2_rcbuf* name,
906
      nghttp2_rcbuf* value,
907
      uint8_t flags,
908
      void* user_data);
909
  static int OnDataChunkReceived(
910
      nghttp2_session* session,
911
      uint8_t flags,
912
      int32_t id,
913
      const uint8_t* data,
914
      size_t len,
915
      void* user_data);
916
  static ssize_t OnSelectPadding(
917
      nghttp2_session* session,
918
      const nghttp2_frame* frame,
919
      size_t maxPayloadLen,
920
      void* user_data);
921
  static int OnNghttpError(
922
      nghttp2_session* session,
923
      const char* message,
924
      size_t len,
925
      void* user_data);
926
  static int OnSendData(
927
      nghttp2_session* session,
928
      nghttp2_frame* frame,
929
      const uint8_t* framehd,
930
      size_t length,
931
      nghttp2_data_source* source,
932
      void* user_data);
933
  static int OnInvalidFrame(
934
      nghttp2_session* session,
935
      const nghttp2_frame* frame,
936
      int lib_error_code,
937
      void* user_data);
938
939
  struct Callbacks {
940
    inline explicit Callbacks(bool kHasGetPaddingCallback);
941
    inline ~Callbacks();
942
943
    nghttp2_session_callbacks* callbacks;
944
  };
945
946
  /* Use callback_struct_saved[kHasGetPaddingCallback ? 1 : 0] */
947
  static const Callbacks callback_struct_saved[2];
948
949
  // The underlying nghttp2_session handle
950
  nghttp2_session* session_;
951
952
  // The session type: client or server
953
  nghttp2_session_type session_type_;
954
955
  // The maximum number of header pairs permitted for streams on this session
956
  uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
957
958
  // The maximum amount of memory allocated for this session
959
  uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY;
960
  uint64_t current_session_memory_ = 0;
961
  // The amount of memory allocated by nghttp2 internals
962
  uint64_t current_nghttp2_memory_ = 0;
963
964
  // The collection of active Http2Streams associated with this session
965
  std::unordered_map<int32_t, Http2Stream*> streams_;
966
967
  int flags_ = SESSION_STATE_NONE;
968
969
  // The StreamBase instance being used for i/o
970
  padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
971
972
  // use this to allow timeout tracking during long-lasting writes
973
  uint32_t chunks_sent_since_last_write_ = 0;
974
975
  uv_buf_t stream_buf_ = uv_buf_init(nullptr, 0);
976
  v8::Local<v8::ArrayBuffer> stream_buf_ab_;
977
978
  size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
979
  std::queue<std::unique_ptr<Http2Ping>> outstanding_pings_;
980
981
  size_t max_outstanding_settings_ = DEFAULT_MAX_SETTINGS;
982
  std::queue<std::unique_ptr<Http2Settings>> outstanding_settings_;
983
984
  std::vector<nghttp2_stream_write> outgoing_buffers_;
985
  std::vector<uint8_t> outgoing_storage_;
986
  std::vector<int32_t> pending_rst_streams_;
987
988
  void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);
989
  void ClearOutgoing(int status);
990
991
  friend class Http2Scope;
992
  friend class Http2StreamListener;
993
};
994
995
4
class Http2SessionPerformanceEntry : public PerformanceEntry {
996
 public:
997
2
  Http2SessionPerformanceEntry(
998
      Environment* env,
999
      const Http2Session::Statistics& stats,
1000
      nghttp2_session_type type) :
1001
          PerformanceEntry(env, "Http2Session", "http2",
1002
                           stats.start_time,
1003
                           stats.end_time),
1004
          ping_rtt_(stats.ping_rtt),
1005
          data_sent_(stats.data_sent),
1006
          data_received_(stats.data_received),
1007
          frame_count_(stats.frame_count),
1008
          frame_sent_(stats.frame_sent),
1009
          stream_count_(stats.stream_count),
1010
          max_concurrent_streams_(stats.max_concurrent_streams),
1011
          stream_average_duration_(stats.stream_average_duration),
1012
2
          session_type_(type) { }
1013
1014
2
  uint64_t ping_rtt() const { return ping_rtt_; }
1015
2
  uint64_t data_sent() const { return data_sent_; }
1016
2
  uint64_t data_received() const { return data_received_; }
1017
2
  uint32_t frame_count() const { return frame_count_; }
1018
2
  uint32_t frame_sent() const { return frame_sent_; }
1019
2
  int32_t stream_count() const { return stream_count_; }
1020
2
  size_t max_concurrent_streams() const { return max_concurrent_streams_; }
1021
2
  double stream_average_duration() const { return stream_average_duration_; }
1022
2
  nghttp2_session_type type() const { return session_type_; }
1023
1024
2
  void Notify(Local<Value> obj) {
1025
2
    PerformanceEntry::Notify(env(), kind(), obj);
1026
2
  }
1027
1028
 private:
1029
  uint64_t ping_rtt_;
1030
  uint64_t data_sent_;
1031
  uint64_t data_received_;
1032
  uint32_t frame_count_;
1033
  uint32_t frame_sent_;
1034
  int32_t stream_count_;
1035
  size_t max_concurrent_streams_;
1036
  double stream_average_duration_;
1037
  nghttp2_session_type session_type_;
1038
};
1039
1040
4
class Http2StreamPerformanceEntry : public PerformanceEntry {
1041
 public:
1042
2
  Http2StreamPerformanceEntry(
1043
      Environment* env,
1044
      int32_t id,
1045
      const Http2Stream::Statistics& stats) :
1046
          PerformanceEntry(env, "Http2Stream", "http2",
1047
                           stats.start_time,
1048
                           stats.end_time),
1049
          id_(id),
1050
          first_header_(stats.first_header),
1051
          first_byte_(stats.first_byte),
1052
          first_byte_sent_(stats.first_byte_sent),
1053
          sent_bytes_(stats.sent_bytes),
1054
2
          received_bytes_(stats.received_bytes) { }
1055
1056
2
  int32_t id() const { return id_; }
1057
4
  uint64_t first_header() const { return first_header_; }
1058
2
  uint64_t first_byte() const { return first_byte_; }
1059
3
  uint64_t first_byte_sent() const { return first_byte_sent_; }
1060
2
  uint64_t sent_bytes() const { return sent_bytes_; }
1061
2
  uint64_t received_bytes() const { return received_bytes_; }
1062
1063
2
  void Notify(Local<Value> obj) {
1064
2
    PerformanceEntry::Notify(env(), kind(), obj);
1065
2
  }
1066
1067
 private:
1068
  int32_t id_;
1069
  uint64_t first_header_;
1070
  uint64_t first_byte_;
1071
  uint64_t first_byte_sent_;
1072
  uint64_t sent_bytes_;
1073
  uint64_t received_bytes_;
1074
};
1075
1076
26
class Http2Session::Http2Ping : public AsyncWrap {
1077
 public:
1078
  explicit Http2Ping(Http2Session* session, v8::Local<v8::Object> obj);
1079
1080
  void MemoryInfo(MemoryTracker* tracker) const override {
1081
    tracker->TrackField("session", session_);
1082
  }
1083
1084
  SET_MEMORY_INFO_NAME(Http2Ping)
1085
  SET_SELF_SIZE(Http2Ping)
1086
1087
  void Send(const uint8_t* payload);
1088
  void Done(bool ack, const uint8_t* payload = nullptr);
1089
  void DetachFromSession();
1090
1091
 private:
1092
  Http2Session* session_;
1093
  uint64_t startTime_;
1094
};
1095
1096
// The Http2Settings class is used to parse the settings passed in for
1097
// an Http2Session, converting those into an array of nghttp2_settings_entry
1098
// structs.
1099
1187
class Http2Session::Http2Settings : public AsyncWrap {
1100
 public:
1101
  Http2Settings(Environment* env,
1102
                Http2Session* session,
1103
                v8::Local<v8::Object> obj,
1104
                uint64_t start_time = uv_hrtime());
1105
1106
6
  void MemoryInfo(MemoryTracker* tracker) const override {
1107
6
    tracker->TrackField("session", session_);
1108
6
  }
1109
1110
6
  SET_MEMORY_INFO_NAME(Http2Settings)
1111
6
  SET_SELF_SIZE(Http2Settings)
1112
1113
  void Send();
1114
  void Done(bool ack);
1115
1116
  // Returns a Buffer instance with the serialized SETTINGS payload
1117
  Local<Value> Pack();
1118
1119
  // Resets the default values in the settings buffer
1120
  static void RefreshDefaults(Environment* env);
1121
1122
  // Update the local or remote settings for the given session
1123
  static void Update(Environment* env,
1124
                     Http2Session* session,
1125
                     get_setting fn);
1126
1127
 private:
1128
  void Init();
1129
  Http2Session* session_;
1130
  uint64_t startTime_;
1131
  size_t count_ = 0;
1132
  nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT];
1133
};
1134
1135
class ExternalHeader :
1136
    public String::ExternalOneByteStringResource {
1137
 public:
1138
24687
  explicit ExternalHeader(nghttp2_rcbuf* buf)
1139
24687
     : buf_(buf), vec_(nghttp2_rcbuf_get_buf(buf)) {
1140
24687
  }
1141
1142
74061
  ~ExternalHeader() override {
1143
24687
    nghttp2_rcbuf_decref(buf_);
1144
24687
    buf_ = nullptr;
1145
49374
  }
1146
1147
49497
  const char* data() const override {
1148
49497
    return const_cast<const char*>(reinterpret_cast<char*>(vec_.base));
1149
  }
1150
1151
98748
  size_t length() const override {
1152
98748
    return vec_.len;
1153
  }
1154
1155
  static inline
1156
1794
  MaybeLocal<String> GetInternalizedString(Environment* env,
1157
                                           const nghttp2_vec& vec) {
1158
    return String::NewFromOneByte(env->isolate(),
1159
                                  vec.base,
1160
                                  v8::NewStringType::kInternalized,
1161
1794
                                  vec.len);
1162
  }
1163
1164
  template <bool may_internalize>
1165
141470
  static MaybeLocal<String> New(Http2Session* session, nghttp2_rcbuf* buf) {
1166
141470
    Environment* env = session->env();
1167

141470
    if (nghttp2_rcbuf_is_static(buf)) {
1168
116728
      auto& static_str_map = env->isolate_data()->http2_static_strs;
1169
116728
      v8::Eternal<v8::String>& eternal = static_str_map[buf];
1170

116728
      if (eternal.IsEmpty()) {
1171
        Local<String> str =
1172
3478
            GetInternalizedString(env, nghttp2_rcbuf_get_buf(buf))
1173
3478
                .ToLocalChecked();
1174
1739
        eternal.Set(env->isolate(), str);
1175
1739
        return str;
1176
      }
1177
229978
      return eternal.Get(env->isolate());
1178
    }
1179
1180
24742
    nghttp2_vec vec = nghttp2_rcbuf_get_buf(buf);
1181

24742
    if (vec.len == 0) {
1182
      nghttp2_rcbuf_decref(buf);
1183
      return String::Empty(env->isolate());
1184
    }
1185
1186
55
    if (may_internalize && vec.len < 64) {
1187
55
      nghttp2_rcbuf_decref(buf);
1188
      // This is a short header name, so there is a good chance V8 already has
1189
      // it internalized.
1190
55
      return GetInternalizedString(env, vec);
1191
    }
1192
1193
24687
    session->StopTrackingRcbuf(buf);
1194
24687
    ExternalHeader* h_str = new ExternalHeader(buf);
1195
24687
    MaybeLocal<String> str = String::NewExternalOneByte(env->isolate(), h_str);
1196

24687
    if (str.IsEmpty())
1197
      delete h_str;
1198
1199
24687
    return str;
1200
  }
1201
1202
 private:
1203
  nghttp2_rcbuf* buf_;
1204
  nghttp2_vec vec_;
1205
};
1206
1207
class Headers {
1208
 public:
1209
  Headers(Isolate* isolate, Local<Context> context, Local<Array> headers);
1210
23217
  ~Headers() = default;
1211
1212
23217
  nghttp2_nv* operator*() {
1213
23217
    return reinterpret_cast<nghttp2_nv*>(*buf_);
1214
  }
1215
1216
23251
  size_t length() const {
1217
23251
    return count_;
1218
  }
1219
1220
 private:
1221
  size_t count_;
1222
  MaybeStackBuffer<char, 3000> buf_;
1223
};
1224
1225
class Origins {
1226
 public:
1227
  Origins(Isolate* isolate,
1228
          Local<Context> context,
1229
          Local<v8::String> origin_string,
1230
          size_t origin_count);
1231
5
  ~Origins() = default;
1232
1233
5
  nghttp2_origin_entry* operator*() {
1234
5
    return reinterpret_cast<nghttp2_origin_entry*>(*buf_);
1235
  }
1236
1237
5
  size_t length() const {
1238
5
    return count_;
1239
  }
1240
1241
 private:
1242
  size_t count_;
1243
  MaybeStackBuffer<char, 512> buf_;
1244
};
1245
1246
}  // namespace http2
1247
}  // namespace node
1248
1249
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1250
1251
#endif  // SRC_NODE_HTTP2_H_