• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SRC_NODE_HTTP_COMMON_H_
2 #define SRC_NODE_HTTP_COMMON_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include "v8.h"
7 #include "node_mem.h"
8 
9 #include <string>
10 
11 namespace node {
12 
13 class Environment;
14 
15 #define MAX_MAX_HEADER_LIST_SIZE 16777215u
16 #define DEFAULT_MAX_HEADER_LIST_PAIRS 128u
17 #define DEFAULT_MAX_HEADER_LENGTH 8192
18 
19 #define HTTP_SPECIAL_HEADERS(V)                                               \
20   V(STATUS, ":status")                                                        \
21   V(METHOD, ":method")                                                        \
22   V(AUTHORITY, ":authority")                                                  \
23   V(SCHEME, ":scheme")                                                        \
24   V(PATH, ":path")                                                            \
25   V(PROTOCOL, ":protocol")
26 
27 #define HTTP_REGULAR_HEADERS(V)                                                \
28   V(ACCEPT_ENCODING, "accept-encoding")                                        \
29   V(ACCEPT_LANGUAGE, "accept-language")                                        \
30   V(ACCEPT_RANGES, "accept-ranges")                                            \
31   V(ACCEPT, "accept")                                                          \
32   V(ACCESS_CONTROL_ALLOW_CREDENTIALS, "access-control-allow-credentials")      \
33   V(ACCESS_CONTROL_ALLOW_HEADERS, "access-control-allow-headers")              \
34   V(ACCESS_CONTROL_ALLOW_METHODS, "access-control-allow-methods")              \
35   V(ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin")                \
36   V(ACCESS_CONTROL_EXPOSE_HEADERS, "access-control-expose-headers")            \
37   V(ACCESS_CONTROL_REQUEST_HEADERS, "access-control-request-headers")          \
38   V(ACCESS_CONTROL_REQUEST_METHOD, "access-control-request-method")            \
39   V(AGE, "age")                                                                \
40   V(AUTHORIZATION, "authorization")                                            \
41   V(CACHE_CONTROL, "cache-control")                                            \
42   V(CONNECTION, "connection")                                                  \
43   V(CONTENT_DISPOSITION, "content-disposition")                                \
44   V(CONTENT_ENCODING, "content-encoding")                                      \
45   V(CONTENT_LENGTH, "content-length")                                          \
46   V(CONTENT_TYPE, "content-type")                                              \
47   V(COOKIE, "cookie")                                                          \
48   V(DATE, "date")                                                              \
49   V(ETAG, "etag")                                                              \
50   V(FORWARDED, "forwarded")                                                    \
51   V(HOST, "host")                                                              \
52   V(IF_MODIFIED_SINCE, "if-modified-since")                                    \
53   V(IF_NONE_MATCH, "if-none-match")                                            \
54   V(IF_RANGE, "if-range")                                                      \
55   V(LAST_MODIFIED, "last-modified")                                            \
56   V(LINK, "link")                                                              \
57   V(LOCATION, "location")                                                      \
58   V(RANGE, "range")                                                            \
59   V(REFERER, "referer")                                                        \
60   V(SERVER, "server")                                                          \
61   V(SET_COOKIE, "set-cookie")                                                  \
62   V(STRICT_TRANSPORT_SECURITY, "strict-transport-security")                    \
63   V(TRANSFER_ENCODING, "transfer-encoding")                                    \
64   V(TE, "te")                                                                  \
65   V(UPGRADE_INSECURE_REQUESTS, "upgrade-insecure-requests")                    \
66   V(UPGRADE, "upgrade")                                                        \
67   V(USER_AGENT, "user-agent")                                                  \
68   V(VARY, "vary")                                                              \
69   V(X_CONTENT_TYPE_OPTIONS, "x-content-type-options")                          \
70   V(X_FRAME_OPTIONS, "x-frame-options")                                        \
71   V(KEEP_ALIVE, "keep-alive")                                                  \
72   V(PROXY_CONNECTION, "proxy-connection")                                      \
73   V(X_XSS_PROTECTION, "x-xss-protection")                                      \
74   V(ALT_SVC, "alt-svc")                                                        \
75   V(CONTENT_SECURITY_POLICY, "content-security-policy")                        \
76   V(EARLY_DATA, "early-data")                                                  \
77   V(EXPECT_CT, "expect-ct")                                                    \
78   V(ORIGIN, "origin")                                                          \
79   V(PURPOSE, "purpose")                                                        \
80   V(TIMING_ALLOW_ORIGIN, "timing-allow-origin")                                \
81   V(X_FORWARDED_FOR, "x-forwarded-for")                                        \
82   V(PRIORITY, "priority")
83 
84 #define HTTP_ADDITIONAL_HEADERS(V)                                            \
85   V(ACCEPT_CHARSET, "accept-charset")                                         \
86   V(ACCESS_CONTROL_MAX_AGE, "access-control-max-age")                         \
87   V(ALLOW, "allow")                                                           \
88   V(CONTENT_LANGUAGE, "content-language")                                     \
89   V(CONTENT_LOCATION, "content-location")                                     \
90   V(CONTENT_MD5, "content-md5")                                               \
91   V(CONTENT_RANGE, "content-range")                                           \
92   V(DNT, "dnt")                                                               \
93   V(EXPECT, "expect")                                                         \
94   V(EXPIRES, "expires")                                                       \
95   V(FROM, "from")                                                             \
96   V(IF_MATCH, "if-match")                                                     \
97   V(IF_UNMODIFIED_SINCE, "if-unmodified-since")                               \
98   V(MAX_FORWARDS, "max-forwards")                                             \
99   V(PREFER, "prefer")                                                         \
100   V(PROXY_AUTHENTICATE, "proxy-authenticate")                                 \
101   V(PROXY_AUTHORIZATION, "proxy-authorization")                               \
102   V(REFRESH, "refresh")                                                       \
103   V(RETRY_AFTER, "retry-after")                                               \
104   V(TRAILER, "trailer")                                                       \
105   V(TK, "tk")                                                                 \
106   V(VIA, "via")                                                               \
107   V(WARNING, "warning")                                                       \
108   V(WWW_AUTHENTICATE, "www-authenticate")                                     \
109   V(HTTP2_SETTINGS, "http2-settings")
110 
111 // Special and regular headers are handled specifically by the HTTP/2 (and
112 // later HTTP/3) implementation.
113 #define HTTP_KNOWN_HEADERS(V)                                                 \
114   HTTP_SPECIAL_HEADERS(V)                                                     \
115   HTTP_REGULAR_HEADERS(V)                                                     \
116   HTTP_ADDITIONAL_HEADERS(V)
117 
118 enum http_known_headers {
119   HTTP_KNOWN_HEADER_MIN,
120 #define V(name, value) HTTP_HEADER_##name,
121   HTTP_KNOWN_HEADERS(V)
122 #undef V
123   HTTP_KNOWN_HEADER_MAX
124 };
125 
126 #define HTTP_STATUS_CODES(V)                                                  \
127   V(CONTINUE, 100)                                                            \
128   V(SWITCHING_PROTOCOLS, 101)                                                 \
129   V(PROCESSING, 102)                                                          \
130   V(EARLY_HINTS, 103)                                                         \
131   V(OK, 200)                                                                  \
132   V(CREATED, 201)                                                             \
133   V(ACCEPTED, 202)                                                            \
134   V(NON_AUTHORITATIVE_INFORMATION, 203)                                       \
135   V(NO_CONTENT, 204)                                                          \
136   V(RESET_CONTENT, 205)                                                       \
137   V(PARTIAL_CONTENT, 206)                                                     \
138   V(MULTI_STATUS, 207)                                                        \
139   V(ALREADY_REPORTED, 208)                                                    \
140   V(IM_USED, 226)                                                             \
141   V(MULTIPLE_CHOICES, 300)                                                    \
142   V(MOVED_PERMANENTLY, 301)                                                   \
143   V(FOUND, 302)                                                               \
144   V(SEE_OTHER, 303)                                                           \
145   V(NOT_MODIFIED, 304)                                                        \
146   V(USE_PROXY, 305)                                                           \
147   V(TEMPORARY_REDIRECT, 307)                                                  \
148   V(PERMANENT_REDIRECT, 308)                                                  \
149   V(BAD_REQUEST, 400)                                                         \
150   V(UNAUTHORIZED, 401)                                                        \
151   V(PAYMENT_REQUIRED, 402)                                                    \
152   V(FORBIDDEN, 403)                                                           \
153   V(NOT_FOUND, 404)                                                           \
154   V(METHOD_NOT_ALLOWED, 405)                                                  \
155   V(NOT_ACCEPTABLE, 406)                                                      \
156   V(PROXY_AUTHENTICATION_REQUIRED, 407)                                       \
157   V(REQUEST_TIMEOUT, 408)                                                     \
158   V(CONFLICT, 409)                                                            \
159   V(GONE, 410)                                                                \
160   V(LENGTH_REQUIRED, 411)                                                     \
161   V(PRECONDITION_FAILED, 412)                                                 \
162   V(PAYLOAD_TOO_LARGE, 413)                                                   \
163   V(URI_TOO_LONG, 414)                                                        \
164   V(UNSUPPORTED_MEDIA_TYPE, 415)                                              \
165   V(RANGE_NOT_SATISFIABLE, 416)                                               \
166   V(EXPECTATION_FAILED, 417)                                                  \
167   V(TEAPOT, 418)                                                              \
168   V(MISDIRECTED_REQUEST, 421)                                                 \
169   V(UNPROCESSABLE_ENTITY, 422)                                                \
170   V(LOCKED, 423)                                                              \
171   V(FAILED_DEPENDENCY, 424)                                                   \
172   V(TOO_EARLY, 425)                                                           \
173   V(UPGRADE_REQUIRED, 426)                                                    \
174   V(PRECONDITION_REQUIRED, 428)                                               \
175   V(TOO_MANY_REQUESTS, 429)                                                   \
176   V(REQUEST_HEADER_FIELDS_TOO_LARGE, 431)                                     \
177   V(UNAVAILABLE_FOR_LEGAL_REASONS, 451)                                       \
178   V(INTERNAL_SERVER_ERROR, 500)                                               \
179   V(NOT_IMPLEMENTED, 501)                                                     \
180   V(BAD_GATEWAY, 502)                                                         \
181   V(SERVICE_UNAVAILABLE, 503)                                                 \
182   V(GATEWAY_TIMEOUT, 504)                                                     \
183   V(HTTP_VERSION_NOT_SUPPORTED, 505)                                          \
184   V(VARIANT_ALSO_NEGOTIATES, 506)                                             \
185   V(INSUFFICIENT_STORAGE, 507)                                                \
186   V(LOOP_DETECTED, 508)                                                       \
187   V(BANDWIDTH_LIMIT_EXCEEDED, 509)                                            \
188   V(NOT_EXTENDED, 510)                                                        \
189   V(NETWORK_AUTHENTICATION_REQUIRED, 511)
190 
191 enum http_status_codes {
192 #define V(name, code) HTTP_STATUS_##name = code,
193   HTTP_STATUS_CODES(V)
194 #undef V
195 };
196 
197 // Unlike the HTTP/1 implementation, the HTTP/2 implementation is not limited
198 // to a fixed number of known supported HTTP methods. These constants, therefore
199 // are provided strictly as a convenience to users and are exposed via the
200 // require('node:http2').constants object.
201 #define HTTP_KNOWN_METHODS(V)                                                 \
202   V(ACL, "ACL")                                                               \
203   V(BASELINE_CONTROL, "BASELINE-CONTROL")                                     \
204   V(BIND, "BIND")                                                             \
205   V(CHECKIN, "CHECKIN")                                                       \
206   V(CHECKOUT, "CHECKOUT")                                                     \
207   V(CONNECT, "CONNECT")                                                       \
208   V(COPY, "COPY")                                                             \
209   V(DELETE, "DELETE")                                                         \
210   V(GET, "GET")                                                               \
211   V(HEAD, "HEAD")                                                             \
212   V(LABEL, "LABEL")                                                           \
213   V(LINK, "LINK")                                                             \
214   V(LOCK, "LOCK")                                                             \
215   V(MERGE, "MERGE")                                                           \
216   V(MKACTIVITY, "MKACTIVITY")                                                 \
217   V(MKCALENDAR, "MKCALENDAR")                                                 \
218   V(MKCOL, "MKCOL")                                                           \
219   V(MKREDIRECTREF, "MKREDIRECTREF")                                           \
220   V(MKWORKSPACE, "MKWORKSPACE")                                               \
221   V(MOVE, "MOVE")                                                             \
222   V(OPTIONS, "OPTIONS")                                                       \
223   V(ORDERPATCH, "ORDERPATCH")                                                 \
224   V(PATCH, "PATCH")                                                           \
225   V(POST, "POST")                                                             \
226   V(PRI, "PRI")                                                               \
227   V(PROPFIND, "PROPFIND")                                                     \
228   V(PROPPATCH, "PROPPATCH")                                                   \
229   V(PUT, "PUT")                                                               \
230   V(REBIND, "REBIND")                                                         \
231   V(REPORT, "REPORT")                                                         \
232   V(SEARCH, "SEARCH")                                                         \
233   V(TRACE, "TRACE")                                                           \
234   V(UNBIND, "UNBIND")                                                         \
235   V(UNCHECKOUT, "UNCHECKOUT")                                                 \
236   V(UNLINK, "UNLINK")                                                         \
237   V(UNLOCK, "UNLOCK")                                                         \
238   V(UPDATE, "UPDATE")                                                         \
239   V(UPDATEREDIRECTREF, "UPDATEREDIRECTREF")                                   \
240   V(VERSION_CONTROL, "VERSION-CONTROL")
241 
242 // NgHeaders takes as input a block of headers provided by the
243 // JavaScript side (see http2's mapToHeaders function) and
244 // converts it into a array of ng header structs. This is done
245 // generically to handle both http/2 and (in the future) http/3,
246 // which use nearly identical structs. The template parameter
247 // takes a Traits type that defines the ng header struct and
248 // the kNoneFlag value. See Http2HeaderTraits in node_http2.h
249 // for an example.
250 template <typename T>
251 class NgHeaders {
252  public:
253   typedef typename T::nv_t nv_t;
254   inline NgHeaders(Environment* env, v8::Local<v8::Array> headers);
255   ~NgHeaders() = default;
256 
257   const nv_t* operator*() const {
258     return reinterpret_cast<const nv_t*>(*buf_);
259   }
260 
data()261   const nv_t* data() const {
262     return reinterpret_cast<const nv_t*>(*buf_);
263   }
264 
length()265   size_t length() const {
266     return count_;
267   }
268 
269  private:
270   size_t count_;
271   MaybeStackBuffer<char, 3000> buf_;
272 };
273 
274 // The ng libraries use nearly identical
275 // reference counted structures for retaining header name and value
276 // information in memory until the application is done with it.
277 // The NgRcBufPointer is an intelligent pointer capable of working
278 // with either type, handling the ref counting increment and
279 // decrement as appropriate. The Template takes a single Traits
280 // type that provides the rc buffer and vec type, as well as
281 // implementations for multiple static functions.
282 // See Http2RcBufferPointerTraits in node_http2.h for an example.
283 template <typename T>
284 class NgRcBufPointer : public MemoryRetainer {
285  public:
286   typedef typename T::rcbuf_t rcbuf_t;
287   typedef typename T::vector_t vector_t;
288 
289   NgRcBufPointer() = default;
290 
NgRcBufPointer(rcbuf_t * buf)291   explicit NgRcBufPointer(rcbuf_t* buf) {
292     reset(buf);
293   }
294 
295   template <typename B>
NgRcBufPointer(const NgRcBufPointer<B> & other)296   NgRcBufPointer(const NgRcBufPointer<B>& other) {
297     reset(other.get());
298   }
299 
NgRcBufPointer(const NgRcBufPointer & other)300   NgRcBufPointer(const NgRcBufPointer& other) {
301     reset(other.get());
302   }
303 
304   template <typename B>
305   NgRcBufPointer& operator=(const NgRcBufPointer<B>& other) {
306     if (other.get() == get()) return *this;
307     this->~NgRcBufPointer();
308     return *new (this) NgRcBufPointer(other);
309   }
310 
311   NgRcBufPointer& operator=(const NgRcBufPointer& other) {
312     if (other.get() == get()) return *this;
313     this->~NgRcBufPointer();
314     return *new (this) NgRcBufPointer(other);
315   }
316 
NgRcBufPointer(NgRcBufPointer && other)317   NgRcBufPointer(NgRcBufPointer&& other) {
318     this->~NgRcBufPointer();
319     buf_ = other.buf_;
320     other.buf_ = nullptr;
321   }
322 
323   NgRcBufPointer& operator=(NgRcBufPointer&& other) {
324     this->~NgRcBufPointer();
325     return *new (this) NgRcBufPointer(std::move(other));
326   }
327 
~NgRcBufPointer()328   ~NgRcBufPointer() {
329     reset();
330   }
331 
332   // Returns the underlying ngvec for this rcbuf
data()333   uint8_t* data() const {
334     vector_t v = T::get_vec(buf_);
335     return v.base;
336   }
337 
len()338   size_t len() const {
339     vector_t v = T::get_vec(buf_);
340     return v.len;
341   }
342 
str()343   std::string str() const {
344     return std::string(reinterpret_cast<const char*>(data()), len());
345   }
346 
347   void reset(rcbuf_t* ptr = nullptr, bool internalizable = false) {
348     if (buf_ == ptr)
349       return;
350 
351     if (buf_ != nullptr)
352       T::dec(buf_);
353 
354     buf_ = ptr;
355 
356     if (ptr != nullptr) {
357       T::inc(ptr);
358       internalizable_ = internalizable;
359     }
360   }
361 
get()362   rcbuf_t* get() const { return buf_; }
363   rcbuf_t& operator*() const { return *get(); }
364   rcbuf_t* operator->() const { return buf_; }
365   operator bool() const { return buf_ != nullptr; }
IsStatic()366   bool IsStatic() const { return T::is_static(buf_) != 0; }
SetInternalizable()367   void SetInternalizable() { internalizable_ = true; }
IsInternalizable()368   bool IsInternalizable() const { return internalizable_; }
369 
IsZeroLength(rcbuf_t * buf)370   static inline bool IsZeroLength(rcbuf_t* buf) {
371     if (buf == nullptr)
372       return true;
373     vector_t b = T::get_vec(buf);
374     return b.len == 0;
375   }
376 
MemoryInfo(MemoryTracker * tracker)377   void MemoryInfo(MemoryTracker* tracker) const override {
378     tracker->TrackFieldWithSize("buf", len(), "buf");
379   }
380 
381   SET_MEMORY_INFO_NAME(NgRcBufPointer)
SET_SELF_SIZE(NgRcBufPointer)382   SET_SELF_SIZE(NgRcBufPointer)
383 
384   class External : public v8::String::ExternalOneByteStringResource {
385    public:
386     explicit External(const NgRcBufPointer<T>& ptr) : ptr_(ptr) {}
387 
388     const char* data() const override {
389       return const_cast<const char*>(reinterpret_cast<char*>(ptr_.data()));
390     }
391 
392     size_t length() const override {
393       return ptr_.len();
394     }
395 
396     static inline
397     v8::MaybeLocal<v8::String> GetInternalizedString(
398         Environment* env,
399         const NgRcBufPointer<T>& ptr) {
400       return v8::String::NewFromOneByte(
401           env->isolate(),
402           ptr.data(),
403           v8::NewStringType::kInternalized,
404           ptr.len());
405     }
406 
407     template <typename Allocator>
408     static v8::MaybeLocal<v8::String> New(
409         Allocator* allocator,
410         NgRcBufPointer<T> ptr) {
411       Environment* env = allocator->env();
412       if (ptr.IsStatic()) {
413         auto& static_str_map = env->isolate_data()->static_str_map;
414         const char* header_name = reinterpret_cast<const char*>(ptr.data());
415         v8::Eternal<v8::String>& eternal = static_str_map[header_name];
416         if (eternal.IsEmpty()) {
417           v8::Local<v8::String> str =
418               GetInternalizedString(env, ptr).ToLocalChecked();
419           eternal.Set(env->isolate(), str);
420           return str;
421         }
422         return eternal.Get(env->isolate());
423       }
424 
425       size_t len = ptr.len();
426 
427       if (len == 0) {
428         ptr.reset();
429         return v8::String::Empty(env->isolate());
430       }
431 
432       if (ptr.IsInternalizable() && len < 64) {
433         v8::MaybeLocal<v8::String> ret = GetInternalizedString(env, ptr);
434         ptr.reset();
435         return ret;
436       }
437 
438       allocator->StopTrackingMemory(ptr.get());
439       External* h_str = new External(std::move(ptr));
440       v8::MaybeLocal<v8::String> str =
441           v8::String::NewExternalOneByte(env->isolate(), h_str);
442       if (str.IsEmpty())
443         delete h_str;
444 
445       return str;
446     }
447 
448    private:
449     NgRcBufPointer<T> ptr_;
450   };
451 
452  private:
453   rcbuf_t* buf_ = nullptr;
454   bool internalizable_ = false;
455 };
456 
457 template <typename allocator_t>
458 struct NgHeaderBase : public MemoryRetainer {
459   virtual v8::MaybeLocal<v8::String> GetName(allocator_t* allocator) const = 0;
460   virtual v8::MaybeLocal<v8::String> GetValue(allocator_t* allocator) const = 0;
461   virtual std::string name() const = 0;
462   virtual std::string value() const = 0;
463   virtual size_t length() const = 0;
464   virtual uint8_t flags() const = 0;
465   virtual std::string ToString() const;
466 };
467 
468 // The ng libraries use nearly identical structs to represent
469 // received http headers. The NgHeader class wraps those in a
470 // consistent way and allows converting the name and value to
471 // v8 strings. The template is given a Traits type that provides
472 // the NgRcBufPointer type, the NgLibMemoryManager to use for
473 // memory tracking, and implementation of static utility functions.
474 // See Http2HeaderTraits in node_http2.h for an example.
475 template <typename T>
476 class NgHeader final : public NgHeaderBase<typename T::allocator_t> {
477  public:
478   typedef typename T::rcbufferpointer_t rcbufferpointer_t;
479   typedef typename T::rcbufferpointer_t::rcbuf_t rcbuf_t;
480   typedef typename T::allocator_t allocator_t;
481 
482   inline static bool IsZeroLength(rcbuf_t* name, rcbuf_t* value);
483   inline static bool IsZeroLength(int32_t token, rcbuf_t* name, rcbuf_t* value);
484   inline NgHeader(
485       Environment* env,
486       rcbuf_t* name,
487       rcbuf_t* value,
488       uint8_t flags);
489   inline NgHeader(
490       Environment* env,
491       int32_t token,
492       rcbuf_t* name,
493       rcbuf_t* value,
494       uint8_t flags);
495   inline NgHeader(NgHeader<T>&& other) noexcept;
496 
497   // Calling GetName and GetValue will have the effect of releasing
498   // control over the reference counted buffer from this NgHeader
499   // object to the v8 string. Once the v8 string is garbage collected,
500   // the reference counter will be decremented.
501 
502   inline v8::MaybeLocal<v8::String> GetName(
503       allocator_t* allocator) const override;
504   inline v8::MaybeLocal<v8::String> GetValue(
505       allocator_t* allocator) const override;
506 
507   inline std::string name() const override;
508   inline std::string value() const override;
509   inline size_t length() const override;
510   inline uint8_t flags() const override;
511 
512   void MemoryInfo(MemoryTracker* tracker) const override;
513 
514   SET_MEMORY_INFO_NAME(NgHeader)
515   SET_SELF_SIZE(NgHeader)
516 
517  private:
518   Environment* env_;
519   rcbufferpointer_t name_;
520   rcbufferpointer_t value_;
521   int32_t token_ = -1;
522   uint8_t flags_ = 0;
523 };
524 
525 inline size_t GetServerMaxHeaderPairs(size_t max_header_pairs);
526 inline size_t GetClientMaxHeaderPairs(size_t max_header_pairs);
527 
528 }  // namespace node
529 
530 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
531 
532 #endif  // SRC_NODE_HTTP_COMMON_H_
533