tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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__