Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_http2.h
Go to the documentation of this file.
1 #ifndef SRC_NODE_HTTP2_H_
2 #define SRC_NODE_HTTP2_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include "node_http2_core-inl.h"
7 #include "stream_base-inl.h"
8 #include "string_bytes.h"
9 
10 namespace node {
11 namespace http2 {
12 
13 using v8::Array;
14 using v8::Context;
15 using v8::EscapableHandleScope;
16 using v8::Isolate;
17 using v8::MaybeLocal;
18 
19 #define HTTP_KNOWN_METHODS(V) \
20  V(ACL, "ACL") \
21  V(BASELINE_CONTROL, "BASELINE-CONTROL") \
22  V(BIND, "BIND") \
23  V(CHECKIN, "CHECKIN") \
24  V(CHECKOUT, "CHECKOUT") \
25  V(CONNECT, "CONNECT") \
26  V(COPY, "COPY") \
27  V(DELETE, "DELETE") \
28  V(GET, "GET") \
29  V(HEAD, "HEAD") \
30  V(LABEL, "LABEL") \
31  V(LINK, "LINK") \
32  V(LOCK, "LOCK") \
33  V(MERGE, "MERGE") \
34  V(MKACTIVITY, "MKACTIVITY") \
35  V(MKCALENDAR, "MKCALENDAR") \
36  V(MKCOL, "MKCOL") \
37  V(MKREDIRECTREF, "MKREDIRECTREF") \
38  V(MKWORKSPACE, "MKWORKSPACE") \
39  V(MOVE, "MOVE") \
40  V(OPTIONS, "OPTIONS") \
41  V(ORDERPATCH, "ORDERPATCH") \
42  V(PATCH, "PATCH") \
43  V(POST, "POST") \
44  V(PRI, "PRI") \
45  V(PROPFIND, "PROPFIND") \
46  V(PROPPATCH, "PROPPATCH") \
47  V(PUT, "PUT") \
48  V(REBIND, "REBIND") \
49  V(REPORT, "REPORT") \
50  V(SEARCH, "SEARCH") \
51  V(TRACE, "TRACE") \
52  V(UNBIND, "UNBIND") \
53  V(UNCHECKOUT, "UNCHECKOUT") \
54  V(UNLINK, "UNLINK") \
55  V(UNLOCK, "UNLOCK") \
56  V(UPDATE, "UPDATE") \
57  V(UPDATEREDIRECTREF, "UPDATEREDIRECTREF") \
58  V(VERSION_CONTROL, "VERSION-CONTROL")
59 
60 #define HTTP_KNOWN_HEADERS(V) \
61  V(STATUS, ":status") \
62  V(METHOD, ":method") \
63  V(AUTHORITY, ":authority") \
64  V(SCHEME, ":scheme") \
65  V(PATH, ":path") \
66  V(ACCEPT_CHARSET, "accept-charset") \
67  V(ACCEPT_ENCODING, "accept-encoding") \
68  V(ACCEPT_LANGUAGE, "accept-language") \
69  V(ACCEPT_RANGES, "accept-ranges") \
70  V(ACCEPT, "accept") \
71  V(ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin") \
72  V(AGE, "age") \
73  V(ALLOW, "allow") \
74  V(AUTHORIZATION, "authorization") \
75  V(CACHE_CONTROL, "cache-control") \
76  V(CONNECTION, "connection") \
77  V(CONTENT_DISPOSITION, "content-disposition") \
78  V(CONTENT_ENCODING, "content-encoding") \
79  V(CONTENT_LANGUAGE, "content-language") \
80  V(CONTENT_LENGTH, "content-length") \
81  V(CONTENT_LOCATION, "content-location") \
82  V(CONTENT_MD5, "content-md5") \
83  V(CONTENT_RANGE, "content-range") \
84  V(CONTENT_TYPE, "content-type") \
85  V(COOKIE, "cookie") \
86  V(DATE, "date") \
87  V(ETAG, "etag") \
88  V(EXPECT, "expect") \
89  V(EXPIRES, "expires") \
90  V(FROM, "from") \
91  V(HOST, "host") \
92  V(IF_MATCH, "if-match") \
93  V(IF_MODIFIED_SINCE, "if-modified-since") \
94  V(IF_NONE_MATCH, "if-none-match") \
95  V(IF_RANGE, "if-range") \
96  V(IF_UNMODIFIED_SINCE, "if-unmodified-since") \
97  V(LAST_MODIFIED, "last-modified") \
98  V(LINK, "link") \
99  V(LOCATION, "location") \
100  V(MAX_FORWARDS, "max-forwards") \
101  V(PREFER, "prefer") \
102  V(PROXY_AUTHENTICATE, "proxy-authenticate") \
103  V(PROXY_AUTHORIZATION, "proxy-authorization") \
104  V(RANGE, "range") \
105  V(REFERER, "referer") \
106  V(REFRESH, "refresh") \
107  V(RETRY_AFTER, "retry-after") \
108  V(SERVER, "server") \
109  V(SET_COOKIE, "set-cookie") \
110  V(STRICT_TRANSPORT_SECURITY, "strict-transport-security") \
111  V(TRANSFER_ENCODING, "transfer-encoding") \
112  V(TE, "te") \
113  V(UPGRADE, "upgrade") \
114  V(USER_AGENT, "user-agent") \
115  V(VARY, "vary") \
116  V(VIA, "via") \
117  V(WWW_AUTHENTICATE, "www-authenticate") \
118  V(HTTP2_SETTINGS, "http2-settings") \
119  V(KEEP_ALIVE, "keep-alive") \
120  V(PROXY_CONNECTION, "proxy-connection")
121 
122 enum http_known_headers {
123 HTTP_KNOWN_HEADER_MIN,
124 #define V(name, value) HTTP_HEADER_##name,
125 HTTP_KNOWN_HEADERS(V)
126 #undef V
127 HTTP_KNOWN_HEADER_MAX
128 };
129 
130 #define HTTP_STATUS_CODES(V) \
131  V(CONTINUE, 100) \
132  V(SWITCHING_PROTOCOLS, 101) \
133  V(PROCESSING, 102) \
134  V(OK, 200) \
135  V(CREATED, 201) \
136  V(ACCEPTED, 202) \
137  V(NON_AUTHORITATIVE_INFORMATION, 203) \
138  V(NO_CONTENT, 204) \
139  V(RESET_CONTENT, 205) \
140  V(PARTIAL_CONTENT, 206) \
141  V(MULTI_STATUS, 207) \
142  V(ALREADY_REPORTED, 208) \
143  V(IM_USED, 226) \
144  V(MULTIPLE_CHOICES, 300) \
145  V(MOVED_PERMANENTLY, 301) \
146  V(FOUND, 302) \
147  V(SEE_OTHER, 303) \
148  V(NOT_MODIFIED, 304) \
149  V(USE_PROXY, 305) \
150  V(TEMPORARY_REDIRECT, 307) \
151  V(PERMANENT_REDIRECT, 308) \
152  V(BAD_REQUEST, 400) \
153  V(UNAUTHORIZED, 401) \
154  V(PAYMENT_REQUIRED, 402) \
155  V(FORBIDDEN, 403) \
156  V(NOT_FOUND, 404) \
157  V(METHOD_NOT_ALLOWED, 405) \
158  V(NOT_ACCEPTABLE, 406) \
159  V(PROXY_AUTHENTICATION_REQUIRED, 407) \
160  V(REQUEST_TIMEOUT, 408) \
161  V(CONFLICT, 409) \
162  V(GONE, 410) \
163  V(LENGTH_REQUIRED, 411) \
164  V(PRECONDITION_FAILED, 412) \
165  V(PAYLOAD_TOO_LARGE, 413) \
166  V(URI_TOO_LONG, 414) \
167  V(UNSUPPORTED_MEDIA_TYPE, 415) \
168  V(RANGE_NOT_SATISFIABLE, 416) \
169  V(EXPECTATION_FAILED, 417) \
170  V(TEAPOT, 418) \
171  V(MISDIRECTED_REQUEST, 421) \
172  V(UNPROCESSABLE_ENTITY, 422) \
173  V(LOCKED, 423) \
174  V(FAILED_DEPENDENCY, 424) \
175  V(UNORDERED_COLLECTION, 425) \
176  V(UPGRADE_REQUIRED, 426) \
177  V(PRECONDITION_REQUIRED, 428) \
178  V(TOO_MANY_REQUESTS, 429) \
179  V(REQUEST_HEADER_FIELDS_TOO_LARGE, 431) \
180  V(UNAVAILABLE_FOR_LEGAL_REASONS, 451) \
181  V(INTERNAL_SERVER_ERROR, 500) \
182  V(NOT_IMPLEMENTED, 501) \
183  V(BAD_GATEWAY, 502) \
184  V(SERVICE_UNAVAILABLE, 503) \
185  V(GATEWAY_TIMEOUT, 504) \
186  V(HTTP_VERSION_NOT_SUPPORTED, 505) \
187  V(VARIANT_ALSO_NEGOTIATES, 506) \
188  V(INSUFFICIENT_STORAGE, 507) \
189  V(LOOP_DETECTED, 508) \
190  V(BANDWIDTH_LIMIT_EXCEEDED, 509) \
191  V(NOT_EXTENDED, 510) \
192  V(NETWORK_AUTHENTICATION_REQUIRED, 511)
193 
194 enum http_status_codes {
195 #define V(name, code) HTTP_STATUS_##name = code,
196 HTTP_STATUS_CODES(V)
197 #undef V
198 };
199 
200 enum padding_strategy_type {
201  // No padding strategy
202  PADDING_STRATEGY_NONE,
203  // Padding will ensure all data frames are maxFrameSize
204  PADDING_STRATEGY_MAX,
205  // Padding will be determined via JS callback
206  PADDING_STRATEGY_CALLBACK
207 };
208 
209 #define NGHTTP2_ERROR_CODES(V) \
210  V(NGHTTP2_ERR_INVALID_ARGUMENT) \
211  V(NGHTTP2_ERR_BUFFER_ERROR) \
212  V(NGHTTP2_ERR_UNSUPPORTED_VERSION) \
213  V(NGHTTP2_ERR_WOULDBLOCK) \
214  V(NGHTTP2_ERR_PROTO) \
215  V(NGHTTP2_ERR_INVALID_FRAME) \
216  V(NGHTTP2_ERR_EOF) \
217  V(NGHTTP2_ERR_DEFERRED) \
218  V(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE) \
219  V(NGHTTP2_ERR_STREAM_CLOSED) \
220  V(NGHTTP2_ERR_STREAM_CLOSING) \
221  V(NGHTTP2_ERR_STREAM_SHUT_WR) \
222  V(NGHTTP2_ERR_INVALID_STREAM_ID) \
223  V(NGHTTP2_ERR_INVALID_STREAM_STATE) \
224  V(NGHTTP2_ERR_DEFERRED_DATA_EXIST) \
225  V(NGHTTP2_ERR_START_STREAM_NOT_ALLOWED) \
226  V(NGHTTP2_ERR_GOAWAY_ALREADY_SENT) \
227  V(NGHTTP2_ERR_INVALID_HEADER_BLOCK) \
228  V(NGHTTP2_ERR_INVALID_STATE) \
229  V(NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) \
230  V(NGHTTP2_ERR_FRAME_SIZE_ERROR) \
231  V(NGHTTP2_ERR_HEADER_COMP) \
232  V(NGHTTP2_ERR_FLOW_CONTROL) \
233  V(NGHTTP2_ERR_INSUFF_BUFSIZE) \
234  V(NGHTTP2_ERR_PAUSE) \
235  V(NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS) \
236  V(NGHTTP2_ERR_PUSH_DISABLED) \
237  V(NGHTTP2_ERR_DATA_EXIST) \
238  V(NGHTTP2_ERR_SESSION_CLOSING) \
239  V(NGHTTP2_ERR_HTTP_HEADER) \
240  V(NGHTTP2_ERR_HTTP_MESSAGING) \
241  V(NGHTTP2_ERR_REFUSED_STREAM) \
242  V(NGHTTP2_ERR_INTERNAL) \
243  V(NGHTTP2_ERR_CANCEL) \
244  V(NGHTTP2_ERR_FATAL) \
245  V(NGHTTP2_ERR_NOMEM) \
246  V(NGHTTP2_ERR_CALLBACK_FAILURE) \
247  V(NGHTTP2_ERR_BAD_CLIENT_MAGIC) \
248  V(NGHTTP2_ERR_FLOODED)
249 
250 const char* nghttp2_errname(int rv) {
251  switch (rv) {
252 #define V(code) case code: return #code;
253  NGHTTP2_ERROR_CODES(V)
254 #undef V
255  default:
256  return "NGHTTP2_UNKNOWN_ERROR";
257  }
258 }
259 
260 #define DEFAULT_SETTINGS_HEADER_TABLE_SIZE 4096
261 #define DEFAULT_SETTINGS_ENABLE_PUSH 1
262 #define DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE 65535
263 #define DEFAULT_SETTINGS_MAX_FRAME_SIZE 16384
264 #define MAX_MAX_FRAME_SIZE 16777215
265 #define MIN_MAX_FRAME_SIZE DEFAULT_SETTINGS_MAX_FRAME_SIZE
266 #define MAX_INITIAL_WINDOW_SIZE 2147483647
267 
268 class Http2Options {
269  public:
270  explicit Http2Options(Environment* env);
271 
272  ~Http2Options() {
273  nghttp2_option_del(options_);
274  }
275 
276  nghttp2_option* operator*() const {
277  return options_;
278  }
279 
280  void SetPaddingStrategy(padding_strategy_type val) {
281  CHECK_LE(val, PADDING_STRATEGY_CALLBACK);
282  padding_strategy_ = static_cast<padding_strategy_type>(val);
283  }
284 
285  padding_strategy_type GetPaddingStrategy() {
286  return padding_strategy_;
287  }
288 
289  private:
290  nghttp2_option* options_;
291  padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
292 };
293 
294 static const size_t kAllocBufferSize = 64 * 1024;
295 
297 typedef uint32_t(*get_setting)(nghttp2_session* session,
298  nghttp2_settings_id id);
299 
300 class Http2Session : public AsyncWrap,
301  public StreamBase,
302  public Nghttp2Session {
303  public:
304  Http2Session(Environment* env,
305  Local<Object> wrap,
306  nghttp2_session_type type) :
307  AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
308  StreamBase(env) {
309  Wrap(object(), this);
310 
311  Http2Options opts(env);
312 
313  padding_strategy_ = opts.GetPaddingStrategy();
314 
315  Init(env->event_loop(), type, *opts);
316  }
317 
318  ~Http2Session() override {
319  CHECK_EQ(false, persistent().IsEmpty());
320  ClearWrap(object());
321  persistent().Reset();
322  CHECK_EQ(true, persistent().IsEmpty());
323  }
324 
325  static void OnStreamAllocImpl(size_t suggested_size,
326  uv_buf_t* buf,
327  void* ctx);
328  static void OnStreamReadImpl(ssize_t nread,
329  const uv_buf_t* bufs,
330  uv_handle_type pending,
331  void* ctx);
332  protected:
333  void OnFreeSession() override;
334 
335  ssize_t OnMaxFrameSizePadding(size_t frameLength,
336  size_t maxPayloadLen);
337 
338  ssize_t OnCallbackPadding(size_t frame,
339  size_t maxPayloadLen);
340 
341  bool HasGetPaddingCallback() override {
342  return padding_strategy_ == PADDING_STRATEGY_MAX ||
343  padding_strategy_ == PADDING_STRATEGY_CALLBACK;
344  }
345 
346  ssize_t GetPadding(size_t frameLength, size_t maxPayloadLen) override {
347  if (padding_strategy_ == PADDING_STRATEGY_MAX) {
348  return OnMaxFrameSizePadding(frameLength, maxPayloadLen);
349  }
350 
351  CHECK_EQ(padding_strategy_, PADDING_STRATEGY_CALLBACK);
352 
353  return OnCallbackPadding(frameLength, maxPayloadLen);
354  }
355 
356  void OnHeaders(Nghttp2Stream* stream,
357  nghttp2_header_list* headers,
358  nghttp2_headers_category cat,
359  uint8_t flags) override;
360  void OnStreamClose(int32_t id, uint32_t code) override;
361  void Send(uv_buf_t* bufs, size_t total) override;
362  void OnDataChunk(Nghttp2Stream* stream, nghttp2_data_chunk_t* chunk) override;
363  void OnSettings(bool ack) override;
364  void OnPriority(int32_t stream,
365  int32_t parent,
366  int32_t weight,
367  int8_t exclusive) override;
368  void OnGoAway(int32_t lastStreamID,
369  uint32_t errorCode,
370  uint8_t* data,
371  size_t length) override;
372  void OnFrameError(int32_t id, uint8_t type, int error_code) override;
373  void OnTrailers(Nghttp2Stream* stream,
374  const SubmitTrailers& submit_trailers) override;
375  void AllocateSend(size_t recommended, uv_buf_t* buf) override;
376 
377  int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count,
378  uv_stream_t* send_handle) override;
379 
380  AsyncWrap* GetAsyncWrap() override {
381  return static_cast<AsyncWrap*>(this);
382  }
383 
384  void* Cast() override {
385  return reinterpret_cast<void*>(this);
386  }
387 
388  // Required for StreamBase
389  bool IsAlive() override {
390  return true;
391  }
392 
393  // Required for StreamBase
394  bool IsClosing() override {
395  return false;
396  }
397 
398  // Required for StreamBase
399  int ReadStart() override { return 0; }
400 
401  // Required for StreamBase
402  int ReadStop() override { return 0; }
403 
404  // Required for StreamBase
405  int DoShutdown(ShutdownWrap* req_wrap) override {
406  return 0;
407  }
408 
409  public:
410  void Consume(Local<External> external);
411  void Unconsume();
412 
413  static void New(const FunctionCallbackInfo<Value>& args);
414  static void Consume(const FunctionCallbackInfo<Value>& args);
415  static void Unconsume(const FunctionCallbackInfo<Value>& args);
416  static void Destroying(const FunctionCallbackInfo<Value>& args);
417  static void Destroy(const FunctionCallbackInfo<Value>& args);
418  static void SubmitSettings(const FunctionCallbackInfo<Value>& args);
419  static void SubmitRstStream(const FunctionCallbackInfo<Value>& args);
420  static void SubmitResponse(const FunctionCallbackInfo<Value>& args);
421  static void SubmitFile(const FunctionCallbackInfo<Value>& args);
422  static void SubmitRequest(const FunctionCallbackInfo<Value>& args);
423  static void SubmitPushPromise(const FunctionCallbackInfo<Value>& args);
424  static void SubmitPriority(const FunctionCallbackInfo<Value>& args);
425  static void SendHeaders(const FunctionCallbackInfo<Value>& args);
426  static void ShutdownStream(const FunctionCallbackInfo<Value>& args);
427  static void StreamWrite(const FunctionCallbackInfo<Value>& args);
428  static void StreamReadStart(const FunctionCallbackInfo<Value>& args);
429  static void StreamReadStop(const FunctionCallbackInfo<Value>& args);
430  static void SetNextStreamID(const FunctionCallbackInfo<Value>& args);
431  static void SendShutdownNotice(const FunctionCallbackInfo<Value>& args);
432  static void SubmitGoaway(const FunctionCallbackInfo<Value>& args);
433  static void DestroyStream(const FunctionCallbackInfo<Value>& args);
434 
435  template <get_setting fn>
436  static void GetSettings(const FunctionCallbackInfo<Value>& args);
437 
438  size_t self_size() const override {
439  return sizeof(*this);
440  }
441 
442  char* stream_alloc() {
443  return stream_buf_;
444  }
445 
446  private:
447  StreamBase* stream_;
448  StreamResource::Callback<StreamResource::AllocCb> prev_alloc_cb_;
449  StreamResource::Callback<StreamResource::ReadCb> prev_read_cb_;
450  padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE;
451 
452  char stream_buf_[kAllocBufferSize];
453 };
454 
455 class ExternalHeader :
456  public String::ExternalOneByteStringResource {
457  public:
458  explicit ExternalHeader(nghttp2_rcbuf* buf)
459  : buf_(buf), vec_(nghttp2_rcbuf_get_buf(buf)) {
460  }
461 
462  ~ExternalHeader() override {
463  nghttp2_rcbuf_decref(buf_);
464  buf_ = nullptr;
465  }
466 
467  const char* data() const override {
468  return const_cast<const char*>(reinterpret_cast<char*>(vec_.base));
469  }
470 
471  size_t length() const override {
472  return vec_.len;
473  }
474 
475  static inline
476  MaybeLocal<String> GetInternalizedString(Environment* env,
477  const nghttp2_vec& vec) {
478  return String::NewFromOneByte(env->isolate(),
479  vec.base,
480  v8::NewStringType::kInternalized,
481  vec.len);
482  }
483 
484  template<bool may_internalize>
485  static MaybeLocal<String> New(Environment* env, nghttp2_rcbuf* buf) {
486  if (nghttp2_rcbuf_is_static(buf)) {
487  auto& static_str_map = env->isolate_data()->http2_static_strs;
488  v8::Eternal<v8::String>& eternal = static_str_map[buf];
489  if (eternal.IsEmpty()) {
490  Local<String> str =
491  GetInternalizedString(env, nghttp2_rcbuf_get_buf(buf))
492  .ToLocalChecked();
493  eternal.Set(env->isolate(), str);
494  return str;
495  }
496  return eternal.Get(env->isolate());
497  }
498 
499  nghttp2_vec vec = nghttp2_rcbuf_get_buf(buf);
500  if (vec.len == 0) {
501  nghttp2_rcbuf_decref(buf);
502  return String::Empty(env->isolate());
503  }
504 
505  if (may_internalize && vec.len < 64) {
506  // This is a short header name, so there is a good chance V8 already has
507  // it internalized.
508  return GetInternalizedString(env, vec);
509  }
510 
511  ExternalHeader* h_str = new ExternalHeader(buf);
512  MaybeLocal<String> str = String::NewExternalOneByte(env->isolate(), h_str);
513  if (str.IsEmpty())
514  delete h_str;
515 
516  return str;
517  }
518 
519  private:
520  nghttp2_rcbuf* buf_;
521  nghttp2_vec vec_;
522 };
523 
524 class Headers {
525  public:
526  Headers(Isolate* isolate, Local<Context> context, Local<Array> headers);
527  ~Headers() {}
528 
529  nghttp2_nv* operator*() {
530  return reinterpret_cast<nghttp2_nv*>(*buf_);
531  }
532 
533  size_t length() const {
534  return count_;
535  }
536 
537  private:
538  size_t count_;
539  MaybeStackBuffer<char, 3000> buf_;
540 };
541 
542 } // namespace http2
543 } // namespace node
544 
545 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
546 
547 #endif // SRC_NODE_HTTP2_H_
StreamResource::Callback< StreamResource::AllocCb > prev_alloc_cb_
unsigned char * buf
Definition: cares_wrap.cc:483
QueryWrap * wrap
Definition: cares_wrap.cc:478
union node::cares_wrap::@8::CaresAsyncData::@0 data
#define V(PROVIDER)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
this ctx
Definition: v8ustack.d:369
void Init(int *argc, const char **argv, int *exec_argc, const char ***exec_argv)
Definition: node.cc:4351
StreamResource::Callback< StreamResource::ReadCb > prev_read_cb_