Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / netwerk / protocol / http / src / nsHttpAuthCache.cpp
blobafcf93376504070fbb3d6256dc0feea54f835f01
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications.
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Darin Fisher <darin@netscape.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include <stdlib.h>
40 #include "nsHttp.h"
41 #include "nsHttpAuthCache.h"
42 #include "nsString.h"
43 #include "nsCRT.h"
44 #include "prprf.h"
46 static inline void
47 GetAuthKey(const char *scheme, const char *host, PRInt32 port, nsCString &key)
49 key.Assign(scheme);
50 key.AppendLiteral("://");
51 key.Append(host);
52 key.Append(':');
53 key.AppendInt(port);
56 // return true if the two strings are equal or both empty. an empty string
57 // is either null or zero length.
58 static PRBool
59 StrEquivalent(const PRUnichar *a, const PRUnichar *b)
61 static const PRUnichar emptyStr[] = {0};
63 if (!a)
64 a = emptyStr;
65 if (!b)
66 b = emptyStr;
68 return nsCRT::strcmp(a, b) == 0;
71 //-----------------------------------------------------------------------------
72 // nsHttpAuthCache <public>
73 //-----------------------------------------------------------------------------
75 nsHttpAuthCache::nsHttpAuthCache()
76 : mDB(nsnull)
80 nsHttpAuthCache::~nsHttpAuthCache()
82 if (mDB)
83 ClearAll();
86 nsresult
87 nsHttpAuthCache::Init()
89 NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED);
91 LOG(("nsHttpAuthCache::Init\n"));
93 mDB = PL_NewHashTable(128, (PLHashFunction) PL_HashString,
94 (PLHashComparator) PL_CompareStrings,
95 (PLHashComparator) 0, &gHashAllocOps, this);
96 if (!mDB)
97 return NS_ERROR_OUT_OF_MEMORY;
99 return NS_OK;
102 nsresult
103 nsHttpAuthCache::GetAuthEntryForPath(const char *scheme,
104 const char *host,
105 PRInt32 port,
106 const char *path,
107 nsHttpAuthEntry **entry)
109 LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
110 scheme, host, port, path));
112 nsCAutoString key;
113 nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
114 if (!node)
115 return NS_ERROR_NOT_AVAILABLE;
117 *entry = node->LookupEntryByPath(path);
118 return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
121 nsresult
122 nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
123 const char *host,
124 PRInt32 port,
125 const char *realm,
126 nsHttpAuthEntry **entry)
129 LOG(("nsHttpAuthCache::GetAuthEntryForDomain [key=%s://%s:%d realm=%s]\n",
130 scheme, host, port, realm));
132 nsCAutoString key;
133 nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
134 if (!node)
135 return NS_ERROR_NOT_AVAILABLE;
137 *entry = node->LookupEntryByRealm(realm);
138 return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
141 nsresult
142 nsHttpAuthCache::SetAuthEntry(const char *scheme,
143 const char *host,
144 PRInt32 port,
145 const char *path,
146 const char *realm,
147 const char *creds,
148 const char *challenge,
149 const nsHttpAuthIdentity &ident,
150 nsISupports *metadata)
152 nsresult rv;
154 LOG(("nsHttpAuthCache::SetAuthEntry [key=%s://%s:%d realm=%s path=%s metadata=%x]\n",
155 scheme, host, port, realm, path, metadata));
157 if (!mDB) {
158 rv = Init();
159 if (NS_FAILED(rv)) return rv;
162 nsCAutoString key;
163 nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
165 if (!node) {
166 // create a new entry node and set the given entry
167 node = new nsHttpAuthNode();
168 if (!node)
169 return NS_ERROR_OUT_OF_MEMORY;
170 rv = node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
171 if (NS_FAILED(rv))
172 delete node;
173 else
174 PL_HashTableAdd(mDB, nsCRT::strdup(key.get()), node);
175 return rv;
178 return node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
181 void
182 nsHttpAuthCache::ClearAuthEntry(const char *scheme,
183 const char *host,
184 PRInt32 port,
185 const char *realm)
187 if (!mDB)
188 return;
190 nsCAutoString key;
191 GetAuthKey(scheme, host, port, key);
192 PL_HashTableRemove(mDB, key.get());
195 nsresult
196 nsHttpAuthCache::ClearAll()
198 LOG(("nsHttpAuthCache::ClearAll\n"));
200 if (mDB) {
201 PL_HashTableDestroy(mDB);
202 mDB = 0;
204 return NS_OK;
207 //-----------------------------------------------------------------------------
208 // nsHttpAuthCache <private>
209 //-----------------------------------------------------------------------------
211 nsHttpAuthNode *
212 nsHttpAuthCache::LookupAuthNode(const char *scheme,
213 const char *host,
214 PRInt32 port,
215 nsCString &key)
217 if (!mDB)
218 return nsnull;
220 GetAuthKey(scheme, host, port, key);
222 return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
225 void *
226 nsHttpAuthCache::AllocTable(void *self, PRSize size)
228 return malloc(size);
231 void
232 nsHttpAuthCache::FreeTable(void *self, void *item)
234 free(item);
237 PLHashEntry *
238 nsHttpAuthCache::AllocEntry(void *self, const void *key)
240 return (PLHashEntry *) malloc(sizeof(PLHashEntry));
243 void
244 nsHttpAuthCache::FreeEntry(void *self, PLHashEntry *he, PRUintn flag)
246 if (flag == HT_FREE_VALUE) {
247 // this would only happen if PL_HashTableAdd were to replace an
248 // existing entry in the hash table, but we _always_ do a lookup
249 // before adding a new entry to avoid this case.
250 NS_NOTREACHED("should never happen");
252 else if (flag == HT_FREE_ENTRY) {
253 // three wonderful flavors of freeing memory ;-)
254 delete (nsHttpAuthNode *) he->value;
255 nsCRT::free((char *) he->key);
256 free(he);
260 PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
262 nsHttpAuthCache::AllocTable,
263 nsHttpAuthCache::FreeTable,
264 nsHttpAuthCache::AllocEntry,
265 nsHttpAuthCache::FreeEntry
268 //-----------------------------------------------------------------------------
269 // nsHttpAuthIdentity
270 //-----------------------------------------------------------------------------
272 nsresult
273 nsHttpAuthIdentity::Set(const PRUnichar *domain,
274 const PRUnichar *user,
275 const PRUnichar *pass)
277 PRUnichar *newUser, *newPass, *newDomain;
279 int domainLen = domain ? nsCRT::strlen(domain) : 0;
280 int userLen = user ? nsCRT::strlen(user) : 0;
281 int passLen = pass ? nsCRT::strlen(pass) : 0;
283 int len = userLen + 1 + passLen + 1 + domainLen + 1;
284 newUser = (PRUnichar *) malloc(len * sizeof(PRUnichar));
285 if (!newUser)
286 return NS_ERROR_OUT_OF_MEMORY;
288 if (user)
289 memcpy(newUser, user, userLen * sizeof(PRUnichar));
290 newUser[userLen] = 0;
292 newPass = &newUser[userLen + 1];
293 if (pass)
294 memcpy(newPass, pass, passLen * sizeof(PRUnichar));
295 newPass[passLen] = 0;
297 newDomain = &newPass[passLen + 1];
298 if (domain)
299 memcpy(newDomain, domain, domainLen * sizeof(PRUnichar));
300 newDomain[domainLen] = 0;
302 // wait until the end to clear member vars in case input params
303 // reference our members!
304 if (mUser)
305 free(mUser);
306 mUser = newUser;
307 mPass = newPass;
308 mDomain = newDomain;
309 return NS_OK;
312 void
313 nsHttpAuthIdentity::Clear()
315 if (mUser) {
316 free(mUser);
317 mUser = nsnull;
318 mPass = nsnull;
319 mDomain = nsnull;
323 PRBool
324 nsHttpAuthIdentity::Equals(const nsHttpAuthIdentity &ident) const
326 // we could probably optimize this with a single loop, but why bother?
327 return StrEquivalent(mUser, ident.mUser) &&
328 StrEquivalent(mPass, ident.mPass) &&
329 StrEquivalent(mDomain, ident.mDomain);
332 //-----------------------------------------------------------------------------
333 // nsHttpAuthEntry
334 //-----------------------------------------------------------------------------
336 nsHttpAuthEntry::~nsHttpAuthEntry()
338 if (mRealm)
339 free(mRealm);
341 while (mRoot) {
342 nsHttpAuthPath *ap = mRoot;
343 mRoot = mRoot->mNext;
344 free(ap);
348 nsresult
349 nsHttpAuthEntry::AddPath(const char *aPath)
351 // null path matches empty path
352 if (!aPath)
353 aPath = "";
355 nsHttpAuthPath *tempPtr = mRoot;
356 while (tempPtr) {
357 const char *curpath = tempPtr->mPath;
358 if (strncmp(aPath, curpath, nsCRT::strlen(curpath)) == 0)
359 return NS_OK; // subpath already exists in the list
361 tempPtr = tempPtr->mNext;
365 //Append the aPath
366 nsHttpAuthPath *newAuthPath;
367 int newpathLen = nsCRT::strlen(aPath);
368 newAuthPath = (nsHttpAuthPath *) malloc(sizeof(nsHttpAuthPath) + newpathLen);
369 if (!newAuthPath)
370 return NS_ERROR_OUT_OF_MEMORY;
372 memcpy(newAuthPath->mPath, aPath, newpathLen+1);
373 newAuthPath->mNext = nsnull;
375 if (!mRoot)
376 mRoot = newAuthPath; //first entry
377 else
378 mTail->mNext = newAuthPath; // Append newAuthPath
380 //update the tail pointer.
381 mTail = newAuthPath;
382 return NS_OK;
385 nsresult
386 nsHttpAuthEntry::Set(const char *path,
387 const char *realm,
388 const char *creds,
389 const char *chall,
390 const nsHttpAuthIdentity &ident,
391 nsISupports *metadata)
393 char *newRealm, *newCreds, *newChall;
395 int realmLen = realm ? nsCRT::strlen(realm) : 0;
396 int credsLen = creds ? nsCRT::strlen(creds) : 0;
397 int challLen = chall ? nsCRT::strlen(chall) : 0;
399 int len = realmLen + 1 + credsLen + 1 + challLen + 1;
400 newRealm = (char *) malloc(len);
401 if (!newRealm)
402 return NS_ERROR_OUT_OF_MEMORY;
404 if (realm)
405 memcpy(newRealm, realm, realmLen);
406 newRealm[realmLen] = 0;
408 newCreds = &newRealm[realmLen + 1];
409 if (creds)
410 memcpy(newCreds, creds, credsLen);
411 newCreds[credsLen] = 0;
413 newChall = &newCreds[credsLen + 1];
414 if (chall)
415 memcpy(newChall, chall, challLen);
416 newChall[challLen] = 0;
418 nsresult rv = mIdent.Set(ident);
419 if (NS_FAILED(rv)) {
420 free(newRealm);
421 return rv;
424 rv = AddPath(path);
425 if (NS_FAILED(rv)) {
426 free(newRealm);
427 return rv;
430 // wait until the end to clear member vars in case input params
431 // reference our members!
432 if (mRealm)
433 free(mRealm);
435 mRealm = newRealm;
436 mCreds = newCreds;
437 mChallenge = newChall;
438 mMetaData = metadata;
440 return NS_OK;
443 //-----------------------------------------------------------------------------
444 // nsHttpAuthNode
445 //-----------------------------------------------------------------------------
447 nsHttpAuthNode::nsHttpAuthNode()
449 LOG(("Creating nsHttpAuthNode @%x\n", this));
452 nsHttpAuthNode::~nsHttpAuthNode()
454 LOG(("Destroying nsHttpAuthNode @%x\n", this));
456 PRInt32 i;
457 for (i=0; i<mList.Count(); ++i)
458 delete (nsHttpAuthEntry *) mList[i];
459 mList.Clear();
462 nsHttpAuthEntry *
463 nsHttpAuthNode::LookupEntryByPath(const char *path)
465 nsHttpAuthEntry *entry;
467 // null path matches empty path
468 if (!path)
469 path = "";
471 // look for an entry that either matches or contains this directory.
472 // ie. we'll give out credentials if the given directory is a sub-
473 // directory of an existing entry.
474 for (PRInt32 i=0; i<mList.Count(); ++i) {
475 entry = (nsHttpAuthEntry *) mList[i];
476 nsHttpAuthPath *authPath = entry->RootPath();
477 while (authPath) {
478 const char *entryPath = authPath->mPath;
479 // proxy auth entries have no path, so require exact match on
480 // empty path string.
481 if (entryPath[0] == '\0') {
482 if (path[0] == '\0')
483 return entry;
485 else if (strncmp(path, entryPath, nsCRT::strlen(entryPath)) == 0)
486 return entry;
488 authPath = authPath->mNext;
491 return nsnull;
494 nsHttpAuthEntry *
495 nsHttpAuthNode::LookupEntryByRealm(const char *realm)
497 nsHttpAuthEntry *entry;
499 // null realm matches empty realm
500 if (!realm)
501 realm = "";
503 // look for an entry that matches this realm
504 PRInt32 i;
505 for (i=0; i<mList.Count(); ++i) {
506 entry = (nsHttpAuthEntry *) mList[i];
507 if (strcmp(realm, entry->Realm()) == 0)
508 return entry;
510 return nsnull;
513 nsresult
514 nsHttpAuthNode::SetAuthEntry(const char *path,
515 const char *realm,
516 const char *creds,
517 const char *challenge,
518 const nsHttpAuthIdentity &ident,
519 nsISupports *metadata)
521 // look for an entry with a matching realm
522 nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
523 if (!entry) {
524 entry = new nsHttpAuthEntry(path, realm, creds, challenge, ident, metadata);
525 if (!entry)
526 return NS_ERROR_OUT_OF_MEMORY;
527 mList.AppendElement(entry);
529 else {
530 // update the entry...
531 entry->Set(path, realm, creds, challenge, ident, metadata);
534 return NS_OK;
537 void
538 nsHttpAuthNode::ClearAuthEntry(const char *realm)
540 nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
541 if (entry) {
542 mList.RemoveElement(entry); // double search OK
543 delete entry;