Wed, 31 Dec 2014 06:09:35 +0100
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