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
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.
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 ***** */
41 #include "nsAutoLock.h"
46 #if defined(PR_LOGGING)
47 PRLogModuleInfo
*gHttpLog
= nsnull
;
50 // define storage for all atoms
51 #define HTTP_ATOM(_name, _value) nsHttpAtom nsHttp::_name = { _value };
52 #include "nsHttpAtomList.h"
55 // find out how many atoms we have
56 #define HTTP_ATOM(_name, _value) Unused_ ## _name,
58 #include "nsHttpAtomList.h"
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.
68 struct HttpHeapAtom
*next
;
72 static struct PLDHashTable sAtomTable
= {0};
73 static struct HttpHeapAtom
*sHeapAtoms
= nsnull
;
74 static PRLock
*sLock
= nsnull
;
77 NewHeapAtom(const char *value
) {
78 int len
= strlen(value
);
81 reinterpret_cast<HttpHeapAtom
*>(malloc(sizeof(*a
) + len
));
84 memcpy(a
->value
, value
, len
+ 1);
86 // add this heap atom to the list of all heap atoms
93 // Hash string ignore case, based on PL_HashString
95 StringHash(PLDHashTable
*table
, const void *key
)
98 for (const char *s
= reinterpret_cast<const char*>(key
); *s
; ++s
)
99 h
= PR_ROTATE_LEFT32(h
, 4) ^ nsCRT::ToLower(*s
);
104 StringCompare(PLDHashTable
*table
, const PLDHashEntryHdr
*entry
,
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
= {
119 PL_DHashMoveEntryStub
,
120 PL_DHashClearEntryStub
,
121 PL_DHashFinalizeStub
,
125 // We put the atoms in a hash table for speedy lookup.. see ResolveAtom.
127 nsHttp::CreateAtomTable()
129 NS_ASSERTION(!sAtomTable
.ops
, "atom table already initialized");
132 sLock
= PR_NewLock();
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"
154 for (int i
= 0; atoms
[i
]; ++i
) {
155 PLDHashEntryStub
*stub
= reinterpret_cast<PLDHashEntryStub
*>
156 (PL_DHashTableOperate(&sAtomTable
, atoms
[i
], PL_DHASH_ADD
));
158 return NS_ERROR_OUT_OF_MEMORY
;
160 NS_ASSERTION(!stub
->key
, "duplicate static atom");
161 stub
->key
= atoms
[i
];
168 nsHttp::DestroyAtomTable()
170 if (sAtomTable
.ops
) {
171 PL_DHashTableFinish(&sAtomTable
);
172 sAtomTable
.ops
= nsnull
;
176 HttpHeapAtom
*next
= sHeapAtoms
->next
;
182 PR_DestroyLock(sLock
);
187 // this function may be called from multiple threads
189 nsHttp::ResolveAtom(const char *str
)
191 nsHttpAtom atom
= { nsnull
};
193 if (!str
|| !sAtomTable
.ops
)
196 nsAutoLock
lock(sLock
);
198 PLDHashEntryStub
*stub
= reinterpret_cast<PLDHashEntryStub
*>
199 (PL_DHashTableOperate(&sAtomTable
, str
, PL_DHASH_ADD
));
201 return atom
; // out of memory
204 atom
._val
= reinterpret_cast<const char *>(stub
->key
);
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
);
212 return atom
; // out of memory
214 stub
->key
= atom
._val
= heapAtom
->value
;
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
254 nsHttp::IsValidToken(const char *start
, const char *end
)
259 for (; start
!= end
; ++start
) {
260 const unsigned char idx
= *start
;
261 if (idx
> 127 || !kValidTokenMap
[idx
])
269 nsHttp::FindToken(const char *input
, const char *token
, const char *seps
)
274 int inputLen
= strlen(input
);
275 int tokenLen
= strlen(token
);
277 if (inputLen
< tokenLen
)
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)))
286 if (input
< inputEnd
&& !strchr(seps
, *(input
+ tokenLen
)))
296 nsHttp::ParseInt64(const char *input
, const char **next
, PRInt64
*r
)
298 const char *start
= input
;
300 while (*input
>= '0' && *input
<= '9') {
301 PRInt64 next
= 10 * (*r
) + (*input
- '0');
302 if (next
< *r
) // overflow?
307 if (input
== start
) // nothing parsed?