LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttp.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 91 210 43.3 %
Date: 2017-07-14 16:53:18 Functions: 13 21 61.9 %
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 "PLDHashTable.h"
      12             : #include "mozilla/Mutex.h"
      13             : #include "mozilla/HashFunctions.h"
      14             : #include "nsCRT.h"
      15             : #include <errno.h>
      16             : 
      17             : namespace mozilla {
      18             : namespace net {
      19             : 
      20             : // define storage for all atoms
      21             : #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
      22             : #include "nsHttpAtomList.h"
      23             : #undef HTTP_ATOM
      24             : 
      25             : // find out how many atoms we have
      26             : #define HTTP_ATOM(_name, _value) Unused_ ## _name,
      27             : enum {
      28             : #include "nsHttpAtomList.h"
      29             :     NUM_HTTP_ATOMS
      30             : };
      31             : #undef HTTP_ATOM
      32             : 
      33             : // we keep a linked list of atoms allocated on the heap for easy clean up when
      34             : // the atom table is destroyed.  The structure and value string are allocated
      35             : // as one contiguous block.
      36             : 
      37             : struct HttpHeapAtom {
      38             :     struct HttpHeapAtom *next;
      39             :     char                 value[1];
      40             : };
      41             : 
      42             : static PLDHashTable        *sAtomTable;
      43             : static struct HttpHeapAtom *sHeapAtoms = nullptr;
      44             : static Mutex               *sLock = nullptr;
      45             : 
      46             : HttpHeapAtom *
      47          14 : NewHeapAtom(const char *value) {
      48          14 :     int len = strlen(value);
      49             : 
      50             :     HttpHeapAtom *a =
      51          14 :         reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
      52          14 :     if (!a)
      53           0 :         return nullptr;
      54          14 :     memcpy(a->value, value, len + 1);
      55             : 
      56             :     // add this heap atom to the list of all heap atoms
      57          14 :     a->next = sHeapAtoms;
      58          14 :     sHeapAtoms = a;
      59             : 
      60          14 :     return a;
      61             : }
      62             : 
      63             : // Hash string ignore case, based on PL_HashString
      64             : static PLDHashNumber
      65         302 : StringHash(const void *key)
      66             : {
      67         302 :     PLDHashNumber h = 0;
      68        3543 :     for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
      69        3241 :         h = AddToHash(h, nsCRT::ToLower(*s));
      70         302 :     return h;
      71             : }
      72             : 
      73             : static bool
      74         132 : StringCompare(const PLDHashEntryHdr *entry, const void *testKey)
      75             : {
      76             :     const void *entryKey =
      77         132 :             reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
      78             : 
      79         132 :     return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
      80         132 :                          reinterpret_cast<const char *>(testKey)) == 0;
      81             : }
      82             : 
      83             : static const PLDHashTableOps ops = {
      84             :     StringHash,
      85             :     StringCompare,
      86             :     PLDHashTable::MoveEntryStub,
      87             :     PLDHashTable::ClearEntryStub,
      88             :     nullptr
      89             : };
      90             : 
      91             : // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
      92             : nsresult
      93           2 : nsHttp::CreateAtomTable()
      94             : {
      95           2 :     MOZ_ASSERT(!sAtomTable, "atom table already initialized");
      96             : 
      97           2 :     if (!sLock) {
      98           2 :         sLock = new Mutex("nsHttp.sLock");
      99             :     }
     100             : 
     101             :     // The initial length for this table is a value greater than the number of
     102             :     // known atoms (NUM_HTTP_ATOMS) because we expect to encounter a few random
     103             :     // headers right off the bat.
     104           2 :     sAtomTable = new PLDHashTable(&ops, sizeof(PLDHashEntryStub),
     105           2 :                                   NUM_HTTP_ATOMS + 10);
     106             : 
     107             :     // fill the table with our known atoms
     108             :     const char *const atoms[] = {
     109             : #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
     110             : #include "nsHttpAtomList.h"
     111             : #undef HTTP_ATOM
     112             :         nullptr
     113         158 :     };
     114             : 
     115         158 :     for (int i = 0; atoms[i]; ++i) {
     116             :         auto stub = static_cast<PLDHashEntryStub*>
     117         156 :                                (sAtomTable->Add(atoms[i], fallible));
     118         156 :         if (!stub)
     119           0 :             return NS_ERROR_OUT_OF_MEMORY;
     120             : 
     121         156 :         MOZ_ASSERT(!stub->key, "duplicate static atom");
     122         156 :         stub->key = atoms[i];
     123             :     }
     124             : 
     125           2 :     return NS_OK;
     126             : }
     127             : 
     128             : void
     129           0 : nsHttp::DestroyAtomTable()
     130             : {
     131           0 :     delete sAtomTable;
     132           0 :     sAtomTable = nullptr;
     133             : 
     134           0 :     while (sHeapAtoms) {
     135           0 :         HttpHeapAtom *next = sHeapAtoms->next;
     136           0 :         free(sHeapAtoms);
     137           0 :         sHeapAtoms = next;
     138             :     }
     139             : 
     140           0 :     delete sLock;
     141           0 :     sLock = nullptr;
     142           0 : }
     143             : 
     144             : Mutex *
     145           3 : nsHttp::GetLock()
     146             : {
     147           3 :     return sLock;
     148             : }
     149             : 
     150             : // this function may be called from multiple threads
     151             : nsHttpAtom
     152         146 : nsHttp::ResolveAtom(const char *str)
     153             : {
     154         146 :     nsHttpAtom atom = { nullptr };
     155             : 
     156         146 :     if (!str || !sAtomTable)
     157           0 :         return atom;
     158             : 
     159         292 :     MutexAutoLock lock(*sLock);
     160             : 
     161         146 :     auto stub = static_cast<PLDHashEntryStub*>(sAtomTable->Add(str, fallible));
     162         146 :     if (!stub)
     163           0 :         return atom;  // out of memory
     164             : 
     165         146 :     if (stub->key) {
     166         132 :         atom._val = reinterpret_cast<const char *>(stub->key);
     167         132 :         return atom;
     168             :     }
     169             : 
     170             :     // if the atom could not be found in the atom table, then we'll go
     171             :     // and allocate a new atom on the heap.
     172          14 :     HttpHeapAtom *heapAtom = NewHeapAtom(str);
     173          14 :     if (!heapAtom)
     174           0 :         return atom;  // out of memory
     175             : 
     176          14 :     stub->key = atom._val = heapAtom->value;
     177          14 :     return atom;
     178             : }
     179             : 
     180             : //
     181             : // From section 2.2 of RFC 2616, a token is defined as:
     182             : //
     183             : //   token          = 1*<any CHAR except CTLs or separators>
     184             : //   CHAR           = <any US-ASCII character (octets 0 - 127)>
     185             : //   separators     = "(" | ")" | "<" | ">" | "@"
     186             : //                  | "," | ";" | ":" | "\" | <">
     187             : //                  | "/" | "[" | "]" | "?" | "="
     188             : //                  | "{" | "}" | SP | HT
     189             : //   CTL            = <any US-ASCII control character
     190             : //                    (octets 0 - 31) and DEL (127)>
     191             : //   SP             = <US-ASCII SP, space (32)>
     192             : //   HT             = <US-ASCII HT, horizontal-tab (9)>
     193             : //
     194             : static const char kValidTokenMap[128] = {
     195             :     0, 0, 0, 0, 0, 0, 0, 0, //   0
     196             :     0, 0, 0, 0, 0, 0, 0, 0, //   8
     197             :     0, 0, 0, 0, 0, 0, 0, 0, //  16
     198             :     0, 0, 0, 0, 0, 0, 0, 0, //  24
     199             : 
     200             :     0, 1, 0, 1, 1, 1, 1, 1, //  32
     201             :     0, 0, 1, 1, 0, 1, 1, 0, //  40
     202             :     1, 1, 1, 1, 1, 1, 1, 1, //  48
     203             :     1, 1, 0, 0, 0, 0, 0, 0, //  56
     204             : 
     205             :     0, 1, 1, 1, 1, 1, 1, 1, //  64
     206             :     1, 1, 1, 1, 1, 1, 1, 1, //  72
     207             :     1, 1, 1, 1, 1, 1, 1, 1, //  80
     208             :     1, 1, 1, 0, 0, 0, 1, 1, //  88
     209             : 
     210             :     1, 1, 1, 1, 1, 1, 1, 1, //  96
     211             :     1, 1, 1, 1, 1, 1, 1, 1, // 104
     212             :     1, 1, 1, 1, 1, 1, 1, 1, // 112
     213             :     1, 1, 1, 0, 1, 0, 1, 0  // 120
     214             : };
     215             : bool
     216          95 : nsHttp::IsValidToken(const char *start, const char *end)
     217             : {
     218          95 :     if (start == end)
     219           0 :         return false;
     220             : 
     221        1811 :     for (; start != end; ++start) {
     222         858 :         const unsigned char idx = *start;
     223         858 :         if (idx > 127 || !kValidTokenMap[idx])
     224           0 :             return false;
     225             :     }
     226             : 
     227          95 :     return true;
     228             : }
     229             : 
     230             : const char*
     231           3 : nsHttp::GetProtocolVersion(uint32_t pv)
     232             : {
     233           3 :     switch (pv) {
     234             :     case HTTP_VERSION_2:
     235             :     case NS_HTTP_VERSION_2_0:
     236           0 :         return "h2";
     237             :     case NS_HTTP_VERSION_1_0:
     238           3 :         return "http/1.0";
     239             :     case NS_HTTP_VERSION_1_1:
     240           0 :         return "http/1.1";
     241             :     default:
     242           0 :         NS_WARNING(nsPrintfCString("Unkown protocol version: 0x%X. "
     243           0 :                                    "Please file a bug", pv).get());
     244           0 :         return "http/1.1";
     245             :     }
     246             : }
     247             : 
     248             : // static
     249             : void
     250           4 : nsHttp::TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest)
     251             : {
     252           8 :   nsAutoCString str(aSource);
     253             : 
     254             :   // HTTP whitespace 0x09: '\t', 0x0A: '\n', 0x0D: '\r', 0x20: ' '
     255             :   static const char kHTTPWhitespace[] = "\t\n\r ";
     256           4 :   str.Trim(kHTTPWhitespace);
     257           4 :   aDest.Assign(str);
     258           4 : }
     259             : 
     260             : // static
     261             : bool
     262          31 : nsHttp::IsReasonableHeaderValue(const nsACString &s)
     263             : {
     264             :   // Header values MUST NOT contain line-breaks.  RFC 2616 technically
     265             :   // permits CTL characters, including CR and LF, in header values provided
     266             :   // they are quoted.  However, this can lead to problems if servers do not
     267             :   // interpret quoted strings properly.  Disallowing CR and LF here seems
     268             :   // reasonable and keeps things simple.  We also disallow a null byte.
     269          31 :   const nsACString::char_type* end = s.EndReading();
     270         343 :   for (const nsACString::char_type* i = s.BeginReading(); i != end; ++i) {
     271         312 :     if (*i == '\r' || *i == '\n' || *i == '\0') {
     272           0 :       return false;
     273             :     }
     274             :   }
     275          31 :   return true;
     276             : }
     277             : 
     278             : const char *
     279          25 : nsHttp::FindToken(const char *input, const char *token, const char *seps)
     280             : {
     281          25 :     if (!input)
     282          16 :         return nullptr;
     283             : 
     284           9 :     int inputLen = strlen(input);
     285           9 :     int tokenLen = strlen(token);
     286             : 
     287           9 :     if (inputLen < tokenLen)
     288           0 :         return nullptr;
     289             : 
     290           9 :     const char *inputTop = input;
     291           9 :     const char *inputEnd = input + inputLen - tokenLen;
     292          93 :     for (; input <= inputEnd; ++input) {
     293          44 :         if (PL_strncasecmp(input, token, tokenLen) == 0) {
     294           2 :             if (input > inputTop && !strchr(seps, *(input - 1)))
     295           0 :                 continue;
     296           2 :             if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
     297           0 :                 continue;
     298           2 :             return input;
     299             :         }
     300             :     }
     301             : 
     302           7 :     return nullptr;
     303             : }
     304             : 
     305             : bool
     306           4 : nsHttp::ParseInt64(const char *input, const char **next, int64_t *r)
     307             : {
     308           4 :     MOZ_ASSERT(input);
     309           4 :     MOZ_ASSERT(r);
     310             : 
     311           4 :     char *end = nullptr;
     312           4 :     errno = 0; // Clear errno to make sure its value is set by strtoll
     313           4 :     int64_t value = strtoll(input, &end, /* base */ 10);
     314             : 
     315             :     // Fail if: - the parsed number overflows.
     316             :     //          - the end points to the start of the input string.
     317             :     //          - we parsed a negative value. Consumers don't expect that.
     318           4 :     if (errno != 0 || end == input || value < 0) {
     319           0 :         LOG(("nsHttp::ParseInt64 value=%" PRId64 " errno=%d", value, errno));
     320           0 :         return false;
     321             :     }
     322             : 
     323           4 :     if (next) {
     324           4 :         *next = end;
     325             :     }
     326           4 :     *r = value;
     327           4 :     return true;
     328             : }
     329             : 
     330             : bool
     331           3 : nsHttp::IsPermanentRedirect(uint32_t httpStatus)
     332             : {
     333           3 :   return httpStatus == 301 || httpStatus == 308;
     334             : }
     335             : 
     336             : 
     337             : template<typename T> void
     338           0 : localEnsureBuffer(UniquePtr<T[]> &buf, uint32_t newSize,
     339             :              uint32_t preserve, uint32_t &objSize)
     340             : {
     341           0 :   if (objSize >= newSize)
     342           0 :     return;
     343             : 
     344             :   // Leave a little slop on the new allocation - add 2KB to
     345             :   // what we need and then round the result up to a 4KB (page)
     346             :   // boundary.
     347             : 
     348           0 :   objSize = (newSize + 2048 + 4095) & ~4095;
     349             : 
     350             :   static_assert(sizeof(T) == 1, "sizeof(T) must be 1");
     351           0 :   auto tmp = MakeUnique<T[]>(objSize);
     352           0 :   if (preserve) {
     353           0 :     memcpy(tmp.get(), buf.get(), preserve);
     354             :   }
     355           0 :   buf = Move(tmp);
     356             : }
     357             : 
     358           0 : void EnsureBuffer(UniquePtr<char[]> &buf, uint32_t newSize,
     359             :                   uint32_t preserve, uint32_t &objSize)
     360             : {
     361           0 :     localEnsureBuffer<char> (buf, newSize, preserve, objSize);
     362           0 : }
     363             : 
     364           0 : void EnsureBuffer(UniquePtr<uint8_t[]> &buf, uint32_t newSize,
     365             :                   uint32_t preserve, uint32_t &objSize)
     366             : {
     367           0 :     localEnsureBuffer<uint8_t> (buf, newSize, preserve, objSize);
     368           0 : }
     369             : ///
     370             : 
     371             : void
     372           0 : ParsedHeaderValueList::Tokenize(char *input, uint32_t inputLen, char **token,
     373             :                                 uint32_t *tokenLen, bool *foundEquals, char **next)
     374             : {
     375           0 :     if (foundEquals) {
     376           0 :         *foundEquals = false;
     377             :     }
     378           0 :     if (next) {
     379           0 :         *next = nullptr;
     380             :     }
     381           0 :     if (inputLen < 1 || !input || !token) {
     382           0 :         return;
     383             :     }
     384             : 
     385           0 :     bool foundFirst = false;
     386           0 :     bool inQuote = false;
     387           0 :     bool foundToken = false;
     388           0 :     *token = input;
     389           0 :     *tokenLen = inputLen;
     390             : 
     391           0 :     for (uint32_t index = 0; !foundToken && index < inputLen; ++index) {
     392             :         // strip leading cruft
     393           0 :         if (!foundFirst &&
     394           0 :             (input[index] == ' ' || input[index] == '"' || input[index] == '\t')) {
     395           0 :             (*token)++;
     396             :         } else {
     397           0 :             foundFirst = true;
     398             :         }
     399             : 
     400           0 :         if (input[index] == '"') {
     401           0 :             inQuote = !inQuote;
     402           0 :             continue;
     403             :         }
     404             : 
     405           0 :         if (inQuote) {
     406           0 :             continue;
     407             :         }
     408             : 
     409           0 :         if (input[index] == '=' || input[index] == ';') {
     410           0 :             *tokenLen = (input + index) - *token;
     411           0 :             if (next && ((index + 1) < inputLen)) {
     412           0 :                 *next = input + index + 1;
     413             :             }
     414           0 :             foundToken = true;
     415           0 :             if (foundEquals && input[index] == '=') {
     416           0 :                 *foundEquals = true;
     417             :             }
     418           0 :             break;
     419             :         }
     420             :     }
     421             : 
     422           0 :     if (!foundToken) {
     423           0 :         *tokenLen = (input + inputLen) - *token;
     424             :     }
     425             : 
     426             :     // strip trailing cruft
     427           0 :     for (char *index = *token + *tokenLen - 1; index >= *token; --index) {
     428           0 :         if (*index != ' ' && *index != '\t' && *index != '"') {
     429           0 :             break;
     430             :         }
     431           0 :         --(*tokenLen);
     432           0 :         if (*index == '"') {
     433           0 :             break;
     434             :         }
     435             :     }
     436             : }
     437             : 
     438           0 : ParsedHeaderValueList::ParsedHeaderValueList(char *t, uint32_t len)
     439             : {
     440           0 :     char *name = nullptr;
     441           0 :     uint32_t nameLen = 0;
     442           0 :     char *value = nullptr;
     443           0 :     uint32_t valueLen = 0;
     444           0 :     char *next = nullptr;
     445             :     bool foundEquals;
     446             : 
     447           0 :     while (t) {
     448           0 :         Tokenize(t, len, &name, &nameLen, &foundEquals, &next);
     449           0 :         if (next) {
     450           0 :             len -= next - t;
     451             :         }
     452           0 :         t = next;
     453           0 :         if (foundEquals && t) {
     454           0 :             Tokenize(t, len, &value, &valueLen, nullptr, &next);
     455           0 :             if (next) {
     456           0 :                 len -= next - t;
     457             :             }
     458           0 :             t = next;
     459             :         }
     460           0 :         mValues.AppendElement(ParsedHeaderPair(name, nameLen, value, valueLen));
     461           0 :         value = name = nullptr;
     462           0 :         valueLen = nameLen = 0;
     463           0 :         next = nullptr;
     464             :     }
     465           0 : }
     466             : 
     467           0 : ParsedHeaderValueListList::ParsedHeaderValueListList(const nsCString &fullHeader)
     468           0 :     : mFull(fullHeader)
     469             : {
     470           0 :     char *t = mFull.BeginWriting();
     471           0 :     uint32_t len = mFull.Length();
     472           0 :     char *last = t;
     473           0 :     bool inQuote = false;
     474           0 :     for (uint32_t index = 0; index < len; ++index) {
     475           0 :         if (t[index] == '"') {
     476           0 :             inQuote = !inQuote;
     477           0 :             continue;
     478             :         }
     479           0 :         if (inQuote) {
     480           0 :             continue;
     481             :         }
     482           0 :         if (t[index] == ',') {
     483           0 :             mValues.AppendElement(ParsedHeaderValueList(last, (t + index) - last));
     484           0 :             last = t + index + 1;
     485             :         }
     486             :     }
     487           0 :     if (!inQuote) {
     488           0 :         mValues.AppendElement(ParsedHeaderValueList(last, (t + len) - last));
     489             :     }
     490           0 : }
     491             : 
     492             : } // namespace net
     493             : } // namespace mozilla

Generated by: LCOV version 1.13