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.

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

mercurial