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