nsHttp.h (18473B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=4 sw=2 sts=2 et cin: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsHttp_h__ 8 #define nsHttp_h__ 9 10 #include <stdint.h> 11 #include "prtime.h" 12 #include "nsString.h" 13 #include "nsError.h" 14 #include "nsTArray.h" 15 #include "mozilla/OriginAttributes.h" 16 #include "mozilla/TimeStamp.h" 17 18 #include "mozilla/UniquePtr.h" 19 #include "NSSErrorsService.h" 20 21 class nsICacheEntry; 22 23 namespace mozilla { 24 25 namespace net { 26 class nsHttpResponseHead; 27 class nsHttpRequestHead; 28 class CacheControlParser; 29 30 enum class HttpVersion { 31 UNKNOWN = 0, 32 v0_9 = 9, 33 v1_0 = 10, 34 v1_1 = 11, 35 v2_0 = 20, 36 v3_0 = 30 37 }; 38 39 enum class SpdyVersion { NONE = 0, HTTP_2 = 5 }; 40 41 enum class SupportedAlpnRank : uint8_t { 42 NOT_SUPPORTED = 0, 43 HTTP_1_1 = 1, 44 HTTP_2 = 2, 45 HTTP_3_VER_1 = 3, 46 }; 47 48 // IMPORTANT: when adding new values, always add them to the end, otherwise 49 // it will mess up telemetry. 50 enum class ConnectionCloseReason : uint32_t { 51 UNSET = 0, 52 OK, 53 IDLE_TIMEOUT, 54 TLS_TIMEOUT, 55 GO_AWAY, 56 DNS_ERROR, 57 NET_RESET, 58 NET_TIMEOUT, 59 NET_REFUSED, 60 NET_INTERRUPT, 61 NET_INADEQ_SEQURITY, 62 SOCKET_ADDRESS_NOT_SUPPORTED, 63 OUT_OF_MEMORY, 64 SOCKET_ADDRESS_IN_USE, 65 BINDING_ABORTED, 66 BINDING_REDIRECTED, 67 ERROR_ABORT, 68 CLOSE_EXISTING_CONN_FOR_COALESCING, 69 CLOSE_NEW_CONN_FOR_COALESCING, 70 CANT_REUSED, 71 OTHER_NET_ERROR, 72 SECURITY_ERROR, 73 }; 74 75 ConnectionCloseReason ToCloseReason(nsresult aErrorCode); 76 77 inline bool IsHttp3(SupportedAlpnRank aRank) { 78 return aRank == SupportedAlpnRank::HTTP_3_VER_1; 79 } 80 81 //----------------------------------------------------------------------------- 82 // http connection capabilities 83 //----------------------------------------------------------------------------- 84 85 #define NS_HTTP_ALLOW_KEEPALIVE (1 << 0) 86 #define NS_HTTP_LARGE_KEEPALIVE (1 << 1) 87 88 // a transaction with this caps flag will continue to own the connection, 89 // preventing it from being reclaimed, even after the transaction completes. 90 #define NS_HTTP_STICKY_CONNECTION (1 << 2) 91 92 // a transaction with this caps flag will, upon opening a new connection, 93 // bypass the local DNS cache 94 #define NS_HTTP_REFRESH_DNS (1 << 3) 95 96 // a transaction with this caps flag will not pass SSL client-certificates 97 // to the server (see bug #466080), but is may also be used for other things 98 #define NS_HTTP_LOAD_ANONYMOUS (1 << 4) 99 100 // a transaction with this flag blocks the initiation of other transactons 101 // in the same load group until it is complete 102 #define NS_HTTP_LOAD_AS_BLOCKING (1 << 6) 103 104 // Disallow the use of the SPDY protocol. This is meant for the contexts 105 // such as HTTP upgrade which are nonsensical for SPDY, it is not the 106 // SPDY configuration variable. 107 #define NS_HTTP_DISALLOW_SPDY (1 << 7) 108 109 // a transaction with this flag loads without respect to whether the load 110 // group is currently blocking on some resources 111 #define NS_HTTP_LOAD_UNBLOCKED (1 << 8) 112 113 // This flag indicates the transaction should accept associated pushes 114 #define NS_HTTP_ONPUSH_LISTENER (1 << 9) 115 116 // Transactions with this flag should react to errors without side effects 117 // First user is to prevent clearing of alt-svc cache on failed probe 118 #define NS_HTTP_ERROR_SOFTLY (1 << 10) 119 120 // This corresponds to nsIHttpChannelInternal.beConservative 121 // it disables any cutting edge features that we are worried might result in 122 // interop problems with critical infrastructure 123 #define NS_HTTP_BE_CONSERVATIVE (1 << 11) 124 125 // Transactions with this flag should be processed first. 126 #define NS_HTTP_URGENT_START (1 << 12) 127 128 // A sticky connection of the transaction is explicitly allowed to be restarted 129 // on ERROR_NET_RESET. 130 #define NS_HTTP_CONNECTION_RESTARTABLE (1 << 13) 131 132 // Allow re-using a spdy/http2 connection with NS_HTTP_ALLOW_KEEPALIVE not set. 133 // This is primarily used to allow connection sharing for websockets over http/2 134 // without accidentally allowing it for websockets not over http/2 135 #define NS_HTTP_ALLOW_SPDY_WITHOUT_KEEPALIVE (1 << 15) 136 137 // Only permit CONNECTing to a proxy. A channel with this flag will not send an 138 // http request after CONNECT or setup tls. An http upgrade handler MUST be 139 // set. An ALPN header is set using the upgrade protocol. 140 #define NS_HTTP_CONNECT_ONLY (1 << 16) 141 142 // The connection should not use IPv4. 143 #define NS_HTTP_DISABLE_IPV4 (1 << 17) 144 145 // The connection should not use IPv6 146 #define NS_HTTP_DISABLE_IPV6 (1 << 18) 147 148 // Encodes the TRR mode. 149 #define NS_HTTP_TRR_MODE_MASK ((1 << 19) | (1 << 20)) 150 151 // Disallow the use of the HTTP3 protocol. This is meant for the contexts 152 // such as HTTP upgrade which are not supported by HTTP3. 153 #define NS_HTTP_DISALLOW_HTTP3 (1 << 21) 154 155 // Force a transaction to stay in pending queue until the HTTPS RR is 156 // available. 157 #define NS_HTTP_FORCE_WAIT_HTTP_RR (1 << 22) 158 159 // This is used for a temporary workaround for a web-compat issue. The flag is 160 // only set on CORS preflight request to allowed sending client certificates 161 // on a connection for an anonymous request. 162 #define NS_HTTP_LOAD_ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT (1 << 23) 163 164 #define NS_HTTP_DISALLOW_HTTPS_RR (1 << 24) 165 166 #define NS_HTTP_DISALLOW_ECH (1 << 25) 167 168 // Used to indicate that an HTTP Connection should obey Resist Fingerprinting 169 // and set the User-Agent accordingly. 170 #define NS_HTTP_USE_RFP (1 << 26) 171 172 // If set, then the initial TLS handshake failed. 173 #define NS_HTTP_IS_RETRY (1 << 27) 174 175 // When set, disallow to connect to a HTTP/2 proxy. 176 #define NS_HTTP_DISALLOW_HTTP2_PROXY (1 << 28) 177 178 // When set, setup TLS tunnel even when HTTP proxy is used. 179 // Need to be used together with NS_HTTP_CONNECT_ONLY 180 #define NS_HTTP_TLS_TUNNEL (1 << 29) 181 182 #define NS_HTTP_TRR_FLAGS_FROM_MODE(x) ((static_cast<uint32_t>(x) & 3) << 19) 183 184 #define NS_HTTP_TRR_MODE_FROM_FLAGS(x) \ 185 (static_cast<nsIRequest::TRRMode>((((x) & NS_HTTP_TRR_MODE_MASK) >> 19) & 3)) 186 187 //----------------------------------------------------------------------------- 188 // some default values 189 //----------------------------------------------------------------------------- 190 191 #define NS_HTTP_DEFAULT_PORT 80 192 #define NS_HTTPS_DEFAULT_PORT 443 193 194 #define NS_HTTP_HEADER_SEP ',' 195 196 //----------------------------------------------------------------------------- 197 // http atoms... 198 //----------------------------------------------------------------------------- 199 200 struct nsHttpAtom; 201 struct nsHttpAtomLiteral; 202 203 namespace nsHttp { 204 [[nodiscard]] nsresult CreateAtomTable(); 205 void DestroyAtomTable(); 206 207 // will dynamically add atoms to the table if they don't already exist 208 nsHttpAtom ResolveAtom(const nsACString& s); 209 210 // returns true if the specified token [start,end) is valid per RFC 2616 211 // section 2.2 212 bool IsValidToken(const char* start, const char* end); 213 214 inline bool IsValidToken(const nsACString& s) { 215 return IsValidToken(s.BeginReading(), s.EndReading()); 216 } 217 218 // Strip the leading or trailing HTTP whitespace per fetch spec section 2.2. 219 void TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest); 220 221 // Returns true if the specified value is reasonable given the defintion 222 // in RFC 2616 section 4.2. Full strict validation is not performed 223 // currently as it would require full parsing of the value. 224 bool IsReasonableHeaderValue(const nsACString& s); 225 226 // find the first instance (case-insensitive comparison) of the given 227 // |token| in the |input| string. the |token| is bounded by elements of 228 // |separators| and may appear at the beginning or end of the |input| 229 // string. null is returned if the |token| is not found. |input| may be 230 // null, in which case null is returned. 231 const char* FindToken(const char* input, const char* token, const char* seps); 232 233 // This function parses a string containing a decimal-valued, non-negative 234 // 64-bit integer. If the value would exceed INT64_MAX, then false is 235 // returned. Otherwise, this function returns true and stores the 236 // parsed value in |result|. The next unparsed character in |input| is 237 // optionally returned via |next| if |next| is non-null. 238 // 239 // TODO(darin): Replace this with something generic. 240 // 241 [[nodiscard]] bool ParseInt64(const char* input, const char** next, 242 int64_t* result); 243 244 // Variant on ParseInt64 that expects the input string to contain nothing 245 // more than the value being parsed. 246 [[nodiscard]] inline bool ParseInt64(const char* input, int64_t* result) { 247 const char* next; 248 return ParseInt64(input, &next, result) && *next == '\0'; 249 } 250 251 // Return whether the HTTP status code represents a permanent redirect 252 bool IsPermanentRedirect(uint32_t httpStatus); 253 254 // Returns the APLN token which represents the used protocol version. 255 const char* GetProtocolVersion(HttpVersion pv); 256 257 bool ValidationRequired(bool isForcedValid, 258 nsHttpResponseHead* cachedResponseHead, 259 uint32_t loadFlags, bool allowStaleCacheContent, 260 bool forceValidateCacheContent, bool isImmutable, 261 bool customConditionalRequest, 262 nsHttpRequestHead& requestHead, nsICacheEntry* entry, 263 CacheControlParser& cacheControlRequest, 264 bool fromPreviousSession, 265 bool* performBackgroundRevalidation = nullptr); 266 267 nsresult GetHttpResponseHeadFromCacheEntry( 268 nsICacheEntry* entry, nsHttpResponseHead* cachedResponseHead); 269 270 nsresult CheckPartial(nsICacheEntry* aEntry, int64_t* aSize, 271 int64_t* aContentLength, 272 nsHttpResponseHead* responseHead); 273 274 void DetermineFramingAndImmutability(nsICacheEntry* entry, 275 nsHttpResponseHead* cachedResponseHead, 276 bool isHttps, bool* weaklyFramed, 277 bool* isImmutable); 278 279 // Called when an optimization feature affecting active vs background tab load 280 // took place. Called only on the parent process and only updates 281 // mLastActiveTabLoadOptimizationHit timestamp to now. 282 void NotifyActiveTabLoadOptimization(); 283 TimeStamp GetLastActiveTabLoadOptimizationHit(); 284 void SetLastActiveTabLoadOptimizationHit(TimeStamp const& when); 285 bool IsBeforeLastActiveTabLoadOptimization(TimeStamp const& when); 286 287 nsCString ConvertRequestHeadToString(nsHttpRequestHead& aRequestHead, 288 bool aHasRequestBody, 289 bool aRequestBodyHasHeaders, 290 bool aUsingConnect); 291 292 template <typename T> 293 using SendFunc = std::function<bool(const T&, uint64_t, uint32_t)>; 294 295 template <typename T> 296 bool SendDataInChunks(const nsCString& aData, uint64_t aOffset, uint32_t aCount, 297 const SendFunc<T>& aSendFunc) { 298 static uint32_t const kCopyChunkSize = 128 * 1024; 299 uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize); 300 301 uint32_t start = 0; 302 while (aCount) { 303 T data(Substring(aData, start, toRead)); 304 305 if (!aSendFunc(data, aOffset, toRead)) { 306 return false; 307 } 308 309 aOffset += toRead; 310 start += toRead; 311 aCount -= toRead; 312 toRead = std::min<uint32_t>(aCount, kCopyChunkSize); 313 } 314 315 return true; 316 } 317 318 } // namespace nsHttp 319 320 struct nsHttpAtomLiteral; 321 struct nsHttpAtom { 322 nsHttpAtom() = default; 323 nsHttpAtom(const nsHttpAtom& other) = default; 324 325 explicit operator bool() const { return !_val.IsEmpty(); } 326 327 const char* get() const { 328 if (_val.IsEmpty()) { 329 return nullptr; 330 } 331 return _val.BeginReading(); 332 } 333 334 const nsCString& val() const { return _val; } 335 336 void operator=(const nsHttpAtom& a) { _val = a._val; } 337 338 // This constructor is mainly used to build the static atom list 339 // Avoid using it for anything else. 340 explicit nsHttpAtom(const nsACString& val) : _val(val) {} 341 342 private: 343 nsCString _val; 344 friend nsHttpAtom nsHttp::ResolveAtom(const nsACString& s); 345 }; 346 347 struct nsHttpAtomLiteral { 348 const char* get() const { return _data.get(); } 349 nsLiteralCString const& val() const { return _data; } 350 351 template <size_t N> 352 constexpr explicit nsHttpAtomLiteral(const char (&val)[N]) : _data(val) {} 353 354 operator nsHttpAtom() const { return nsHttpAtom(_data); } 355 356 private: 357 nsLiteralCString _data; 358 }; 359 360 inline bool operator==(nsHttpAtomLiteral const& self, 361 nsHttpAtomLiteral const& other) { 362 return self.get() == other.get(); 363 } 364 inline bool operator!=(nsHttpAtomLiteral const& self, 365 nsHttpAtomLiteral const& other) { 366 return self.get() != other.get(); 367 } 368 369 inline bool operator==(nsHttpAtom const& self, nsHttpAtomLiteral const& other) { 370 return self.val() == other.val(); 371 } 372 inline bool operator!=(nsHttpAtom const& self, nsHttpAtomLiteral const& other) { 373 return self.val() != other.val(); 374 } 375 376 inline bool operator==(nsHttpAtomLiteral const& self, nsHttpAtom const& other) { 377 return self.val() == other.val(); 378 } 379 inline bool operator!=(nsHttpAtomLiteral const& self, nsHttpAtom const& other) { 380 return self.val() != other.val(); 381 } 382 383 inline bool operator==(nsHttpAtom const& self, nsHttpAtom const& other) { 384 return self.val() == other.val(); 385 } 386 inline bool operator!=(nsHttpAtom const& self, nsHttpAtom const& other) { 387 return self.val() != other.val(); 388 } 389 390 namespace nsHttp { 391 392 // Declare all atoms 393 // 394 // The atom names and values are stored in nsHttpAtomList.h and are brought 395 // to you by the magic of C preprocessing. Add new atoms to nsHttpAtomList 396 // and all support logic will be auto-generated. 397 // 398 #define HTTP_ATOM(_name, _value) \ 399 inline constexpr nsHttpAtomLiteral _name(_value); 400 #include "nsHttpAtomList.h" 401 #undef HTTP_ATOM 402 } // namespace nsHttp 403 404 //----------------------------------------------------------------------------- 405 // utilities... 406 //----------------------------------------------------------------------------- 407 408 static inline uint32_t PRTimeToSeconds(PRTime t_usec) { 409 return uint32_t(t_usec / PR_USEC_PER_SEC); 410 } 411 412 #define NowInSeconds() PRTimeToSeconds(PR_Now()) 413 414 // Round q-value to 2 decimal places; return 2 most significant digits as uint. 415 #define QVAL_TO_UINT(q) ((unsigned int)(((q) + 0.005) * 100.0)) 416 417 #define HTTP_LWS " \t" 418 #define HTTP_HEADER_VALUE_SEPS HTTP_LWS "," 419 420 void EnsureBuffer(UniquePtr<char[]>& buf, uint32_t newSize, uint32_t preserve, 421 uint32_t& objSize); 422 void EnsureBuffer(UniquePtr<uint8_t[]>& buf, uint32_t newSize, 423 uint32_t preserve, uint32_t& objSize); 424 425 // h2=":443"; ma=60; single 426 // results in 3 mValues = {{h2, :443}, {ma, 60}, {single}} 427 428 class ParsedHeaderPair { 429 public: 430 ParsedHeaderPair(const char* name, int32_t nameLen, const char* val, 431 int32_t valLen, bool isQuotedValue); 432 433 ParsedHeaderPair(ParsedHeaderPair const& copy) 434 : mName(copy.mName), 435 mValue(copy.mValue), 436 mUnquotedValue(copy.mUnquotedValue), 437 mIsQuotedValue(copy.mIsQuotedValue) { 438 if (mIsQuotedValue) { 439 mValue.Rebind(mUnquotedValue.BeginReading(), mUnquotedValue.Length()); 440 } 441 } 442 443 nsDependentCSubstring mName; 444 nsDependentCSubstring mValue; 445 446 private: 447 nsCString mUnquotedValue; 448 bool mIsQuotedValue; 449 450 void RemoveQuotedStringEscapes(const char* val, int32_t valLen); 451 }; 452 453 class ParsedHeaderValueList { 454 public: 455 ParsedHeaderValueList(const char* t, uint32_t len, bool allowInvalidValue); 456 nsTArray<ParsedHeaderPair> mValues; 457 458 private: 459 void ParseNameAndValue(const char* input, bool allowInvalidValue); 460 }; 461 462 class ParsedHeaderValueListList { 463 public: 464 // RFC 7231 section 3.2.6 defines the syntax of the header field values. 465 // |allowInvalidValue| indicates whether the rule will be used to check 466 // the input text. 467 // Note that ParsedHeaderValueListList is currently used to parse 468 // Alt-Svc and Server-Timing header. |allowInvalidValue| is set to true 469 // when parsing Alt-Svc for historical reasons. 470 explicit ParsedHeaderValueListList(const nsCString& fullHeader, 471 bool allowInvalidValue = true); 472 nsTArray<ParsedHeaderValueList> mValues; 473 474 private: 475 nsCString mFull; 476 }; 477 478 void LogHeaders(const char* lineStart); 479 480 // Convert HTTP response codes returned by a proxy to nsresult. 481 // This function should be only used when we get a failed response to the 482 // CONNECT method. 483 nsresult HttpProxyResponseToErrorCode(uint32_t aStatusCode); 484 485 // Convert an alpn string to SupportedAlpnType. 486 SupportedAlpnRank IsAlpnSupported(const nsACString& aAlpn); 487 488 // Keep this list in sync with the error mapping in 489 // neqo_glue/src/lib.rs::into_nsresult(). These are the network/NSS errors for 490 // which we allow a transaction to retry. 491 static inline bool AllowedErrorForTransactionRetry(nsresult aError) { 492 return psm::IsNSSErrorCode(-1 * NS_ERROR_GET_CODE(aError)) || 493 aError == NS_ERROR_NET_RESET || 494 aError == NS_ERROR_CONNECTION_REFUSED || 495 aError == NS_ERROR_UNKNOWN_HOST || aError == NS_ERROR_NET_TIMEOUT || 496 aError == NS_ERROR_NOT_CONNECTED || 497 aError == NS_ERROR_SOCKET_ADDRESS_IN_USE || 498 aError == NS_ERROR_FILE_ALREADY_EXISTS || 499 aError == NS_ERROR_NET_INTERRUPT; 500 } 501 502 [[nodiscard]] nsresult MakeOriginURL(const nsACString& origin, 503 nsCOMPtr<nsIURI>& url); 504 505 [[nodiscard]] nsresult MakeOriginURL(const nsACString& scheme, 506 const nsACString& origin, 507 nsCOMPtr<nsIURI>& url); 508 509 void CreatePushHashKey(const nsCString& scheme, const nsCString& hostHeader, 510 const mozilla::OriginAttributes& originAttributes, 511 uint64_t serial, const nsACString& pathInfo, 512 nsCString& outOrigin, nsCString& outKey); 513 514 nsresult GetNSResultFromWebTransportError(uint8_t aErrorCode); 515 516 uint8_t GetWebTransportErrorFromNSResult(nsresult aResult); 517 518 uint64_t WebTransportErrorToHttp3Error(uint8_t aErrorCode); 519 520 uint8_t Http3ErrorToWebTransportError(uint64_t aErrorCode); 521 522 bool PossibleZeroRTTRetryError(nsresult aReason); 523 524 void DisallowHTTPSRR(uint32_t& aCaps); 525 526 nsLiteralCString HttpVersionToTelemetryLabel(HttpVersion version); 527 528 enum class ProxyDNSStrategy : uint8_t { 529 // To resolve the origin of the end server we are connecting 530 // to. 531 ORIGIN = 1 << 0, 532 // To resolve the host name of the proxy. 533 PROXY = 1 << 1 534 }; 535 536 ProxyDNSStrategy GetProxyDNSStrategyHelper(const char* aType, uint32_t aFlag); 537 538 } // namespace net 539 } // namespace mozilla 540 541 #endif // nsHttp_h__