LCOV - code coverage report
Current view: directory - netwerk/protocol/http - nsHttp.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 96 88 91.7 %
Date: 2012-06-02 Functions: 9 9 100.0 %

       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                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Darin Fisher <darin@netscape.com> (original author)
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsHttp.h"
      41                 : #include "pldhash.h"
      42                 : #include "mozilla/Mutex.h"
      43                 : #include "mozilla/HashFunctions.h"
      44                 : #include "nsCRT.h"
      45                 : #include "prbit.h"
      46                 : 
      47                 : using namespace mozilla;
      48                 : 
      49                 : #if defined(PR_LOGGING)
      50                 : PRLogModuleInfo *gHttpLog = nsnull;
      51                 : #endif
      52                 : 
      53                 : // define storage for all atoms
      54                 : #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
      55                 : #include "nsHttpAtomList.h"
      56                 : #undef HTTP_ATOM
      57                 : 
      58                 : // find out how many atoms we have
      59                 : #define HTTP_ATOM(_name, _value) Unused_ ## _name,
      60                 : enum {
      61                 : #include "nsHttpAtomList.h"
      62                 :     NUM_HTTP_ATOMS
      63                 : };
      64                 : #undef HTTP_ATOM
      65                 : 
      66                 : using namespace mozilla;
      67                 : 
      68                 : // we keep a linked list of atoms allocated on the heap for easy clean up when
      69                 : // the atom table is destroyed.  The structure and value string are allocated
      70                 : // as one contiguous block.
      71                 : 
      72                 : struct HttpHeapAtom {
      73                 :     struct HttpHeapAtom *next;
      74                 :     char                 value[1];
      75                 : };
      76                 : 
      77                 : static struct PLDHashTable  sAtomTable = {0};
      78                 : static struct HttpHeapAtom *sHeapAtoms = nsnull;
      79                 : static Mutex               *sLock = nsnull;
      80                 : 
      81                 : HttpHeapAtom *
      82            1897 : NewHeapAtom(const char *value) {
      83            1897 :     int len = strlen(value);
      84                 : 
      85                 :     HttpHeapAtom *a =
      86            1897 :         reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
      87            1897 :     if (!a)
      88               0 :         return nsnull;
      89            1897 :     memcpy(a->value, value, len + 1);
      90                 : 
      91                 :     // add this heap atom to the list of all heap atoms
      92            1897 :     a->next = sHeapAtoms;
      93            1897 :     sHeapAtoms = a;
      94                 : 
      95            1897 :     return a;
      96                 : }
      97                 : 
      98                 : // Hash string ignore case, based on PL_HashString
      99                 : static PLDHashNumber
     100           96450 : StringHash(PLDHashTable *table, const void *key)
     101                 : {
     102           96450 :     PLDHashNumber h = 0;
     103         1013312 :     for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
     104          916862 :         h = AddToHash(h, nsCRT::ToLower(*s));
     105           96450 :     return h;
     106                 : }
     107                 : 
     108                 : static bool
     109           36159 : StringCompare(PLDHashTable *table, const PLDHashEntryHdr *entry,
     110                 :               const void *testKey)
     111                 : {
     112                 :     const void *entryKey =
     113           36159 :             reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
     114                 : 
     115                 :     return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
     116           36159 :                          reinterpret_cast<const char *>(testKey)) == 0;
     117                 : }
     118                 : 
     119                 : static const PLDHashTableOps ops = {
     120                 :     PL_DHashAllocTable,
     121                 :     PL_DHashFreeTable,
     122                 :     StringHash,
     123                 :     StringCompare,
     124                 :     PL_DHashMoveEntryStub,
     125                 :     PL_DHashClearEntryStub,
     126                 :     PL_DHashFinalizeStub,
     127                 :     nsnull
     128                 : };
     129                 : 
     130                 : // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
     131                 : nsresult
     132             679 : nsHttp::CreateAtomTable()
     133                 : {
     134             679 :     NS_ASSERTION(!sAtomTable.ops, "atom table already initialized");
     135                 : 
     136             679 :     if (!sLock) {
     137             679 :         sLock = new Mutex("nsHttp.sLock");
     138                 :     }
     139                 : 
     140                 :     // The capacity for this table is initialized to a value greater than the
     141                 :     // number of known atoms (NUM_HTTP_ATOMS) because we expect to encounter a
     142                 :     // few random headers right off the bat.
     143             679 :     if (!PL_DHashTableInit(&sAtomTable, &ops, nsnull, sizeof(PLDHashEntryStub),
     144             679 :                            NUM_HTTP_ATOMS + 10)) {
     145               0 :         sAtomTable.ops = nsnull;
     146               0 :         return NS_ERROR_OUT_OF_MEMORY;
     147                 :     }
     148                 : 
     149                 :     // fill the table with our known atoms
     150                 :     const char *const atoms[] = {
     151                 : #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
     152                 : #include "nsHttpAtomList.h"
     153                 : #undef HTTP_ATOM
     154                 :         nsnull
     155             679 :     };
     156                 : 
     157           59073 :     for (int i = 0; atoms[i]; ++i) {
     158                 :         PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
     159           58394 :                                                  (PL_DHashTableOperate(&sAtomTable, atoms[i], PL_DHASH_ADD));
     160           58394 :         if (!stub)
     161               0 :             return NS_ERROR_OUT_OF_MEMORY;
     162                 :         
     163           58394 :         NS_ASSERTION(!stub->key, "duplicate static atom");
     164           58394 :         stub->key = atoms[i];
     165                 :     }
     166                 : 
     167             679 :     return NS_OK;
     168                 : }
     169                 : 
     170                 : void
     171             677 : nsHttp::DestroyAtomTable()
     172                 : {
     173             677 :     if (sAtomTable.ops) {
     174             677 :         PL_DHashTableFinish(&sAtomTable);
     175             677 :         sAtomTable.ops = nsnull;
     176                 :     }
     177                 : 
     178            3251 :     while (sHeapAtoms) {
     179            1897 :         HttpHeapAtom *next = sHeapAtoms->next;
     180            1897 :         free(sHeapAtoms);
     181            1897 :         sHeapAtoms = next;
     182                 :     }
     183                 : 
     184             677 :     if (sLock) {
     185             677 :         delete sLock;
     186             677 :         sLock = nsnull;
     187                 :     }
     188             677 : }
     189                 : 
     190                 : // this function may be called from multiple threads
     191                 : nsHttpAtom
     192           38056 : nsHttp::ResolveAtom(const char *str)
     193                 : {
     194           38056 :     nsHttpAtom atom = { nsnull };
     195                 : 
     196           38056 :     if (!str || !sAtomTable.ops)
     197               0 :         return atom;
     198                 : 
     199           76112 :     MutexAutoLock lock(*sLock);
     200                 : 
     201                 :     PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
     202           38056 :                                              (PL_DHashTableOperate(&sAtomTable, str, PL_DHASH_ADD));
     203           38056 :     if (!stub)
     204                 :         return atom;  // out of memory
     205                 : 
     206           38056 :     if (stub->key) {
     207           36159 :         atom._val = reinterpret_cast<const char *>(stub->key);
     208                 :         return atom;
     209                 :     }
     210                 : 
     211                 :     // if the atom could not be found in the atom table, then we'll go
     212                 :     // and allocate a new atom on the heap.
     213            1897 :     HttpHeapAtom *heapAtom = NewHeapAtom(str);
     214            1897 :     if (!heapAtom)
     215                 :         return atom;  // out of memory
     216                 : 
     217            1897 :     stub->key = atom._val = heapAtom->value;
     218                 :     return atom;
     219                 : }
     220                 : 
     221                 : //
     222                 : // From section 2.2 of RFC 2616, a token is defined as:
     223                 : //
     224                 : //   token          = 1*<any CHAR except CTLs or separators>
     225                 : //   CHAR           = <any US-ASCII character (octets 0 - 127)>
     226                 : //   separators     = "(" | ")" | "<" | ">" | "@"
     227                 : //                  | "," | ";" | ":" | "\" | <">
     228                 : //                  | "/" | "[" | "]" | "?" | "="
     229                 : //                  | "{" | "}" | SP | HT
     230                 : //   CTL            = <any US-ASCII control character
     231                 : //                    (octets 0 - 31) and DEL (127)>
     232                 : //   SP             = <US-ASCII SP, space (32)>
     233                 : //   HT             = <US-ASCII HT, horizontal-tab (9)>
     234                 : //
     235                 : static const char kValidTokenMap[128] = {
     236                 :     0, 0, 0, 0, 0, 0, 0, 0, //   0
     237                 :     0, 0, 0, 0, 0, 0, 0, 0, //   8
     238                 :     0, 0, 0, 0, 0, 0, 0, 0, //  16
     239                 :     0, 0, 0, 0, 0, 0, 0, 0, //  24
     240                 : 
     241                 :     0, 1, 0, 1, 1, 1, 1, 1, //  32
     242                 :     0, 0, 1, 1, 0, 1, 1, 0, //  40
     243                 :     1, 1, 1, 1, 1, 1, 1, 1, //  48
     244                 :     1, 1, 0, 0, 0, 0, 0, 0, //  56
     245                 : 
     246                 :     0, 1, 1, 1, 1, 1, 1, 1, //  64
     247                 :     1, 1, 1, 1, 1, 1, 1, 1, //  72
     248                 :     1, 1, 1, 1, 1, 1, 1, 1, //  80
     249                 :     1, 1, 1, 0, 0, 0, 1, 1, //  88
     250                 : 
     251                 :     1, 1, 1, 1, 1, 1, 1, 1, //  96
     252                 :     1, 1, 1, 1, 1, 1, 1, 1, // 104
     253                 :     1, 1, 1, 1, 1, 1, 1, 1, // 112
     254                 :     1, 1, 1, 0, 1, 0, 1, 0  // 120
     255                 : };
     256                 : bool
     257           28675 : nsHttp::IsValidToken(const char *start, const char *end)
     258                 : {
     259           28675 :     if (start == end)
     260               0 :         return false;
     261                 : 
     262          290091 :     for (; start != end; ++start) {
     263          261418 :         const unsigned char idx = *start;
     264          261418 :         if (idx > 127 || !kValidTokenMap[idx])
     265               2 :             return false;
     266                 :     }
     267                 : 
     268           28673 :     return true;
     269                 : }
     270                 : 
     271                 : const char *
     272           11933 : nsHttp::FindToken(const char *input, const char *token, const char *seps)
     273                 : {
     274           11933 :     if (!input)
     275            8109 :         return nsnull;
     276                 : 
     277            3824 :     int inputLen = strlen(input);
     278            3824 :     int tokenLen = strlen(token);
     279                 : 
     280            3824 :     if (inputLen < tokenLen)
     281              32 :         return nsnull;
     282                 : 
     283            3792 :     const char *inputTop = input;
     284            3792 :     const char *inputEnd = input + inputLen - tokenLen;
     285           25862 :     for (; input <= inputEnd; ++input) {
     286           22133 :         if (PL_strncasecmp(input, token, tokenLen) == 0) {
     287              64 :             if (input > inputTop && !strchr(seps, *(input - 1)))
     288               0 :                 continue;
     289              64 :             if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
     290               1 :                 continue;
     291              63 :             return input;
     292                 :         }
     293                 :     }
     294                 : 
     295            3729 :     return nsnull;
     296                 : }
     297                 : 
     298                 : bool
     299            3398 : nsHttp::ParseInt64(const char *input, const char **next, PRInt64 *r)
     300                 : {
     301            3398 :     const char *start = input;
     302            3398 :     *r = 0;
     303           15004 :     while (*input >= '0' && *input <= '9') {
     304            8208 :         PRInt64 next = 10 * (*r) + (*input - '0');
     305            8208 :         if (next < *r) // overflow?
     306               0 :             return false;
     307            8208 :         *r = next;
     308            8208 :         ++input;
     309                 :     }
     310            3398 :     if (input == start) // nothing parsed?
     311               6 :         return false;
     312            3392 :     if (next)
     313            3392 :         *next = input;
     314            3392 :     return true;
     315                 : }

Generated by: LCOV version 1.7