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