netwerk/protocol/http/nsHttp.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/nsHttp.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,299 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim:set ts=4 sw=4 sts=4 et cin: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +// HttpLog.h should generally be included first
    1.11 +#include "HttpLog.h"
    1.12 +
    1.13 +#include "nsHttp.h"
    1.14 +#include "pldhash.h"
    1.15 +#include "mozilla/Mutex.h"
    1.16 +#include "mozilla/HashFunctions.h"
    1.17 +#include "nsCRT.h"
    1.18 +
    1.19 +#if defined(PR_LOGGING)
    1.20 +PRLogModuleInfo *gHttpLog = nullptr;
    1.21 +#endif
    1.22 +
    1.23 +namespace mozilla {
    1.24 +namespace net {
    1.25 +
    1.26 +// define storage for all atoms
    1.27 +#define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
    1.28 +#include "nsHttpAtomList.h"
    1.29 +#undef HTTP_ATOM
    1.30 +
    1.31 +// find out how many atoms we have
    1.32 +#define HTTP_ATOM(_name, _value) Unused_ ## _name,
    1.33 +enum {
    1.34 +#include "nsHttpAtomList.h"
    1.35 +    NUM_HTTP_ATOMS
    1.36 +};
    1.37 +#undef HTTP_ATOM
    1.38 +
    1.39 +// we keep a linked list of atoms allocated on the heap for easy clean up when
    1.40 +// the atom table is destroyed.  The structure and value string are allocated
    1.41 +// as one contiguous block.
    1.42 +
    1.43 +struct HttpHeapAtom {
    1.44 +    struct HttpHeapAtom *next;
    1.45 +    char                 value[1];
    1.46 +};
    1.47 +
    1.48 +static struct PLDHashTable  sAtomTable = {0};
    1.49 +static struct HttpHeapAtom *sHeapAtoms = nullptr;
    1.50 +static Mutex               *sLock = nullptr;
    1.51 +
    1.52 +HttpHeapAtom *
    1.53 +NewHeapAtom(const char *value) {
    1.54 +    int len = strlen(value);
    1.55 +
    1.56 +    HttpHeapAtom *a =
    1.57 +        reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
    1.58 +    if (!a)
    1.59 +        return nullptr;
    1.60 +    memcpy(a->value, value, len + 1);
    1.61 +
    1.62 +    // add this heap atom to the list of all heap atoms
    1.63 +    a->next = sHeapAtoms;
    1.64 +    sHeapAtoms = a;
    1.65 +
    1.66 +    return a;
    1.67 +}
    1.68 +
    1.69 +// Hash string ignore case, based on PL_HashString
    1.70 +static PLDHashNumber
    1.71 +StringHash(PLDHashTable *table, const void *key)
    1.72 +{
    1.73 +    PLDHashNumber h = 0;
    1.74 +    for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
    1.75 +        h = AddToHash(h, nsCRT::ToLower(*s));
    1.76 +    return h;
    1.77 +}
    1.78 +
    1.79 +static bool
    1.80 +StringCompare(PLDHashTable *table, const PLDHashEntryHdr *entry,
    1.81 +              const void *testKey)
    1.82 +{
    1.83 +    const void *entryKey =
    1.84 +            reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
    1.85 +
    1.86 +    return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
    1.87 +                         reinterpret_cast<const char *>(testKey)) == 0;
    1.88 +}
    1.89 +
    1.90 +static const PLDHashTableOps ops = {
    1.91 +    PL_DHashAllocTable,
    1.92 +    PL_DHashFreeTable,
    1.93 +    StringHash,
    1.94 +    StringCompare,
    1.95 +    PL_DHashMoveEntryStub,
    1.96 +    PL_DHashClearEntryStub,
    1.97 +    PL_DHashFinalizeStub,
    1.98 +    nullptr
    1.99 +};
   1.100 +
   1.101 +// We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
   1.102 +nsresult
   1.103 +nsHttp::CreateAtomTable()
   1.104 +{
   1.105 +    MOZ_ASSERT(!sAtomTable.ops, "atom table already initialized");
   1.106 +
   1.107 +    if (!sLock) {
   1.108 +        sLock = new Mutex("nsHttp.sLock");
   1.109 +    }
   1.110 +
   1.111 +    // The capacity for this table is initialized to a value greater than the
   1.112 +    // number of known atoms (NUM_HTTP_ATOMS) because we expect to encounter a
   1.113 +    // few random headers right off the bat.
   1.114 +    if (!PL_DHashTableInit(&sAtomTable, &ops, nullptr,
   1.115 +                           sizeof(PLDHashEntryStub),
   1.116 +                           NUM_HTTP_ATOMS + 10, fallible_t())) {
   1.117 +        sAtomTable.ops = nullptr;
   1.118 +        return NS_ERROR_OUT_OF_MEMORY;
   1.119 +    }
   1.120 +
   1.121 +    // fill the table with our known atoms
   1.122 +    const char *const atoms[] = {
   1.123 +#define HTTP_ATOM(_name, _value) nsHttp::_name._val,
   1.124 +#include "nsHttpAtomList.h"
   1.125 +#undef HTTP_ATOM
   1.126 +        nullptr
   1.127 +    };
   1.128 +
   1.129 +    for (int i = 0; atoms[i]; ++i) {
   1.130 +        PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
   1.131 +                                                 (PL_DHashTableOperate(&sAtomTable, atoms[i], PL_DHASH_ADD));
   1.132 +        if (!stub)
   1.133 +            return NS_ERROR_OUT_OF_MEMORY;
   1.134 +
   1.135 +        MOZ_ASSERT(!stub->key, "duplicate static atom");
   1.136 +        stub->key = atoms[i];
   1.137 +    }
   1.138 +
   1.139 +    return NS_OK;
   1.140 +}
   1.141 +
   1.142 +void
   1.143 +nsHttp::DestroyAtomTable()
   1.144 +{
   1.145 +    if (sAtomTable.ops) {
   1.146 +        PL_DHashTableFinish(&sAtomTable);
   1.147 +        sAtomTable.ops = nullptr;
   1.148 +    }
   1.149 +
   1.150 +    while (sHeapAtoms) {
   1.151 +        HttpHeapAtom *next = sHeapAtoms->next;
   1.152 +        free(sHeapAtoms);
   1.153 +        sHeapAtoms = next;
   1.154 +    }
   1.155 +
   1.156 +    if (sLock) {
   1.157 +        delete sLock;
   1.158 +        sLock = nullptr;
   1.159 +    }
   1.160 +}
   1.161 +
   1.162 +Mutex *
   1.163 +nsHttp::GetLock()
   1.164 +{
   1.165 +    return sLock;
   1.166 +}
   1.167 +
   1.168 +// this function may be called from multiple threads
   1.169 +nsHttpAtom
   1.170 +nsHttp::ResolveAtom(const char *str)
   1.171 +{
   1.172 +    nsHttpAtom atom = { nullptr };
   1.173 +
   1.174 +    if (!str || !sAtomTable.ops)
   1.175 +        return atom;
   1.176 +
   1.177 +    MutexAutoLock lock(*sLock);
   1.178 +
   1.179 +    PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
   1.180 +                                             (PL_DHashTableOperate(&sAtomTable, str, PL_DHASH_ADD));
   1.181 +    if (!stub)
   1.182 +        return atom;  // out of memory
   1.183 +
   1.184 +    if (stub->key) {
   1.185 +        atom._val = reinterpret_cast<const char *>(stub->key);
   1.186 +        return atom;
   1.187 +    }
   1.188 +
   1.189 +    // if the atom could not be found in the atom table, then we'll go
   1.190 +    // and allocate a new atom on the heap.
   1.191 +    HttpHeapAtom *heapAtom = NewHeapAtom(str);
   1.192 +    if (!heapAtom)
   1.193 +        return atom;  // out of memory
   1.194 +
   1.195 +    stub->key = atom._val = heapAtom->value;
   1.196 +    return atom;
   1.197 +}
   1.198 +
   1.199 +//
   1.200 +// From section 2.2 of RFC 2616, a token is defined as:
   1.201 +//
   1.202 +//   token          = 1*<any CHAR except CTLs or separators>
   1.203 +//   CHAR           = <any US-ASCII character (octets 0 - 127)>
   1.204 +//   separators     = "(" | ")" | "<" | ">" | "@"
   1.205 +//                  | "," | ";" | ":" | "\" | <">
   1.206 +//                  | "/" | "[" | "]" | "?" | "="
   1.207 +//                  | "{" | "}" | SP | HT
   1.208 +//   CTL            = <any US-ASCII control character
   1.209 +//                    (octets 0 - 31) and DEL (127)>
   1.210 +//   SP             = <US-ASCII SP, space (32)>
   1.211 +//   HT             = <US-ASCII HT, horizontal-tab (9)>
   1.212 +//
   1.213 +static const char kValidTokenMap[128] = {
   1.214 +    0, 0, 0, 0, 0, 0, 0, 0, //   0
   1.215 +    0, 0, 0, 0, 0, 0, 0, 0, //   8
   1.216 +    0, 0, 0, 0, 0, 0, 0, 0, //  16
   1.217 +    0, 0, 0, 0, 0, 0, 0, 0, //  24
   1.218 +
   1.219 +    0, 1, 0, 1, 1, 1, 1, 1, //  32
   1.220 +    0, 0, 1, 1, 0, 1, 1, 0, //  40
   1.221 +    1, 1, 1, 1, 1, 1, 1, 1, //  48
   1.222 +    1, 1, 0, 0, 0, 0, 0, 0, //  56
   1.223 +
   1.224 +    0, 1, 1, 1, 1, 1, 1, 1, //  64
   1.225 +    1, 1, 1, 1, 1, 1, 1, 1, //  72
   1.226 +    1, 1, 1, 1, 1, 1, 1, 1, //  80
   1.227 +    1, 1, 1, 0, 0, 0, 1, 1, //  88
   1.228 +
   1.229 +    1, 1, 1, 1, 1, 1, 1, 1, //  96
   1.230 +    1, 1, 1, 1, 1, 1, 1, 1, // 104
   1.231 +    1, 1, 1, 1, 1, 1, 1, 1, // 112
   1.232 +    1, 1, 1, 0, 1, 0, 1, 0  // 120
   1.233 +};
   1.234 +bool
   1.235 +nsHttp::IsValidToken(const char *start, const char *end)
   1.236 +{
   1.237 +    if (start == end)
   1.238 +        return false;
   1.239 +
   1.240 +    for (; start != end; ++start) {
   1.241 +        const unsigned char idx = *start;
   1.242 +        if (idx > 127 || !kValidTokenMap[idx])
   1.243 +            return false;
   1.244 +    }
   1.245 +
   1.246 +    return true;
   1.247 +}
   1.248 +
   1.249 +const char *
   1.250 +nsHttp::FindToken(const char *input, const char *token, const char *seps)
   1.251 +{
   1.252 +    if (!input)
   1.253 +        return nullptr;
   1.254 +
   1.255 +    int inputLen = strlen(input);
   1.256 +    int tokenLen = strlen(token);
   1.257 +
   1.258 +    if (inputLen < tokenLen)
   1.259 +        return nullptr;
   1.260 +
   1.261 +    const char *inputTop = input;
   1.262 +    const char *inputEnd = input + inputLen - tokenLen;
   1.263 +    for (; input <= inputEnd; ++input) {
   1.264 +        if (PL_strncasecmp(input, token, tokenLen) == 0) {
   1.265 +            if (input > inputTop && !strchr(seps, *(input - 1)))
   1.266 +                continue;
   1.267 +            if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
   1.268 +                continue;
   1.269 +            return input;
   1.270 +        }
   1.271 +    }
   1.272 +
   1.273 +    return nullptr;
   1.274 +}
   1.275 +
   1.276 +bool
   1.277 +nsHttp::ParseInt64(const char *input, const char **next, int64_t *r)
   1.278 +{
   1.279 +    const char *start = input;
   1.280 +    *r = 0;
   1.281 +    while (*input >= '0' && *input <= '9') {
   1.282 +        int64_t next = 10 * (*r) + (*input - '0');
   1.283 +        if (next < *r) // overflow?
   1.284 +            return false;
   1.285 +        *r = next;
   1.286 +        ++input;
   1.287 +    }
   1.288 +    if (input == start) // nothing parsed?
   1.289 +        return false;
   1.290 +    if (next)
   1.291 +        *next = input;
   1.292 +    return true;
   1.293 +}
   1.294 +
   1.295 +bool
   1.296 +nsHttp::IsPermanentRedirect(uint32_t httpStatus)
   1.297 +{
   1.298 +  return httpStatus == 301 || httpStatus == 308;
   1.299 +}
   1.300 +
   1.301 +} // namespace mozilla::net
   1.302 +} // namespace mozilla

mercurial