netwerk/protocol/http/nsHttp.cpp

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:1703ddb2b534
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/. */
6
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9
10 #include "nsHttp.h"
11 #include "pldhash.h"
12 #include "mozilla/Mutex.h"
13 #include "mozilla/HashFunctions.h"
14 #include "nsCRT.h"
15
16 #if defined(PR_LOGGING)
17 PRLogModuleInfo *gHttpLog = nullptr;
18 #endif
19
20 namespace mozilla {
21 namespace net {
22
23 // define storage for all atoms
24 #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
25 #include "nsHttpAtomList.h"
26 #undef HTTP_ATOM
27
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
35
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.
39
40 struct HttpHeapAtom {
41 struct HttpHeapAtom *next;
42 char value[1];
43 };
44
45 static struct PLDHashTable sAtomTable = {0};
46 static struct HttpHeapAtom *sHeapAtoms = nullptr;
47 static Mutex *sLock = nullptr;
48
49 HttpHeapAtom *
50 NewHeapAtom(const char *value) {
51 int len = strlen(value);
52
53 HttpHeapAtom *a =
54 reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
55 if (!a)
56 return nullptr;
57 memcpy(a->value, value, len + 1);
58
59 // add this heap atom to the list of all heap atoms
60 a->next = sHeapAtoms;
61 sHeapAtoms = a;
62
63 return a;
64 }
65
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 }
75
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;
82
83 return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
84 reinterpret_cast<const char *>(testKey)) == 0;
85 }
86
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 };
97
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");
103
104 if (!sLock) {
105 sLock = new Mutex("nsHttp.sLock");
106 }
107
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 }
117
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 };
125
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;
131
132 MOZ_ASSERT(!stub->key, "duplicate static atom");
133 stub->key = atoms[i];
134 }
135
136 return NS_OK;
137 }
138
139 void
140 nsHttp::DestroyAtomTable()
141 {
142 if (sAtomTable.ops) {
143 PL_DHashTableFinish(&sAtomTable);
144 sAtomTable.ops = nullptr;
145 }
146
147 while (sHeapAtoms) {
148 HttpHeapAtom *next = sHeapAtoms->next;
149 free(sHeapAtoms);
150 sHeapAtoms = next;
151 }
152
153 if (sLock) {
154 delete sLock;
155 sLock = nullptr;
156 }
157 }
158
159 Mutex *
160 nsHttp::GetLock()
161 {
162 return sLock;
163 }
164
165 // this function may be called from multiple threads
166 nsHttpAtom
167 nsHttp::ResolveAtom(const char *str)
168 {
169 nsHttpAtom atom = { nullptr };
170
171 if (!str || !sAtomTable.ops)
172 return atom;
173
174 MutexAutoLock lock(*sLock);
175
176 PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
177 (PL_DHashTableOperate(&sAtomTable, str, PL_DHASH_ADD));
178 if (!stub)
179 return atom; // out of memory
180
181 if (stub->key) {
182 atom._val = reinterpret_cast<const char *>(stub->key);
183 return atom;
184 }
185
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
191
192 stub->key = atom._val = heapAtom->value;
193 return atom;
194 }
195
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
215
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
220
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
225
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;
236
237 for (; start != end; ++start) {
238 const unsigned char idx = *start;
239 if (idx > 127 || !kValidTokenMap[idx])
240 return false;
241 }
242
243 return true;
244 }
245
246 const char *
247 nsHttp::FindToken(const char *input, const char *token, const char *seps)
248 {
249 if (!input)
250 return nullptr;
251
252 int inputLen = strlen(input);
253 int tokenLen = strlen(token);
254
255 if (inputLen < tokenLen)
256 return nullptr;
257
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 }
269
270 return nullptr;
271 }
272
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 }
291
292 bool
293 nsHttp::IsPermanentRedirect(uint32_t httpStatus)
294 {
295 return httpStatus == 301 || httpStatus == 308;
296 }
297
298 } // namespace mozilla::net
299 } // namespace mozilla

mercurial