Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / netwerk / protocol / http / src / nsHttp.cpp
blob1313002fd18c1ef92f8aa183608a3652585bbfae
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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications.
20 * Portions created by the Initial Developer are Copyright (C) 2001
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Darin Fisher <darin@netscape.com> (original author)
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsHttp.h"
41 #include "nsAutoLock.h"
42 #include "pldhash.h"
43 #include "nsCRT.h"
44 #include "prbit.h"
46 #if defined(PR_LOGGING)
47 PRLogModuleInfo *gHttpLog = nsnull;
48 #endif
50 // define storage for all atoms
51 #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
52 #include "nsHttpAtomList.h"
53 #undef HTTP_ATOM
55 // find out how many atoms we have
56 #define HTTP_ATOM(_name, _value) Unused_ ## _name,
57 enum {
58 #include "nsHttpAtomList.h"
59 NUM_HTTP_ATOMS
61 #undef HTTP_ATOM
63 // we keep a linked list of atoms allocated on the heap for easy clean up when
64 // the atom table is destroyed. The structure and value string are allocated
65 // as one contiguous block.
67 struct HttpHeapAtom {
68 struct HttpHeapAtom *next;
69 char value[1];
72 static struct PLDHashTable sAtomTable = {0};
73 static struct HttpHeapAtom *sHeapAtoms = nsnull;
74 static PRLock *sLock = nsnull;
76 HttpHeapAtom *
77 NewHeapAtom(const char *value) {
78 int len = strlen(value);
80 HttpHeapAtom *a =
81 reinterpret_cast<HttpHeapAtom *>(malloc(sizeof(*a) + len));
82 if (!a)
83 return nsnull;
84 memcpy(a->value, value, len + 1);
86 // add this heap atom to the list of all heap atoms
87 a->next = sHeapAtoms;
88 sHeapAtoms = a;
90 return a;
93 // Hash string ignore case, based on PL_HashString
94 static PLDHashNumber
95 StringHash(PLDHashTable *table, const void *key)
97 PLDHashNumber h = 0;
98 for (const char *s = reinterpret_cast<const char*>(key); *s; ++s)
99 h = PR_ROTATE_LEFT32(h, 4) ^ nsCRT::ToLower(*s);
100 return h;
103 static PRBool
104 StringCompare(PLDHashTable *table, const PLDHashEntryHdr *entry,
105 const void *testKey)
107 const void *entryKey =
108 reinterpret_cast<const PLDHashEntryStub *>(entry)->key;
110 return PL_strcasecmp(reinterpret_cast<const char *>(entryKey),
111 reinterpret_cast<const char *>(testKey)) == 0;
114 static const PLDHashTableOps ops = {
115 PL_DHashAllocTable,
116 PL_DHashFreeTable,
117 StringHash,
118 StringCompare,
119 PL_DHashMoveEntryStub,
120 PL_DHashClearEntryStub,
121 PL_DHashFinalizeStub,
122 nsnull
125 // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
126 nsresult
127 nsHttp::CreateAtomTable()
129 NS_ASSERTION(!sAtomTable.ops, "atom table already initialized");
131 if (!sLock) {
132 sLock = PR_NewLock();
133 if (!sLock)
134 return NS_ERROR_OUT_OF_MEMORY;
137 // The capacity for this table is initialized to a value greater than the
138 // number of known atoms (NUM_HTTP_ATOMS) because we expect to encounter a
139 // few random headers right off the bat.
140 if (!PL_DHashTableInit(&sAtomTable, &ops, nsnull, sizeof(PLDHashEntryStub),
141 NUM_HTTP_ATOMS + 10)) {
142 sAtomTable.ops = nsnull;
143 return NS_ERROR_OUT_OF_MEMORY;
146 // fill the table with our known atoms
147 const char *const atoms[] = {
148 #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
149 #include "nsHttpAtomList.h"
150 #undef HTTP_ATOM
151 nsnull
154 for (int i = 0; atoms[i]; ++i) {
155 PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
156 (PL_DHashTableOperate(&sAtomTable, atoms[i], PL_DHASH_ADD));
157 if (!stub)
158 return NS_ERROR_OUT_OF_MEMORY;
160 NS_ASSERTION(!stub->key, "duplicate static atom");
161 stub->key = atoms[i];
164 return NS_OK;
167 void
168 nsHttp::DestroyAtomTable()
170 if (sAtomTable.ops) {
171 PL_DHashTableFinish(&sAtomTable);
172 sAtomTable.ops = nsnull;
175 while (sHeapAtoms) {
176 HttpHeapAtom *next = sHeapAtoms->next;
177 free(sHeapAtoms);
178 sHeapAtoms = next;
181 if (sLock) {
182 PR_DestroyLock(sLock);
183 sLock = nsnull;
187 // this function may be called from multiple threads
188 nsHttpAtom
189 nsHttp::ResolveAtom(const char *str)
191 nsHttpAtom atom = { nsnull };
193 if (!str || !sAtomTable.ops)
194 return atom;
196 nsAutoLock lock(sLock);
198 PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
199 (PL_DHashTableOperate(&sAtomTable, str, PL_DHASH_ADD));
200 if (!stub)
201 return atom; // out of memory
203 if (stub->key) {
204 atom._val = reinterpret_cast<const char *>(stub->key);
205 return atom;
208 // if the atom could not be found in the atom table, then we'll go
209 // and allocate a new atom on the heap.
210 HttpHeapAtom *heapAtom = NewHeapAtom(str);
211 if (!heapAtom)
212 return atom; // out of memory
214 stub->key = atom._val = heapAtom->value;
215 return atom;
219 // From section 2.2 of RFC 2616, a token is defined as:
221 // token = 1*<any CHAR except CTLs or separators>
222 // CHAR = <any US-ASCII character (octets 0 - 127)>
223 // separators = "(" | ")" | "<" | ">" | "@"
224 // | "," | ";" | ":" | "\" | <">
225 // | "/" | "[" | "]" | "?" | "="
226 // | "{" | "}" | SP | HT
227 // CTL = <any US-ASCII control character
228 // (octets 0 - 31) and DEL (127)>
229 // SP = <US-ASCII SP, space (32)>
230 // HT = <US-ASCII HT, horizontal-tab (9)>
232 static const char kValidTokenMap[128] = {
233 0, 0, 0, 0, 0, 0, 0, 0, // 0
234 0, 0, 0, 0, 0, 0, 0, 0, // 8
235 0, 0, 0, 0, 0, 0, 0, 0, // 16
236 0, 0, 0, 0, 0, 0, 0, 0, // 24
238 0, 1, 0, 1, 1, 1, 1, 1, // 32
239 0, 0, 1, 1, 0, 1, 1, 0, // 40
240 1, 1, 1, 1, 1, 1, 1, 1, // 48
241 1, 1, 0, 0, 0, 0, 0, 0, // 56
243 0, 1, 1, 1, 1, 1, 1, 1, // 64
244 1, 1, 1, 1, 1, 1, 1, 1, // 72
245 1, 1, 1, 1, 1, 1, 1, 1, // 80
246 1, 1, 1, 0, 0, 0, 1, 1, // 88
248 1, 1, 1, 1, 1, 1, 1, 1, // 96
249 1, 1, 1, 1, 1, 1, 1, 1, // 104
250 1, 1, 1, 1, 1, 1, 1, 1, // 112
251 1, 1, 1, 0, 1, 0, 1, 0 // 120
253 PRBool
254 nsHttp::IsValidToken(const char *start, const char *end)
256 if (start == end)
257 return PR_FALSE;
259 for (; start != end; ++start) {
260 const unsigned char idx = *start;
261 if (idx > 127 || !kValidTokenMap[idx])
262 return PR_FALSE;
265 return PR_TRUE;
268 const char *
269 nsHttp::FindToken(const char *input, const char *token, const char *seps)
271 if (!input)
272 return nsnull;
274 int inputLen = strlen(input);
275 int tokenLen = strlen(token);
277 if (inputLen < tokenLen)
278 return nsnull;
280 const char *inputTop = input;
281 const char *inputEnd = input + inputLen - tokenLen;
282 for (; input <= inputEnd; ++input) {
283 if (PL_strncasecmp(input, token, tokenLen) == 0) {
284 if (input > inputTop && !strchr(seps, *(input - 1)))
285 continue;
286 if (input < inputEnd && !strchr(seps, *(input + tokenLen)))
287 continue;
288 return input;
292 return nsnull;
295 PRBool
296 nsHttp::ParseInt64(const char *input, const char **next, PRInt64 *r)
298 const char *start = input;
299 *r = 0;
300 while (*input >= '0' && *input <= '9') {
301 PRInt64 next = 10 * (*r) + (*input - '0');
302 if (next < *r) // overflow?
303 return PR_FALSE;
304 *r = next;
305 ++input;
307 if (input == start) // nothing parsed?
308 return PR_FALSE;
309 if (next)
310 *next = input;
311 return PR_TRUE;