LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttp.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 17 341 5.0 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim:set ts=4 sw=4 sts=4 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             : // HttpLog.h should generally be included first
       8             : #include "HttpLog.h"
       9             : 
      10             : #include "nsHttp.h"
      11             : #include "CacheControlParser.h"
      12             : #include "PLDHashTable.h"
      13             : #include "mozilla/Mutex.h"
      14             : #include "mozilla/HashFunctions.h"
      15             : #include "nsCRT.h"
      16             : #include "nsHttpRequestHead.h"
      17             : #include "nsHttpResponseHead.h"
      18             : #include "nsHttpHandler.h"
      19             : #include "nsICacheEntry.h"
      20             : #include "nsIRequest.h"
      21             : #include <errno.h>
      22             : #include <functional>
      23             : 
      24             : namespace mozilla {
      25             : namespace net {
      26             : 
      27             : // define storage for all atoms
      28             : namespace nsHttp {
      29             : #define HTTP_ATOM(_name, _value) nsHttpAtom _name = { _value };
      30             : #include "nsHttpAtomList.h"
      31             : #undef HTTP_ATOM
      32             : }
      33             : 
      34             : // find out how many atoms we have
      35             : #define HTTP_ATOM(_name, _value) Unused_ ## _name,
      36             : enum {
      37             : #include "nsHttpAtomList.h"
      38             :     NUM_HTTP_ATOMS
      39             : };
      40             : #undef HTTP_ATOM
      41             : 
      42             : // we keep a linked list of atoms allocated on the heap for easy clean up when
      43             : // the atom table is destroyed.  The structure and value string are allocated
      44             : // as one contiguous block.
      45             : 
      46             : struct HttpHeapAtom {
      47             :     struct HttpHeapAtom *next;
      48             :     char                 value[1];
      49             : };
      50             : 
      51             : static PLDHashTable        *sAtomTable;
      52             : static struct HttpHeapAtom *sHeapAtoms = nullptr;
      53             : static Mutex               *sLock = nullptr;
      54             : 
      55             : HttpHeapAtom *
      56           0 : NewHeapAtom(const char *value) {
      57           0 :     int len = strlen(value);
      58             : 
      59             :     HttpHeapAtom *a =
      60           0 :         reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
      61           0 :     if (!a)
      62             :         return nullptr;
      63           0 :     memcpy(a->value, value, len + 1);
      64             : 
      65             :     // add this heap atom to the list of all heap atoms
      66           0 :     a->next = sHeapAtoms;
      67           0 :     sHeapAtoms = a;
      68             : 
      69           0 :     return a;
      70             : }
      71             : 
      72             : // Hash string ignore case, based on PL_HashString
      73             : static PLDHashNumber
      74           0 : StringHash(const void *key)
      75             : {
      76           0 :     PLDHashNumber h = 0;
      77           0 :     for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
      78           0 :         h = AddToHash(h, nsCRT::ToLower(*s));
      79           0 :     return h;
      80             : }
      81             : 
      82             : static bool
      83           0 : StringCompare(const PLDHashEntryHdr *entry, const void *testKey)
      84             : {
      85             :     const void *entryKey =
      86           0 :             reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
      87             : 
      88           0 :     return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
      89           0 :                          reinterpret_cast<const char *>(testKey)) == 0;
      90             : }
      91             : 
      92             : static const PLDHashTableOps ops = {
      93             :     StringHash,
      94             :     StringCompare,
      95             :     PLDHashTable::MoveEntryStub,
      96             :     PLDHashTable::ClearEntryStub,
      97             :     nullptr
      98             : };
      99             : 
     100             : // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
     101             : namespace nsHttp {
     102             : nsresult
     103           0 : CreateAtomTable()
     104             : {
     105           0 :     MOZ_ASSERT(!sAtomTable, "atom table already initialized");
     106             : 
     107           0 :     if (!sLock) {
     108           0 :         sLock = new Mutex("nsHttp.sLock");
     109             :     }
     110             : 
     111             :     // The initial length for this table is a value greater than the number of
     112             :     // known atoms (NUM_HTTP_ATOMS) because we expect to encounter a few random
     113             :     // headers right off the bat.
     114           0 :     sAtomTable = new PLDHashTable(&ops, sizeof(PLDHashEntryStub),
     115           0 :                                   NUM_HTTP_ATOMS + 10);
     116             : 
     117             :     // fill the table with our known atoms
     118             :     const char *const atoms[] = {
     119             : #define HTTP_ATOM(_name, _value) _name._val,
     120             : #include "nsHttpAtomList.h"
     121             : #undef HTTP_ATOM
     122             :         nullptr
     123           0 :     };
     124             : 
     125           0 :     for (int i = 0; atoms[i]; ++i) {
     126             :         auto stub = static_cast<PLDHashEntryStub*>
     127           0 :                                (sAtomTable->Add(atoms[i], fallible));
     128           0 :         if (!stub)
     129             :             return NS_ERROR_OUT_OF_MEMORY;
     130             : 
     131           0 :         MOZ_ASSERT(!stub->key, "duplicate static atom");
     132           0 :         stub->key = atoms[i];
     133             :     }
     134             : 
     135             :     return NS_OK;
     136             : }
     137             : 
     138             : void
     139           0 : DestroyAtomTable()
     140             : {
     141           0 :     delete sAtomTable;
     142           0 :     sAtomTable = nullptr;
     143             : 
     144           0 :     while (sHeapAtoms) {
     145           0 :         HttpHeapAtom *next = sHeapAtoms->next;
     146           0 :         free(sHeapAtoms);
     147           0 :         sHeapAtoms = next;
     148             :     }
     149             : 
     150           0 :     delete sLock;
     151           0 :     sLock = nullptr;
     152           0 : }
     153             : 
     154             : Mutex *
     155           0 : GetLock()
     156             : {
     157           0 :     return sLock;
     158             : }
     159             : 
     160             : // this function may be called from multiple threads
     161             : nsHttpAtom
     162           0 : ResolveAtom(const char *str)
     163             : {
     164           0 :     nsHttpAtom atom = { nullptr };
     165             : 
     166           0 :     if (!str || !sAtomTable)
     167           0 :         return atom;
     168             : 
     169           0 :     MutexAutoLock lock(*sLock);
     170             : 
     171           0 :     auto stub = static_cast<PLDHashEntryStub*>(sAtomTable->Add(str, fallible));
     172           0 :     if (!stub)
     173           0 :         return atom;  // out of memory
     174             : 
     175           0 :     if (stub->key) {
     176           0 :         atom._val = reinterpret_cast<const char *>(stub->key);
     177           0 :         return atom;
     178             :     }
     179             : 
     180             :     // if the atom could not be found in the atom table, then we'll go
     181             :     // and allocate a new atom on the heap.
     182           0 :     HttpHeapAtom *heapAtom = NewHeapAtom(str);
     183           0 :     if (!heapAtom)
     184           0 :         return atom;  // out of memory
     185             : 
     186           0 :     stub->key = atom._val = heapAtom->value;
     187           0 :     return atom;
     188             : }
     189             : 
     190             : //
     191             : // From section 2.2 of RFC 2616, a token is defined as:
     192             : //
     193             : //   token          = 1*<any CHAR except CTLs or separators>
     194             : //   CHAR           = <any US-ASCII character (octets 0 - 127)>
     195             : //   separators     = "(" | ")" | "<" | ">" | "@"
     196             : //                  | "," | ";" | ":" | "\" | <">
     197             : //                  | "/" | "[" | "]" | "?" | "="
     198             : //                  | "{" | "}" | SP | HT
     199             : //   CTL            = <any US-ASCII control character
     200             : //                    (octets 0 - 31) and DEL (127)>
     201             : //   SP             = <US-ASCII SP, space (32)>
     202             : //   HT             = <US-ASCII HT, horizontal-tab (9)>
     203             : //
     204             : static const char kValidTokenMap[128] = {
     205             :     0, 0, 0, 0, 0, 0, 0, 0, //   0
     206             :     0, 0, 0, 0, 0, 0, 0, 0, //   8
     207             :     0, 0, 0, 0, 0, 0, 0, 0, //  16
     208             :     0, 0, 0, 0, 0, 0, 0, 0, //  24
     209             : 
     210             :     0, 1, 0, 1, 1, 1, 1, 1, //  32
     211             :     0, 0, 1, 1, 0, 1, 1, 0, //  40
     212             :     1, 1, 1, 1, 1, 1, 1, 1, //  48
     213             :     1, 1, 0, 0, 0, 0, 0, 0, //  56
     214             : 
     215             :     0, 1, 1, 1, 1, 1, 1, 1, //  64
     216             :     1, 1, 1, 1, 1, 1, 1, 1, //  72
     217             :     1, 1, 1, 1, 1, 1, 1, 1, //  80
     218             :     1, 1, 1, 0, 0, 0, 1, 1, //  88
     219             : 
     220             :     1, 1, 1, 1, 1, 1, 1, 1, //  96
     221             :     1, 1, 1, 1, 1, 1, 1, 1, // 104
     222             :     1, 1, 1, 1, 1, 1, 1, 1, // 112
     223             :     1, 1, 1, 0, 1, 0, 1, 0  // 120
     224             : };
     225             : bool
     226           0 : IsValidToken(const char *start, const char *end)
     227             : {
     228           0 :     if (start == end)
     229             :         return false;
     230             : 
     231           0 :     for (; start != end; ++start) {
     232           0 :         const unsigned char idx = *start;
     233           0 :         if (idx > 127 || !kValidTokenMap[idx])
     234             :             return false;
     235             :     }
     236             : 
     237             :     return true;
     238             : }
     239             : 
     240             : const char*
     241           0 : GetProtocolVersion(HttpVersion pv)
     242             : {
     243           0 :     switch (pv) {
     244             :     case HttpVersion::v2_0:
     245             :         return "h2";
     246             :     case HttpVersion::v1_0:
     247           0 :         return "http/1.0";
     248             :     case HttpVersion::v1_1:
     249           0 :         return "http/1.1";
     250             :     default:
     251           0 :         NS_WARNING(nsPrintfCString("Unkown protocol version: 0x%X. "
     252           0 :                                    "Please file a bug", static_cast<uint32_t>(pv)).get());
     253           0 :         return "http/1.1";
     254             :     }
     255             : }
     256             : 
     257             : // static
     258             : void
     259          79 : TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest)
     260             : {
     261         158 :   nsAutoCString str(aSource);
     262             : 
     263             :   // HTTP whitespace 0x09: '\t', 0x0A: '\n', 0x0D: '\r', 0x20: ' '
     264             :   static const char kHTTPWhitespace[] = "\t\n\r ";
     265          79 :   str.Trim(kHTTPWhitespace);
     266           0 :   aDest.Assign(str);
     267           0 : }
     268             : 
     269             : // static
     270             : bool
     271         127 : IsReasonableHeaderValue(const nsACString &s)
     272             : {
     273             :   // Header values MUST NOT contain line-breaks.  RFC 2616 technically
     274             :   // permits CTL characters, including CR and LF, in header values provided
     275             :   // they are quoted.  However, this can lead to problems if servers do not
     276             :   // interpret quoted strings properly.  Disallowing CR and LF here seems
     277             :   // reasonable and keeps things simple.  We also disallow a null byte.
     278         254 :   const nsACString::char_type* end = s.EndReading();
     279           0 :   for (const nsACString::char_type* i = s.BeginReading(); i != end; ++i) {
     280           0 :     if (*i == '\r' || *i == '\n' || *i == '\0') {
     281             :       return false;
     282             :     }
     283             :   }
     284             :   return true;
     285             : }
     286             : 
     287             : const char *
     288          24 : FindToken(const char *input, const char *token, const char *seps)
     289             : {
     290          24 :     if (!input)
     291             :         return nullptr;
     292             : 
     293          15 :     int inputLen = strlen(input);
     294           0 :     int tokenLen = strlen(token);
     295             : 
     296          15 :     if (inputLen < tokenLen)
     297             :         return nullptr;
     298             : 
     299          15 :     const char *inputTop = input;
     300           0 :     const char *inputEnd = input + inputLen - tokenLen;
     301           0 :     for (; input <= inputEnd; ++input) {
     302           0 :         if (PL_strncasecmp(input, token, tokenLen) == 0) {
     303           0 :             if (input > inputTop && !strchr(seps, *(input - 1)))
     304             :                 continue;
     305           7 :             if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
     306             :                 continue;
     307             :             return input;
     308             :         }
     309             :     }
     310             : 
     311             :     return nullptr;
     312             : }
     313             : 
     314             : bool
     315           2 : ParseInt64(const char *input, const char **next, int64_t *r)
     316             : {
     317           2 :     MOZ_ASSERT(input);
     318           0 :     MOZ_ASSERT(r);
     319             : 
     320           2 :     char *end = nullptr;
     321           0 :     errno = 0; // Clear errno to make sure its value is set by strtoll
     322           0 :     int64_t value = strtoll(input, &end, /* base */ 10);
     323             : 
     324             :     // Fail if: - the parsed number overflows.
     325             :     //          - the end points to the start of the input string.
     326             :     //          - we parsed a negative value. Consumers don't expect that.
     327           2 :     if (errno != 0 || end == input || value < 0) {
     328           0 :         LOG(("nsHttp::ParseInt64 value=%" PRId64 " errno=%d", value, errno));
     329             :         return false;
     330             :     }
     331             : 
     332           2 :     if (next) {
     333           0 :         *next = end;
     334             :     }
     335           2 :     *r = value;
     336           0 :     return true;
     337             : }
     338             : 
     339             : bool
     340           0 : IsPermanentRedirect(uint32_t httpStatus)
     341             : {
     342           0 :   return httpStatus == 301 || httpStatus == 308;
     343             : }
     344             : 
     345             : bool
     346           0 : ValidationRequired(bool isForcedValid, nsHttpResponseHead *cachedResponseHead,
     347             :                    uint32_t loadFlags, bool allowStaleCacheContent,
     348             :                    bool isImmutable, bool customConditionalRequest,
     349             :                    nsHttpRequestHead &requestHead,
     350             :                    nsICacheEntry *entry, CacheControlParser &cacheControlRequest,
     351             :                    bool fromPreviousSession)
     352             : {
     353             :     // Check isForcedValid to see if it is possible to skip validation.
     354             :     // Don't skip validation if we have serious reason to believe that this
     355             :     // content is invalid (it's expired).
     356             :     // See netwerk/cache2/nsICacheEntry.idl for details
     357           0 :     if (isForcedValid &&
     358           0 :         (!cachedResponseHead->ExpiresInPast() ||
     359           0 :          !cachedResponseHead->MustValidateIfExpired())) {
     360           0 :         LOG(("NOT validating based on isForcedValid being true.\n"));
     361             :         return false;
     362             :     }
     363             : 
     364             :     // If the LOAD_FROM_CACHE flag is set, any cached data can simply be used
     365           0 :     if (loadFlags & nsIRequest::LOAD_FROM_CACHE || allowStaleCacheContent) {
     366           0 :         LOG(("NOT validating based on LOAD_FROM_CACHE load flag\n"));
     367             :         return false;
     368             :     }
     369             : 
     370             :     // If the VALIDATE_ALWAYS flag is set, any cached data won't be used until
     371             :     // it's revalidated with the server.
     372           0 :     if ((loadFlags & nsIRequest::VALIDATE_ALWAYS) && !isImmutable) {
     373           0 :         LOG(("Validating based on VALIDATE_ALWAYS load flag\n"));
     374             :         return true;
     375             :     }
     376             : 
     377             :     // Even if the VALIDATE_NEVER flag is set, there are still some cases in
     378             :     // which we must validate the cached response with the server.
     379           0 :     if (loadFlags & nsIRequest::VALIDATE_NEVER) {
     380           0 :         LOG(("VALIDATE_NEVER set\n"));
     381             :         // if no-store validate cached response (see bug 112564)
     382           0 :         if (cachedResponseHead->NoStore()) {
     383           0 :             LOG(("Validating based on no-store logic\n"));
     384             :             return true;
     385             :         }
     386           0 :         LOG(("NOT validating based on VALIDATE_NEVER load flag\n"));
     387             :         return false;
     388             :     }
     389             : 
     390             :     // check if validation is strictly required...
     391           0 :     if (cachedResponseHead->MustValidate()) {
     392           0 :         LOG(("Validating based on MustValidate() returning TRUE\n"));
     393             :         return true;
     394             :     }
     395             : 
     396             :     // possibly serve from cache for a custom If-Match/If-Unmodified-Since
     397             :     // conditional request
     398           0 :     if (customConditionalRequest &&
     399           0 :         !requestHead.HasHeader(nsHttp::If_Match) &&
     400           0 :         !requestHead.HasHeader(nsHttp::If_Unmodified_Since)) {
     401           0 :         LOG(("Validating based on a custom conditional request\n"));
     402             :         return true;
     403             :     }
     404             : 
     405             :     // previously we also checked for a query-url w/out expiration
     406             :     // and didn't do heuristic on it. but defacto that is allowed now.
     407             :     //
     408             :     // Check if the cache entry has expired...
     409             : 
     410           0 :     bool doValidation = true;
     411           0 :     uint32_t now = NowInSeconds();
     412             : 
     413           0 :     uint32_t age = 0;
     414           0 :     nsresult rv = cachedResponseHead->ComputeCurrentAge(now, now, &age);
     415           0 :     if (NS_FAILED(rv)) {
     416             :         return true;
     417             :     }
     418             : 
     419           0 :     uint32_t freshness = 0;
     420           0 :     rv = cachedResponseHead->ComputeFreshnessLifetime(&freshness);
     421           0 :     if (NS_FAILED(rv)) {
     422             :         return true;
     423             :     }
     424             : 
     425           0 :     uint32_t expiration = 0;
     426           0 :     rv = entry->GetExpirationTime(&expiration);
     427           0 :     if (NS_FAILED(rv)) {
     428             :         return true;
     429             :     }
     430             : 
     431             :     uint32_t maxAgeRequest, maxStaleRequest, minFreshRequest;
     432             : 
     433           0 :     LOG(("  NowInSeconds()=%u, expiration time=%u, freshness lifetime=%u, age=%u",
     434             :             now, expiration, freshness, age));
     435             : 
     436           0 :     if (cacheControlRequest.NoCache()) {
     437           0 :         LOG(("  validating, no-cache request"));
     438             :         doValidation = true;
     439           0 :     } else if (cacheControlRequest.MaxStale(&maxStaleRequest)) {
     440           0 :         uint32_t staleTime = age > freshness ? age - freshness : 0;
     441           0 :         doValidation = staleTime > maxStaleRequest;
     442           0 :         LOG(("  validating=%d, max-stale=%u requested", doValidation, maxStaleRequest));
     443           0 :     } else if (cacheControlRequest.MaxAge(&maxAgeRequest)) {
     444             :         // The input information for age and freshness calculation are in seconds.
     445             :         // Hence, the internal logic can't have better resolution than seconds too.
     446             :         // To make max-age=0 case work even for requests made in less than a second
     447             :         // after the last response has been received, we use >= for compare.  This
     448             :         // is correct because of the rounding down of the age calculated value.
     449           0 :         doValidation = age >= maxAgeRequest;
     450           0 :         LOG(("  validating=%d, max-age=%u requested", doValidation, maxAgeRequest));
     451           0 :     } else if (cacheControlRequest.MinFresh(&minFreshRequest)) {
     452           0 :         uint32_t freshTime = freshness > age ? freshness - age : 0;
     453           0 :         doValidation = freshTime < minFreshRequest;
     454           0 :         LOG(("  validating=%d, min-fresh=%u requested", doValidation, minFreshRequest));
     455           0 :     } else if (now < expiration) {
     456           0 :         doValidation = false;
     457           0 :         LOG(("  not validating, expire time not in the past"));
     458           0 :     } else if (cachedResponseHead->MustValidateIfExpired()) {
     459             :         doValidation = true;
     460           0 :     } else if (loadFlags & nsIRequest::VALIDATE_ONCE_PER_SESSION) {
     461             :         // If the cached response does not include expiration infor-
     462             :         // mation, then we must validate the response, despite whether
     463             :         // or not this is the first access this session.  This behavior
     464             :         // is consistent with existing browsers and is generally expected
     465             :         // by web authors.
     466           0 :         if (freshness == 0)
     467             :             doValidation = true;
     468             :         else
     469           0 :             doValidation = fromPreviousSession;
     470             :     } else {
     471             :         doValidation = true;
     472             :     }
     473             : 
     474           0 :     LOG(("%salidating based on expiration time\n", doValidation ? "V" : "Not v"));
     475             :     return doValidation;
     476             : }
     477             : 
     478             : nsresult
     479           0 : GetHttpResponseHeadFromCacheEntry(nsICacheEntry *entry, nsHttpResponseHead *cachedResponseHead)
     480             : {
     481           0 :     nsCString buf;
     482             :     // A "original-response-headers" metadata element holds network original headers,
     483             :     // i.e. the headers in the form as they arrieved from the network.
     484             :     // We need to get the network original headers first, because we need to keep them
     485             :     // in order.
     486           0 :     nsresult rv = entry->GetMetaDataElement("original-response-headers", getter_Copies(buf));
     487           0 :     if (NS_SUCCEEDED(rv)) {
     488           0 :         rv = cachedResponseHead->ParseCachedOriginalHeaders((char *) buf.get());
     489           0 :         if (NS_FAILED(rv)) {
     490           0 :             LOG(("  failed to parse original-response-headers\n"));
     491             :         }
     492             :     }
     493             : 
     494           0 :     buf.Adopt(nullptr);
     495             :     // A "response-head" metadata element holds response head, e.g. response status
     496             :     // line and headers in the form Firefox uses them internally (no dupicate
     497             :     // headers, etc.).
     498           0 :     rv = entry->GetMetaDataElement("response-head", getter_Copies(buf));
     499           0 :     NS_ENSURE_SUCCESS(rv, rv);
     500             : 
     501             :     // Parse string stored in a "response-head" metadata element.
     502             :     // These response headers will be merged with the orignal headers (i.e. the
     503             :     // headers stored in a "original-response-headers" metadata element).
     504           0 :     rv = cachedResponseHead->ParseCachedHead(buf.get());
     505           0 :     NS_ENSURE_SUCCESS(rv, rv);
     506           0 :     buf.Adopt(nullptr);
     507             : 
     508           0 :     return NS_OK;
     509             : }
     510             : 
     511             : nsresult
     512           0 : CheckPartial(nsICacheEntry* aEntry, int64_t *aSize, int64_t *aContentLength,
     513             :              nsHttpResponseHead *responseHead)
     514             : {
     515             :     nsresult rv;
     516             : 
     517           0 :     rv = aEntry->GetDataSize(aSize);
     518             : 
     519           0 :     if (NS_ERROR_IN_PROGRESS == rv) {
     520           0 :         *aSize = -1;
     521           0 :         rv = NS_OK;
     522             :     }
     523             : 
     524           0 :     NS_ENSURE_SUCCESS(rv, rv);
     525             : 
     526           0 :     if (!responseHead) {
     527             :         return NS_ERROR_UNEXPECTED;
     528             :     }
     529             : 
     530           0 :     *aContentLength = responseHead->ContentLength();
     531             : 
     532           0 :     return NS_OK;
     533             : }
     534             : 
     535             : void
     536           0 : DetermineFramingAndImmutability(nsICacheEntry *entry,
     537             :         nsHttpResponseHead *responseHead, bool isHttps,
     538             :         bool *weaklyFramed, bool *isImmutable)
     539             : {
     540           0 :     nsCString framedBuf;
     541           0 :     nsresult rv = entry->GetMetaDataElement("strongly-framed", getter_Copies(framedBuf));
     542             :     // describe this in terms of explicitly weakly framed so as to be backwards
     543             :     // compatible with old cache contents which dont have strongly-framed makers
     544           0 :     *weaklyFramed = NS_SUCCEEDED(rv) && framedBuf.EqualsLiteral("0");
     545           0 :     *isImmutable = !*weaklyFramed && isHttps && responseHead->Immutable();
     546           0 : }
     547             : 
     548             : bool
     549           0 : IsBeforeLastActiveTabLoadOptimization(TimeStamp const & when)
     550             : {
     551           0 :   return gHttpHandler && gHttpHandler->IsBeforeLastActiveTabLoadOptimization(when);
     552             : }
     553             : 
     554             : void
     555           0 : NotifyActiveTabLoadOptimization()
     556             : {
     557           0 :   if (gHttpHandler) {
     558           0 :     gHttpHandler->NotifyActiveTabLoadOptimization();
     559             :   }
     560           0 : }
     561             : 
     562           0 : TimeStamp const GetLastActiveTabLoadOptimizationHit()
     563             : {
     564           0 :   return gHttpHandler ? gHttpHandler->GetLastActiveTabLoadOptimizationHit() : TimeStamp();
     565             : }
     566             : 
     567             : void
     568           0 : SetLastActiveTabLoadOptimizationHit(TimeStamp const &when)
     569             : {
     570           0 :   if (gHttpHandler) {
     571           0 :     gHttpHandler->SetLastActiveTabLoadOptimizationHit(when);
     572             :   }
     573           0 : }
     574             : 
     575             : HttpVersion
     576           0 : GetHttpVersionFromSpdy(SpdyVersion sv)
     577             : {
     578           0 :     MOZ_DIAGNOSTIC_ASSERT(sv != SpdyVersion::NONE);
     579           0 :     MOZ_ASSERT(sv == SpdyVersion::HTTP_2);
     580             : 
     581           0 :     return HttpVersion::v2_0;
     582             : }
     583             : 
     584             : } // namespace nsHttp
     585             : 
     586             : 
     587             : template<typename T> void
     588           0 : localEnsureBuffer(UniquePtr<T[]> &buf, uint32_t newSize,
     589             :              uint32_t preserve, uint32_t &objSize)
     590             : {
     591           0 :   if (objSize >= newSize)
     592           0 :     return;
     593             : 
     594             :   // Leave a little slop on the new allocation - add 2KB to
     595             :   // what we need and then round the result up to a 4KB (page)
     596             :   // boundary.
     597             : 
     598           0 :   objSize = (newSize + 2048 + 4095) & ~4095;
     599             : 
     600             :   static_assert(sizeof(T) == 1, "sizeof(T) must be 1");
     601           0 :   auto tmp = MakeUnique<T[]>(objSize);
     602           0 :   if (preserve) {
     603           0 :     memcpy(tmp.get(), buf.get(), preserve);
     604             :   }
     605           0 :   buf = std::move(tmp);
     606             : }
     607             : 
     608           0 : void EnsureBuffer(UniquePtr<char[]> &buf, uint32_t newSize,
     609             :                   uint32_t preserve, uint32_t &objSize)
     610             : {
     611           0 :     localEnsureBuffer<char> (buf, newSize, preserve, objSize);
     612           0 : }
     613             : 
     614           0 : void EnsureBuffer(UniquePtr<uint8_t[]> &buf, uint32_t newSize,
     615             :                   uint32_t preserve, uint32_t &objSize)
     616             : {
     617           0 :     localEnsureBuffer<uint8_t> (buf, newSize, preserve, objSize);
     618           0 : }
     619             : 
     620             : static bool
     621           0 : IsTokenSymbol(signed char chr) {
     622           0 :   if (chr < 33 || chr == 127 ||
     623           0 :       chr == '(' || chr == ')' || chr == '<' || chr == '>' ||
     624           0 :       chr == '@' || chr == ',' || chr == ';' || chr == ':' ||
     625           0 :       chr == '"' || chr == '/' || chr == '[' || chr == ']' ||
     626           0 :       chr == '?' || chr == '=' || chr == '{' || chr == '}' || chr == '\\') {
     627             :     return false;
     628             :   }
     629           0 :   return true;
     630             : }
     631             : 
     632           0 : ParsedHeaderPair::ParsedHeaderPair(const char *name, int32_t nameLen,
     633             :                                    const char *val, int32_t valLen,
     634           0 :                                    bool isQuotedValue)
     635             :     : mName(nsDependentCSubstring(nullptr, 0u))
     636             :     , mValue(nsDependentCSubstring(nullptr, 0u))
     637           0 :     , mIsQuotedValue(isQuotedValue)
     638             : {
     639           0 :     if (nameLen > 0) {
     640           0 :         mName.Rebind(name, name + nameLen);
     641             :     }
     642           0 :     if (valLen > 0) {
     643           0 :         if (mIsQuotedValue) {
     644           0 :             RemoveQuotedStringEscapes(val, valLen);
     645           0 :             mValue.Rebind(mUnquotedValue.BeginWriting(), mUnquotedValue.Length());
     646             :         } else {
     647           0 :             mValue.Rebind(val, val + valLen);
     648             :         }
     649             :     }
     650           0 : }
     651             : 
     652             : void
     653           0 : ParsedHeaderPair::RemoveQuotedStringEscapes(const char *val, int32_t valLen)
     654             : {
     655           0 :     mUnquotedValue.Truncate();
     656           0 :     const char *c = val;
     657           0 :     for (int32_t i = 0; i < valLen; ++i) {
     658           0 :         if (c[i] == '\\' && c[i + 1]) {
     659           0 :             ++i;
     660             :         }
     661           0 :         mUnquotedValue.Append(c[i]);
     662             :     }
     663           0 : }
     664             : 
     665             : static
     666           0 : void Tokenize(const char *input, uint32_t inputLen, const char token,
     667             :               const std::function<void(const char *, uint32_t)>& consumer)
     668             : {
     669             :     auto trimWhitespace =
     670           0 :         [] (const char *in, uint32_t inLen, const char **out, uint32_t *outLen) {
     671           0 :             *out = in;
     672           0 :             *outLen = inLen;
     673           0 :             if (inLen == 0) {
     674             :                 return;
     675             :             }
     676             : 
     677             :             // Trim leading space
     678           0 :             while (nsCRT::IsAsciiSpace(**out)) {
     679           0 :                 (*out)++;
     680           0 :                 --(*outLen);
     681             :             }
     682             : 
     683             :             // Trim tailing space
     684           0 :             for (const char *i = *out + *outLen - 1; i >= *out; --i) {
     685           0 :                 if (!nsCRT::IsAsciiSpace(*i)) {
     686             :                     break;
     687             :                 }
     688           0 :                 --(*outLen);
     689             :             }
     690             :         };
     691             : 
     692           0 :     const char *first = input;
     693           0 :     bool inQuote = false;
     694           0 :     const char *result = nullptr;
     695           0 :     uint32_t resultLen = 0;
     696           0 :     for (uint32_t index = 0; index < inputLen; ++index) {
     697           0 :         if (inQuote && input[index] == '\\' && input[index + 1]) {
     698             :             index++;
     699             :             continue;
     700             :         }
     701           0 :         if (input[index] == '"') {
     702           0 :             inQuote = !inQuote;
     703           0 :             continue;
     704             :         }
     705           0 :         if (inQuote) {
     706             :             continue;
     707             :         }
     708           0 :         if (input[index] == token) {
     709           0 :             trimWhitespace(first, (input + index) - first,
     710           0 :                            &result, &resultLen);
     711           0 :             consumer(result, resultLen);
     712           0 :             first = input + index + 1;
     713             :         }
     714             :     }
     715             : 
     716           0 :     trimWhitespace(first, (input + inputLen) - first,
     717           0 :                    &result, &resultLen);
     718           0 :     consumer(result, resultLen);
     719           0 : }
     720             : 
     721           0 : ParsedHeaderValueList::ParsedHeaderValueList(const char *t,
     722             :                                              uint32_t len,
     723           0 :                                              bool allowInvalidValue)
     724             : {
     725           0 :     if (!len) {
     726           0 :         return;
     727             :     }
     728             : 
     729           0 :     ParsedHeaderValueList *self = this;
     730           0 :     auto consumer = [=] (const char *output, uint32_t outputLength) {
     731           0 :         self->ParseNameAndValue(output, allowInvalidValue);
     732           0 :     };
     733             : 
     734           0 :     Tokenize(t, len, ';', consumer);
     735             : }
     736             : 
     737             : void
     738           0 : ParsedHeaderValueList::ParseNameAndValue(const char *input, bool allowInvalidValue)
     739             : {
     740           0 :     const char *nameStart = input;
     741           0 :     const char *nameEnd = nullptr;
     742           0 :     const char *valueStart = input;
     743           0 :     const char *valueEnd = nullptr;
     744           0 :     bool isQuotedString = false;
     745           0 :     bool invalidValue = false;
     746             : 
     747           0 :     for (; *input && *input != ';' && *input != ',' &&
     748           0 :            !nsCRT::IsAsciiSpace(*input) && *input != '='; input++)
     749             :         ;
     750             : 
     751           0 :     nameEnd = input;
     752             : 
     753           0 :     if (!(nameEnd - nameStart)) {
     754             :         return;
     755             :     }
     756             : 
     757             :     // Check whether param name is a valid token.
     758           0 :     for (const char *c = nameStart; c < nameEnd; c++) {
     759           0 :         if (!IsTokenSymbol(*c)) {
     760             :             nameEnd = c;
     761             :             break;
     762             :         }
     763             :     }
     764             : 
     765           0 :     if (!(nameEnd - nameStart)) {
     766             :         return;
     767             :     }
     768             : 
     769           0 :     while (nsCRT::IsAsciiSpace(*input)) {
     770           0 :         ++input;
     771             :     }
     772             : 
     773           0 :     if (!*input || *input++ != '=') {
     774           0 :         mValues.AppendElement(ParsedHeaderPair(nameStart, nameEnd - nameStart,
     775           0 :                                                nullptr, 0, false));
     776           0 :         return;
     777             :     }
     778             : 
     779           0 :     while (nsCRT::IsAsciiSpace(*input)) {
     780           0 :         ++input;
     781             :     }
     782             : 
     783           0 :     if (*input != '"') {
     784             :         // The value is a token, not a quoted string.
     785             :         valueStart = input;
     786           0 :         for (valueEnd = input;
     787           0 :              *valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) &&
     788           0 :              *valueEnd != ';' && *valueEnd != ',';
     789             :              valueEnd++)
     790             :           ;
     791           0 :         input = valueEnd;
     792           0 :         if (!allowInvalidValue) {
     793           0 :             for (const char *c = valueStart; c < valueEnd; c++) {
     794           0 :                 if (!IsTokenSymbol(*c)) {
     795             :                     valueEnd = c;
     796             :                     break;
     797             :                 }
     798             :             }
     799             :         }
     800             :     } else {
     801           0 :         bool foundQuotedEnd = false;
     802           0 :         isQuotedString = true;
     803             : 
     804           0 :         ++input;
     805           0 :         valueStart = input;
     806           0 :         for (valueEnd = input; *valueEnd; ++valueEnd) {
     807           0 :             if (*valueEnd == '\\' && *(valueEnd + 1)) {
     808           0 :                 ++valueEnd;
     809             :             }
     810           0 :             else if (*valueEnd == '"') {
     811             :                 foundQuotedEnd = true;
     812             :                 break;
     813             :             }
     814             :         }
     815           0 :         if (!foundQuotedEnd) {
     816           0 :             invalidValue = true;
     817             :         }
     818             : 
     819           0 :         input = valueEnd;
     820             :         // *valueEnd != null means that *valueEnd is quote character.
     821             :         if (*valueEnd) {
     822             :             input++;
     823             :         }
     824             :     }
     825             : 
     826           0 :     if (invalidValue) {
     827           0 :         valueEnd = valueStart;
     828             :     }
     829             : 
     830           0 :     mValues.AppendElement(ParsedHeaderPair(nameStart, nameEnd - nameStart,
     831           0 :                                            valueStart, valueEnd - valueStart,
     832           0 :                                            isQuotedString));
     833             : }
     834             : 
     835           0 : ParsedHeaderValueListList::ParsedHeaderValueListList(const nsCString &fullHeader,
     836           0 :                                                      bool allowInvalidValue)
     837           0 :     : mFull(fullHeader)
     838             : {
     839           0 :     auto &values = mValues;
     840             :     auto consumer =
     841           0 :         [&values, allowInvalidValue] (const char *output, uint32_t outputLength) {
     842           0 :             values.AppendElement(ParsedHeaderValueList(output,
     843             :                                                        outputLength,
     844           0 :                                                        allowInvalidValue));
     845           0 :         };
     846             : 
     847           0 :     Tokenize(mFull.BeginReading(), mFull.Length(), ',', consumer);
     848           0 : }
     849             : 
     850           0 : void LogCallingScriptLocation(void* instance)
     851             : {
     852           0 :     if (!LOG4_ENABLED()) {
     853           0 :         return;
     854             :     }
     855             : 
     856           0 :     JSContext* cx = nsContentUtils::GetCurrentJSContext();
     857           0 :     if (!cx) {
     858             :         return;
     859             :     }
     860             : 
     861             :     nsAutoCString fileNameString;
     862             :     uint32_t line = 0, col = 0;
     863             :     if (!nsJSUtils::GetCallingLocation(cx, fileNameString, &line, &col)) {
     864             :         return;
     865             :     }
     866             : 
     867             :     LOG(("%p called from script: %s:%u:%u", instance, fileNameString.get(), line, col));
     868             : }
     869             : 
     870             : } // namespace net
     871             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952