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: 200 216 92.6 %
Date: 2020-02-27 22:14:15 Branches: 22 32 68.8 %

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_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
479043
struct nghttp2_stream_write : public MemoryRetainer {
87
  WriteWrap* req_wrap = nullptr;
88
  uv_buf_t buf;
89
90
65185
  inline explicit nghttp2_stream_write(uv_buf_t buf_) : buf(buf_) {}
91
27458
  inline nghttp2_stream_write(WriteWrap* req, uv_buf_t buf_) :
92
27458
      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
214143
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(TOO_EARLY, 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
  // Removed and turned into an alias because it is unreasonably expensive for
328
  // very little benefit.
329
  PADDING_STRATEGY_CALLBACK = PADDING_STRATEGY_ALIGNED
330
};
331
332
enum session_state_flags {
333
  SESSION_STATE_NONE = 0x0,
334
  SESSION_STATE_HAS_SCOPE = 0x1,
335
  SESSION_STATE_WRITE_SCHEDULED = 0x2,
336
  SESSION_STATE_CLOSED = 0x4,
337
  SESSION_STATE_CLOSING = 0x8,
338
  SESSION_STATE_SENDING = 0x10,
339
  SESSION_STATE_WRITE_IN_PROGRESS = 0x20,
340
  SESSION_STATE_READING_STOPPED = 0x40,
341
  SESSION_STATE_NGHTTP2_RECV_PAUSED = 0x80
342
};
343
344
typedef uint32_t(*get_setting)(nghttp2_session* session,
345
                               nghttp2_settings_id id);
346
347
class Http2Session;
348
class Http2Stream;
349
350
// This scope should be present when any call into nghttp2 that may schedule
351
// data to be written to the underlying transport is made, and schedules
352
// such a write automatically once the scope is exited.
353
class Http2Scope {
354
 public:
355
  explicit Http2Scope(Http2Stream* stream);
356
  explicit Http2Scope(Http2Session* session);
357
  ~Http2Scope();
358
359
 private:
360
  Http2Session* session_ = nullptr;
361
  Local<Object> session_handle_;
362
};
363
364
// The Http2Options class is used to parse the options object passed in to
365
// a Http2Session object and convert those into an appropriate nghttp2_option
366
// struct. This is the primary mechanism by which the Http2Session object is
367
// configured.
368
class Http2Options {
369
 public:
370
  Http2Options(Environment* env, nghttp2_session_type type);
371
372
1180
  ~Http2Options() {
373
590
    nghttp2_option_del(options_);
374
590
  }
375
376
590
  nghttp2_option* operator*() const {
377
590
    return options_;
378
  }
379
380
1
  void SetMaxHeaderPairs(uint32_t max) {
381
1
    max_header_pairs_ = max;
382
1
  }
383
384
590
  uint32_t GetMaxHeaderPairs() const {
385
590
    return max_header_pairs_;
386
  }
387
388
2
  void SetPaddingStrategy(padding_strategy_type val) {
389
2
    padding_strategy_ = val;
390
2
  }
391
392
590
  padding_strategy_type GetPaddingStrategy() const {
393
590
    return padding_strategy_;
394
  }
395
396
2
  void SetMaxOutstandingPings(size_t max) {
397
2
    max_outstanding_pings_ = max;
398
2
  }
399
400
590
  size_t GetMaxOutstandingPings() {
401
590
    return max_outstanding_pings_;
402
  }
403
404
2
  void SetMaxOutstandingSettings(size_t max) {
405
2
    max_outstanding_settings_ = max;
406
2
  }
407
408
590
  size_t GetMaxOutstandingSettings() {
409
590
    return max_outstanding_settings_;
410
  }
411
412
6
  void SetMaxSessionMemory(uint64_t max) {
413
6
    max_session_memory_ = max;
414
6
  }
415
416
590
  uint64_t GetMaxSessionMemory() {
417
590
    return max_session_memory_;
418
  }
419
420
 private:
421
  nghttp2_option* options_;
422
  uint64_t max_session_memory_ = DEFAULT_MAX_SESSION_MEMORY;
423
  uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS;
424
  padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
425
  size_t max_outstanding_pings_ = DEFAULT_MAX_PINGS;
426
  size_t max_outstanding_settings_ = DEFAULT_MAX_SETTINGS;
427
};
428
429
class Http2Priority {
430
 public:
431
  Http2Priority(Environment* env,
432
                Local<Value> parent,
433
                Local<Value> weight,
434
                Local<Value> exclusive);
435
436
11697
  nghttp2_priority_spec* operator*() {
437
11697
    return &spec;
438
  }
439
 private:
440
  nghttp2_priority_spec spec;
441
};
442
443
47200
class Http2StreamListener : public StreamListener {
444
 public:
445
  uv_buf_t OnStreamAlloc(size_t suggested_size) override;
446
  void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
447
};
448
449
class Http2Stream : public AsyncWrap,
450
                    public StreamBase {
451
 public:
452
  static Http2Stream* New(
453
      Http2Session* session,
454
      int32_t id,
455
      nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,
456
      int options = 0);
457
  ~Http2Stream() override;
458
459
  nghttp2_stream* operator*();
460
461
135957
  Http2Session* session() { return session_.get(); }
462
17
  const Http2Session* session() const { return session_.get(); }
463
464
  void EmitStatistics();
465
466
  // Required for StreamBase
467
  int ReadStart() override;
468
469
  // Required for StreamBase
470
  int ReadStop() override;
471
472
  // Required for StreamBase
473
  ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
474
  int DoShutdown(ShutdownWrap* req_wrap) override;
475
476
14
  bool HasWantsWrite() const override { return true; }
477
478
  // Initiate a response on this stream.
479
  int SubmitResponse(nghttp2_nv* nva, size_t len, int options);
480
481
  // Submit informational headers for this stream
482
  int SubmitInfo(nghttp2_nv* nva, size_t len);
483
484
  // Submit trailing headers for this stream
485
  int SubmitTrailers(nghttp2_nv* nva, size_t len);
486
  void OnTrailers();
487
488
  // Submit a PRIORITY frame for this stream
489
  int SubmitPriority(nghttp2_priority_spec* prispec, bool silent = false);
490
491
  // Submits an RST_STREAM frame using the given code
492
  void SubmitRstStream(const uint32_t code);
493
494
  void FlushRstStream();
495
496
  // Submits a PUSH_PROMISE frame with this stream as the parent.
497
  Http2Stream* SubmitPushPromise(
498
      nghttp2_nv* nva,
499
      size_t len,
500
      int32_t* ret,
501
      int options = 0);
502
503
504
  void Close(int32_t code);
505
506
  // Destroy this stream instance and free all held memory.
507
  void Destroy();
508
509
373360
  inline bool IsDestroyed() const {
510
373360
    return flags_ & NGHTTP2_STREAM_FLAG_DESTROYED;
511
  }
512
513
47727
  inline bool IsWritable() const {
514
47727
    return !(flags_ & NGHTTP2_STREAM_FLAG_SHUT);
515
  }
516
517
  inline bool IsPaused() const {
518
    return flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED;
519
  }
520
521
  inline bool IsClosed() const {
522
    return flags_ & NGHTTP2_STREAM_FLAG_CLOSED;
523
  }
524
525
12609
  inline bool HasTrailers() const {
526
12609
    return flags_ & NGHTTP2_STREAM_FLAG_TRAILERS;
527
  }
528
529
  // Returns true if this stream is in the reading state, which occurs when
530
  // the NGHTTP2_STREAM_FLAG_READ_START flag has been set and the
531
  // NGHTTP2_STREAM_FLAG_READ_PAUSED flag is *not* set.
532
13841
  inline bool IsReading() const {
533

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

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

142468
    if (nghttp2_rcbuf_is_static(buf)) {
1225
117579
      auto& static_str_map = env->isolate_data()->http2_static_strs;
1226
117579
      v8::Eternal<v8::String>& eternal = static_str_map[buf];
1227

117579
      if (eternal.IsEmpty()) {
1228
        Local<String> str =
1229
3464
            GetInternalizedString(env, nghttp2_rcbuf_get_buf(buf))
1230
1732
                .ToLocalChecked();
1231
1732
        eternal.Set(env->isolate(), str);
1232
1732
        return str;
1233
      }
1234
231694
      return eternal.Get(env->isolate());
1235
    }
1236
1237
24889
    nghttp2_vec vec = nghttp2_rcbuf_get_buf(buf);
1238

24889
    if (vec.len == 0) {
1239
1
      nghttp2_rcbuf_decref(buf);
1240
2
      return String::Empty(env->isolate());
1241
    }
1242
1243
56
    if (may_internalize && vec.len < 64) {
1244
56
      nghttp2_rcbuf_decref(buf);
1245
      // This is a short header name, so there is a good chance V8 already has
1246
      // it internalized.
1247
56
      return GetInternalizedString(env, vec);
1248
    }
1249
1250
24832
    session->StopTrackingRcbuf(buf);
1251
24832
    ExternalHeader* h_str = new ExternalHeader(buf);
1252
24832
    MaybeLocal<String> str = String::NewExternalOneByte(env->isolate(), h_str);
1253

24832
    if (str.IsEmpty())
1254
      delete h_str;
1255
1256
24832
    return str;
1257
  }
1258
1259
 private:
1260
  nghttp2_rcbuf* buf_;
1261
  nghttp2_vec vec_;
1262
};
1263
1264
class Headers {
1265
 public:
1266
  Headers(Isolate* isolate, Local<Context> context, Local<Array> headers);
1267
23355
  ~Headers() = default;
1268
1269
23355
  nghttp2_nv* operator*() {
1270
23355
    return reinterpret_cast<nghttp2_nv*>(*buf_);
1271
  }
1272
1273
23390
  size_t length() const {
1274
23390
    return count_;
1275
  }
1276
1277
 private:
1278
  size_t count_;
1279
  MaybeStackBuffer<char, 3000> buf_;
1280
};
1281
1282
class Origins {
1283
 public:
1284
  Origins(Isolate* isolate,
1285
          Local<Context> context,
1286
          Local<v8::String> origin_string,
1287
          size_t origin_count);
1288
5
  ~Origins() = default;
1289
1290
5
  nghttp2_origin_entry* operator*() {
1291
5
    return reinterpret_cast<nghttp2_origin_entry*>(*buf_);
1292
  }
1293
1294
5
  size_t length() const {
1295
5
    return count_;
1296
  }
1297
1298
 private:
1299
  size_t count_;
1300
  MaybeStackBuffer<char, 512> buf_;
1301
};
1302
1303
}  // namespace http2
1304
}  // namespace node
1305
1306
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1307
1308
#endif  // SRC_NODE_HTTP2_H_