netwerk/protocol/http/nsHttp.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 // HttpLog.h should generally be included first
     8 #include "HttpLog.h"
    10 #include "nsHttp.h"
    11 #include "pldhash.h"
    12 #include "mozilla/Mutex.h"
    13 #include "mozilla/HashFunctions.h"
    14 #include "nsCRT.h"
    16 #if defined(PR_LOGGING)
    17 PRLogModuleInfo *gHttpLog = nullptr;
    18 #endif
    20 namespace mozilla {
    21 namespace net {
    23 // define storage for all atoms
    24 #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
    25 #include "nsHttpAtomList.h"
    26 #undef HTTP_ATOM
    28 // find out how many atoms we have
    29 #define HTTP_ATOM(_name, _value) Unused_ ## _name,
    30 enum {
    31 #include "nsHttpAtomList.h"
    32     NUM_HTTP_ATOMS
    33 };
    34 #undef HTTP_ATOM
    36 // we keep a linked list of atoms allocated on the heap for easy clean up when
    37 // the atom table is destroyed.  The structure and value string are allocated
    38 // as one contiguous block.
    40 struct HttpHeapAtom {
    41     struct HttpHeapAtom *next;
    42     char                 value[1];
    43 };
    45 static struct PLDHashTable  sAtomTable = {0};
    46 static struct HttpHeapAtom *sHeapAtoms = nullptr;
    47 static Mutex               *sLock = nullptr;
    49 HttpHeapAtom *
    50 NewHeapAtom(const char *value) {
    51     int len = strlen(value);
    53     HttpHeapAtom *a =
    54         reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
    55     if (!a)
    56         return nullptr;
    57     memcpy(a->value, value, len + 1);
    59     // add this heap atom to the list of all heap atoms
    60     a->next = sHeapAtoms;
    61     sHeapAtoms = a;
    63     return a;
    64 }
    66 // Hash string ignore case, based on PL_HashString
    67 static PLDHashNumber
    68 StringHash(PLDHashTable *table, const void *key)
    69 {
    70     PLDHashNumber h = 0;
    71     for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
    72         h = AddToHash(h, nsCRT::ToLower(*s));
    73     return h;
    74 }
    76 static bool
    77 StringCompare(PLDHashTable *table, const PLDHashEntryHdr *entry,
    78               const void *testKey)
    79 {
    80     const void *entryKey =
    81             reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
    83     return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
    84                          reinterpret_cast<const char *>(testKey)) == 0;
    85 }
    87 static const PLDHashTableOps ops = {
    88     PL_DHashAllocTable,
    89     PL_DHashFreeTable,
    90     StringHash,
    91     StringCompare,
    92     PL_DHashMoveEntryStub,
    93     PL_DHashClearEntryStub,
    94     PL_DHashFinalizeStub,
    95     nullptr
    96 };
    98 // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
    99 nsresult
   100 nsHttp::CreateAtomTable()
   101 {
   102     MOZ_ASSERT(!sAtomTable.ops, "atom table already initialized");
   104     if (!sLock) {
   105         sLock = new Mutex("nsHttp.sLock");
   106     }
   108     // The capacity for this table is initialized to a value greater than the
   109     // number of known atoms (NUM_HTTP_ATOMS) because we expect to encounter a
   110     // few random headers right off the bat.
   111     if (!PL_DHashTableInit(&sAtomTable, &ops, nullptr,
   112                            sizeof(PLDHashEntryStub),
   113                            NUM_HTTP_ATOMS + 10, fallible_t())) {
   114         sAtomTable.ops = nullptr;
   115         return NS_ERROR_OUT_OF_MEMORY;
   116     }
   118     // fill the table with our known atoms
   119     const char *const atoms[] = {
   120 #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
   121 #include "nsHttpAtomList.h"
   122 #undef HTTP_ATOM
   123         nullptr
   124     };
   126     for (int i = 0; atoms[i]; ++i) {
   127         PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
   128                                                  (PL_DHashTableOperate(&sAtomTable, atoms[i], PL_DHASH_ADD));
   129         if (!stub)
   130             return NS_ERROR_OUT_OF_MEMORY;
   132         MOZ_ASSERT(!stub->key, "duplicate static atom");
   133         stub->key = atoms[i];
   134     }
   136     return NS_OK;
   137 }
   139 void
   140 nsHttp::DestroyAtomTable()
   141 {
   142     if (sAtomTable.ops) {
   143         PL_DHashTableFinish(&sAtomTable);
   144         sAtomTable.ops = nullptr;
   145     }
   147     while (sHeapAtoms) {
   148         HttpHeapAtom *next = sHeapAtoms->next;
   149         free(sHeapAtoms);
   150         sHeapAtoms = next;
   151     }
   153     if (sLock) {
   154         delete sLock;
   155         sLock = nullptr;
   156     }
   157 }
   159 Mutex *
   160 nsHttp::GetLock()
   161 {
   162     return sLock;
   163 }
   165 // this function may be called from multiple threads
   166 nsHttpAtom
   167 nsHttp::ResolveAtom(const char *str)
   168 {
   169     nsHttpAtom atom = { nullptr };
   171     if (!str || !sAtomTable.ops)
   172         return atom;
   174     MutexAutoLock lock(*sLock);
   176     PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
   177                                              (PL_DHashTableOperate(&sAtomTable, str, PL_DHASH_ADD));
   178     if (!stub)
   179         return atom;  // out of memory
   181     if (stub->key) {
   182         atom._val = reinterpret_cast<const char *>(stub->key);
   183         return atom;
   184     }
   186     // if the atom could not be found in the atom table, then we'll go
   187     // and allocate a new atom on the heap.
   188     HttpHeapAtom *heapAtom = NewHeapAtom(str);
   189     if (!heapAtom)
   190         return atom;  // out of memory
   192     stub->key = atom._val = heapAtom->value;
   193     return atom;
   194 }
   196 //
   197 // From section 2.2 of RFC 2616, a token is defined as:
   198 //
   199 //   token          = 1*<any CHAR except CTLs or separators>
   200 //   CHAR           = <any US-ASCII character (octets 0 - 127)>
   201 //   separators     = "(" | ")" | "<" | ">" | "@"
   202 //                  | "," | ";" | ":" | "\" | <">
   203 //                  | "/" | "[" | "]" | "?" | "="
   204 //                  | "{" | "}" | SP | HT
   205 //   CTL            = <any US-ASCII control character
   206 //                    (octets 0 - 31) and DEL (127)>
   207 //   SP             = <US-ASCII SP, space (32)>
   208 //   HT             = <US-ASCII HT, horizontal-tab (9)>
   209 //
   210 static const char kValidTokenMap[128] = {
   211     0, 0, 0, 0, 0, 0, 0, 0, //   0
   212     0, 0, 0, 0, 0, 0, 0, 0, //   8
   213     0, 0, 0, 0, 0, 0, 0, 0, //  16
   214     0, 0, 0, 0, 0, 0, 0, 0, //  24
   216     0, 1, 0, 1, 1, 1, 1, 1, //  32
   217     0, 0, 1, 1, 0, 1, 1, 0, //  40
   218     1, 1, 1, 1, 1, 1, 1, 1, //  48
   219     1, 1, 0, 0, 0, 0, 0, 0, //  56
   221     0, 1, 1, 1, 1, 1, 1, 1, //  64
   222     1, 1, 1, 1, 1, 1, 1, 1, //  72
   223     1, 1, 1, 1, 1, 1, 1, 1, //  80
   224     1, 1, 1, 0, 0, 0, 1, 1, //  88
   226     1, 1, 1, 1, 1, 1, 1, 1, //  96
   227     1, 1, 1, 1, 1, 1, 1, 1, // 104
   228     1, 1, 1, 1, 1, 1, 1, 1, // 112
   229     1, 1, 1, 0, 1, 0, 1, 0  // 120
   230 };
   231 bool
   232 nsHttp::IsValidToken(const char *start, const char *end)
   233 {
   234     if (start == end)
   235         return false;
   237     for (; start != end; ++start) {
   238         const unsigned char idx = *start;
   239         if (idx > 127 || !kValidTokenMap[idx])
   240             return false;
   241     }
   243     return true;
   244 }
   246 const char *
   247 nsHttp::FindToken(const char *input, const char *token, const char *seps)
   248 {
   249     if (!input)
   250         return nullptr;
   252     int inputLen = strlen(input);
   253     int tokenLen = strlen(token);
   255     if (inputLen < tokenLen)
   256         return nullptr;
   258     const char *inputTop = input;
   259     const char *inputEnd = input + inputLen - tokenLen;
   260     for (; input <= inputEnd; ++input) {
   261         if (PL_strncasecmp(input, token, tokenLen) == 0) {
   262             if (input > inputTop && !strchr(seps, *(input - 1)))
   263                 continue;
   264             if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
   265                 continue;
   266             return input;
   267         }
   268     }
   270     return nullptr;
   271 }
   273 bool
   274 nsHttp::ParseInt64(const char *input, const char **next, int64_t *r)
   275 {
   276     const char *start = input;
   277     *r = 0;
   278     while (*input >= '0' && *input <= '9') {
   279         int64_t next = 10 * (*r) + (*input - '0');
   280         if (next < *r) // overflow?
   281             return false;
   282         *r = next;
   283         ++input;
   284     }
   285     if (input == start) // nothing parsed?
   286         return false;
   287     if (next)
   288         *next = input;
   289     return true;
   290 }
   292 bool
   293 nsHttp::IsPermanentRedirect(uint32_t httpStatus)
   294 {
   295   return httpStatus == 301 || httpStatus == 308;
   296 }
   298 } // namespace mozilla::net
   299 } // namespace mozilla

mercurial