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
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.
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 ***** */
41 #include "nsHttpAuthCache.h"
47 GetAuthKey(const char *scheme
, const char *host
, PRInt32 port
, nsCString
&key
)
50 key
.AppendLiteral("://");
56 // return true if the two strings are equal or both empty. an empty string
57 // is either null or zero length.
59 StrEquivalent(const PRUnichar
*a
, const PRUnichar
*b
)
61 static const PRUnichar emptyStr
[] = {0};
68 return nsCRT::strcmp(a
, b
) == 0;
71 //-----------------------------------------------------------------------------
72 // nsHttpAuthCache <public>
73 //-----------------------------------------------------------------------------
75 nsHttpAuthCache::nsHttpAuthCache()
80 nsHttpAuthCache::~nsHttpAuthCache()
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);
97 return NS_ERROR_OUT_OF_MEMORY
;
103 nsHttpAuthCache::GetAuthEntryForPath(const char *scheme
,
107 nsHttpAuthEntry
**entry
)
109 LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
110 scheme
, host
, port
, path
));
113 nsHttpAuthNode
*node
= LookupAuthNode(scheme
, host
, port
, key
);
115 return NS_ERROR_NOT_AVAILABLE
;
117 *entry
= node
->LookupEntryByPath(path
);
118 return *entry
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
122 nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme
,
126 nsHttpAuthEntry
**entry
)
129 LOG(("nsHttpAuthCache::GetAuthEntryForDomain [key=%s://%s:%d realm=%s]\n",
130 scheme
, host
, port
, realm
));
133 nsHttpAuthNode
*node
= LookupAuthNode(scheme
, host
, port
, key
);
135 return NS_ERROR_NOT_AVAILABLE
;
137 *entry
= node
->LookupEntryByRealm(realm
);
138 return *entry
? NS_OK
: NS_ERROR_NOT_AVAILABLE
;
142 nsHttpAuthCache::SetAuthEntry(const char *scheme
,
148 const char *challenge
,
149 const nsHttpAuthIdentity
&ident
,
150 nsISupports
*metadata
)
154 LOG(("nsHttpAuthCache::SetAuthEntry [key=%s://%s:%d realm=%s path=%s metadata=%x]\n",
155 scheme
, host
, port
, realm
, path
, metadata
));
159 if (NS_FAILED(rv
)) return rv
;
163 nsHttpAuthNode
*node
= LookupAuthNode(scheme
, host
, port
, key
);
166 // create a new entry node and set the given entry
167 node
= new nsHttpAuthNode();
169 return NS_ERROR_OUT_OF_MEMORY
;
170 rv
= node
->SetAuthEntry(path
, realm
, creds
, challenge
, ident
, metadata
);
174 PL_HashTableAdd(mDB
, nsCRT::strdup(key
.get()), node
);
178 return node
->SetAuthEntry(path
, realm
, creds
, challenge
, ident
, metadata
);
182 nsHttpAuthCache::ClearAuthEntry(const char *scheme
,
191 GetAuthKey(scheme
, host
, port
, key
);
192 PL_HashTableRemove(mDB
, key
.get());
196 nsHttpAuthCache::ClearAll()
198 LOG(("nsHttpAuthCache::ClearAll\n"));
201 PL_HashTableDestroy(mDB
);
207 //-----------------------------------------------------------------------------
208 // nsHttpAuthCache <private>
209 //-----------------------------------------------------------------------------
212 nsHttpAuthCache::LookupAuthNode(const char *scheme
,
220 GetAuthKey(scheme
, host
, port
, key
);
222 return (nsHttpAuthNode
*) PL_HashTableLookup(mDB
, key
.get());
226 nsHttpAuthCache::AllocTable(void *self
, PRSize size
)
232 nsHttpAuthCache::FreeTable(void *self
, void *item
)
238 nsHttpAuthCache::AllocEntry(void *self
, const void *key
)
240 return (PLHashEntry
*) malloc(sizeof(PLHashEntry
));
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
);
260 PLHashAllocOps
nsHttpAuthCache::gHashAllocOps
=
262 nsHttpAuthCache::AllocTable
,
263 nsHttpAuthCache::FreeTable
,
264 nsHttpAuthCache::AllocEntry
,
265 nsHttpAuthCache::FreeEntry
268 //-----------------------------------------------------------------------------
269 // nsHttpAuthIdentity
270 //-----------------------------------------------------------------------------
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
));
286 return NS_ERROR_OUT_OF_MEMORY
;
289 memcpy(newUser
, user
, userLen
* sizeof(PRUnichar
));
290 newUser
[userLen
] = 0;
292 newPass
= &newUser
[userLen
+ 1];
294 memcpy(newPass
, pass
, passLen
* sizeof(PRUnichar
));
295 newPass
[passLen
] = 0;
297 newDomain
= &newPass
[passLen
+ 1];
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!
313 nsHttpAuthIdentity::Clear()
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 //-----------------------------------------------------------------------------
334 //-----------------------------------------------------------------------------
336 nsHttpAuthEntry::~nsHttpAuthEntry()
342 nsHttpAuthPath
*ap
= mRoot
;
343 mRoot
= mRoot
->mNext
;
349 nsHttpAuthEntry::AddPath(const char *aPath
)
351 // null path matches empty path
355 nsHttpAuthPath
*tempPtr
= mRoot
;
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
;
366 nsHttpAuthPath
*newAuthPath
;
367 int newpathLen
= nsCRT::strlen(aPath
);
368 newAuthPath
= (nsHttpAuthPath
*) malloc(sizeof(nsHttpAuthPath
) + newpathLen
);
370 return NS_ERROR_OUT_OF_MEMORY
;
372 memcpy(newAuthPath
->mPath
, aPath
, newpathLen
+1);
373 newAuthPath
->mNext
= nsnull
;
376 mRoot
= newAuthPath
; //first entry
378 mTail
->mNext
= newAuthPath
; // Append newAuthPath
380 //update the tail pointer.
386 nsHttpAuthEntry::Set(const char *path
,
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
);
402 return NS_ERROR_OUT_OF_MEMORY
;
405 memcpy(newRealm
, realm
, realmLen
);
406 newRealm
[realmLen
] = 0;
408 newCreds
= &newRealm
[realmLen
+ 1];
410 memcpy(newCreds
, creds
, credsLen
);
411 newCreds
[credsLen
] = 0;
413 newChall
= &newCreds
[credsLen
+ 1];
415 memcpy(newChall
, chall
, challLen
);
416 newChall
[challLen
] = 0;
418 nsresult rv
= mIdent
.Set(ident
);
430 // wait until the end to clear member vars in case input params
431 // reference our members!
437 mChallenge
= newChall
;
438 mMetaData
= metadata
;
443 //-----------------------------------------------------------------------------
445 //-----------------------------------------------------------------------------
447 nsHttpAuthNode::nsHttpAuthNode()
449 LOG(("Creating nsHttpAuthNode @%x\n", this));
452 nsHttpAuthNode::~nsHttpAuthNode()
454 LOG(("Destroying nsHttpAuthNode @%x\n", this));
457 for (i
=0; i
<mList
.Count(); ++i
)
458 delete (nsHttpAuthEntry
*) mList
[i
];
463 nsHttpAuthNode::LookupEntryByPath(const char *path
)
465 nsHttpAuthEntry
*entry
;
467 // null path matches empty 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();
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') {
485 else if (strncmp(path
, entryPath
, nsCRT::strlen(entryPath
)) == 0)
488 authPath
= authPath
->mNext
;
495 nsHttpAuthNode::LookupEntryByRealm(const char *realm
)
497 nsHttpAuthEntry
*entry
;
499 // null realm matches empty realm
503 // look for an entry that matches this realm
505 for (i
=0; i
<mList
.Count(); ++i
) {
506 entry
= (nsHttpAuthEntry
*) mList
[i
];
507 if (strcmp(realm
, entry
->Realm()) == 0)
514 nsHttpAuthNode::SetAuthEntry(const char *path
,
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
);
524 entry
= new nsHttpAuthEntry(path
, realm
, creds
, challenge
, ident
, metadata
);
526 return NS_ERROR_OUT_OF_MEMORY
;
527 mList
.AppendElement(entry
);
530 // update the entry...
531 entry
->Set(path
, realm
, creds
, challenge
, ident
, metadata
);
538 nsHttpAuthNode::ClearAuthEntry(const char *realm
)
540 nsHttpAuthEntry
*entry
= LookupEntryByRealm(realm
);
542 mList
.RemoveElement(entry
); // double search OK