1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Mozilla.
15
* The Initial Developer of the Original Code is Netscape
16
* Communications. Portions created by Netscape Communications are
17
* Copyright (C) 2001 by Netscape Communications. All
21
* Darin Fisher <darin@netscape.com> (original author)
26
#include "nsHttpAuthCache.h"
32
GetAuthKey(const char *scheme, const char *host, PRInt32 port, nsCString &key)
34
key.Assign(nsDependentCString(scheme) +
35
NS_LITERAL_CSTRING("://") +
36
nsDependentCString(host) +
37
NS_LITERAL_CSTRING(":"));
41
// return true if the two strings are equal or both empty. an empty string
42
// is either null or zero length.
44
StrEquivalent(const PRUnichar *a, const PRUnichar *b)
46
static const PRUnichar emptyStr[] = {0};
53
return nsCRT::strcmp(a, b) == 0;
56
//-----------------------------------------------------------------------------
57
// nsHttpAuthCache <public>
58
//-----------------------------------------------------------------------------
60
nsHttpAuthCache::nsHttpAuthCache()
65
nsHttpAuthCache::~nsHttpAuthCache()
72
nsHttpAuthCache::Init()
74
NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED);
76
LOG(("nsHttpAuthCache::Init\n"));
78
mDB = PL_NewHashTable(128, (PLHashFunction) PL_HashString,
79
(PLHashComparator) PL_CompareStrings,
80
(PLHashComparator) 0, &gHashAllocOps, this);
82
return NS_ERROR_OUT_OF_MEMORY;
88
nsHttpAuthCache::GetAuthEntryForPath(const char *scheme,
92
nsHttpAuthEntry **entry)
94
LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
95
scheme, host, port, path));
98
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
100
return NS_ERROR_NOT_AVAILABLE;
102
*entry = node->LookupEntryByPath(path);
103
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
107
nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
111
nsHttpAuthEntry **entry)
114
LOG(("nsHttpAuthCache::GetAuthEntryForDomain [key=%s://%s:%d realm=%s]\n",
115
scheme, host, port, realm));
118
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
120
return NS_ERROR_NOT_AVAILABLE;
122
*entry = node->LookupEntryByRealm(realm);
123
return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
127
nsHttpAuthCache::SetAuthEntry(const char *scheme,
133
const char *challenge,
134
const nsHttpAuthIdentity &ident,
135
nsISupports *metadata)
139
LOG(("nsHttpAuthCache::SetAuthEntry [key=%s://%s:%d realm=%s path=%s metadata=%x]\n",
140
scheme, host, port, realm, path, metadata));
144
if (NS_FAILED(rv)) return rv;
148
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
151
// create a new entry node and set the given entry
152
node = new nsHttpAuthNode();
154
return NS_ERROR_OUT_OF_MEMORY;
155
rv = node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
159
PL_HashTableAdd(mDB, nsCRT::strdup(key.get()), node);
163
return node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
167
nsHttpAuthCache::ClearAuthEntry(const char *scheme,
176
GetAuthKey(scheme, host, port, key);
177
PL_HashTableRemove(mDB, key.get());
181
nsHttpAuthCache::ClearAll()
183
LOG(("nsHttpAuthCache::ClearAll\n"));
186
PL_HashTableDestroy(mDB);
192
//-----------------------------------------------------------------------------
193
// nsHttpAuthCache <private>
194
//-----------------------------------------------------------------------------
197
nsHttpAuthCache::LookupAuthNode(const char *scheme,
205
GetAuthKey(scheme, host, port, key);
207
return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
211
nsHttpAuthCache::AllocTable(void *self, PRSize size)
217
nsHttpAuthCache::FreeTable(void *self, void *item)
223
nsHttpAuthCache::AllocEntry(void *self, const void *key)
225
return (PLHashEntry *) malloc(sizeof(PLHashEntry));
229
nsHttpAuthCache::FreeEntry(void *self, PLHashEntry *he, PRUintn flag)
231
if (flag == HT_FREE_VALUE) {
232
// this would only happen if PL_HashTableAdd were to replace an
233
// existing entry in the hash table, but we _always_ do a lookup
234
// before adding a new entry to avoid this case.
235
NS_NOTREACHED("should never happen");
237
else if (flag == HT_FREE_ENTRY) {
238
// three wonderful flavors of freeing memory ;-)
239
delete (nsHttpAuthNode *) he->value;
240
nsCRT::free((char *) he->key);
245
PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
247
nsHttpAuthCache::AllocTable,
248
nsHttpAuthCache::FreeTable,
249
nsHttpAuthCache::AllocEntry,
250
nsHttpAuthCache::FreeEntry
253
//-----------------------------------------------------------------------------
254
// nsHttpAuthIdentity
255
//-----------------------------------------------------------------------------
258
nsHttpAuthIdentity::Set(const PRUnichar *domain,
259
const PRUnichar *user,
260
const PRUnichar *pass)
262
PRUnichar *newUser, *newPass, *newDomain;
264
int domainLen = domain ? nsCRT::strlen(domain) : 0;
265
int userLen = user ? nsCRT::strlen(user) : 0;
266
int passLen = pass ? nsCRT::strlen(pass) : 0;
268
int len = userLen + 1 + passLen + 1 + domainLen + 1;
269
newUser = (PRUnichar *) malloc(len * sizeof(PRUnichar));
271
return NS_ERROR_OUT_OF_MEMORY;
274
memcpy(newUser, user, userLen * sizeof(PRUnichar));
275
newUser[userLen] = 0;
277
newPass = &newUser[userLen + 1];
279
memcpy(newPass, pass, passLen * sizeof(PRUnichar));
280
newPass[passLen] = 0;
282
newDomain = &newPass[passLen + 1];
284
memcpy(newDomain, domain, domainLen * sizeof(PRUnichar));
285
newDomain[domainLen] = 0;
287
// wait until the end to clear member vars in case input params
288
// reference our members!
298
nsHttpAuthIdentity::Clear()
309
nsHttpAuthIdentity::Equals(const nsHttpAuthIdentity &ident) const
311
// we could probably optimize this with a single loop, but why bother?
312
return StrEquivalent(mUser, ident.mUser) &&
313
StrEquivalent(mPass, ident.mPass) &&
314
StrEquivalent(mDomain, ident.mDomain);
317
//-----------------------------------------------------------------------------
319
//-----------------------------------------------------------------------------
321
nsHttpAuthEntry::~nsHttpAuthEntry()
327
nsHttpAuthPath *ap = mRoot;
328
mRoot = mRoot->mNext;
334
nsHttpAuthEntry::AddPath(const char *aPath)
336
// null path matches empty path
340
nsHttpAuthPath *tempPtr = mRoot;
342
const char *curpath = tempPtr->mPath;
343
if (strncmp(aPath, curpath, nsCRT::strlen(curpath)) == 0)
344
return NS_OK; // subpath already exists in the list
346
tempPtr = tempPtr->mNext;
351
nsHttpAuthPath *newAuthPath;
352
int newpathLen = nsCRT::strlen(aPath);
353
newAuthPath = (nsHttpAuthPath *) malloc(sizeof(nsHttpAuthPath) + newpathLen);
355
return NS_ERROR_OUT_OF_MEMORY;
357
memcpy(newAuthPath->mPath, aPath, newpathLen+1);
358
newAuthPath->mNext = nsnull;
361
mRoot = newAuthPath; //first entry
363
mTail->mNext = newAuthPath; // Append newAuthPath
365
//update the tail pointer.
371
nsHttpAuthEntry::Set(const char *path,
375
const nsHttpAuthIdentity &ident,
376
nsISupports *metadata)
378
char *newRealm, *newCreds, *newChall;
380
int realmLen = realm ? nsCRT::strlen(realm) : 0;
381
int credsLen = creds ? nsCRT::strlen(creds) : 0;
382
int challLen = chall ? nsCRT::strlen(chall) : 0;
384
int len = realmLen + 1 + credsLen + 1 + challLen + 1;
385
newRealm = (char *) malloc(len);
387
return NS_ERROR_OUT_OF_MEMORY;
390
memcpy(newRealm, realm, realmLen);
391
newRealm[realmLen] = 0;
393
newCreds = &newRealm[realmLen + 1];
395
memcpy(newCreds, creds, credsLen);
396
newCreds[credsLen] = 0;
398
newChall = &newCreds[credsLen + 1];
400
memcpy(newChall, chall, challLen);
401
newChall[challLen] = 0;
403
nsresult rv = mIdent.Set(ident);
415
// wait until the end to clear member vars in case input params
416
// reference our members!
422
mChallenge = newChall;
423
mMetaData = metadata;
428
//-----------------------------------------------------------------------------
430
//-----------------------------------------------------------------------------
432
nsHttpAuthNode::nsHttpAuthNode()
434
LOG(("Creating nsHttpAuthNode @%x\n", this));
437
nsHttpAuthNode::~nsHttpAuthNode()
439
LOG(("Destroying nsHttpAuthNode @%x\n", this));
442
for (i=0; i<mList.Count(); ++i)
443
delete (nsHttpAuthEntry *) mList[i];
448
nsHttpAuthNode::LookupEntryByPath(const char *path)
450
nsHttpAuthEntry *entry;
452
// null path matches empty path
456
// look for an entry that either matches or contains this directory.
457
// ie. we'll give out credentials if the given directory is a sub-
458
// directory of an existing entry.
459
for (PRInt32 i=0; i<mList.Count(); ++i) {
460
entry = (nsHttpAuthEntry *) mList[i];
461
nsHttpAuthPath *authPath = entry->RootPath();
463
const char *entryPath = authPath->mPath;
464
// proxy auth entries have no path, so require exact match on
465
// empty path string.
466
if (entryPath[0] == '\0') {
470
else if (strncmp(path, entryPath, nsCRT::strlen(entryPath)) == 0)
473
authPath = authPath->mNext;
480
nsHttpAuthNode::LookupEntryByRealm(const char *realm)
482
nsHttpAuthEntry *entry;
484
// null realm matches empty realm
488
// look for an entry that matches this realm
490
for (i=0; i<mList.Count(); ++i) {
491
entry = (nsHttpAuthEntry *) mList[i];
492
if (strcmp(realm, entry->Realm()) == 0)
499
nsHttpAuthNode::SetAuthEntry(const char *path,
502
const char *challenge,
503
const nsHttpAuthIdentity &ident,
504
nsISupports *metadata)
506
// look for an entry with a matching realm
507
nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
509
entry = new nsHttpAuthEntry(path, realm, creds, challenge, ident, metadata);
511
return NS_ERROR_OUT_OF_MEMORY;
512
mList.AppendElement(entry);
515
// update the entry...
516
entry->Set(path, realm, creds, challenge, ident, metadata);
523
nsHttpAuthNode::ClearAuthEntry(const char *realm)
525
nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
527
mList.RemoveElement(entry); // double search OK