~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/netwerk/protocol/http/src/nsHttpAuthCache.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/*
 
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/
 
7
 * 
 
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.
 
12
 * 
 
13
 * The Original Code is Mozilla.
 
14
 * 
 
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
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s): 
 
21
 *   Darin Fisher <darin@netscape.com> (original author)
 
22
 */
 
23
 
 
24
#include <stdlib.h>
 
25
#include "nsHttp.h"
 
26
#include "nsHttpAuthCache.h"
 
27
#include "nsString.h"
 
28
#include "nsCRT.h"
 
29
#include "prprf.h"
 
30
 
 
31
static inline void
 
32
GetAuthKey(const char *scheme, const char *host, PRInt32 port, nsCString &key)
 
33
{
 
34
    key.Assign(nsDependentCString(scheme) +
 
35
               NS_LITERAL_CSTRING("://") +
 
36
               nsDependentCString(host) +
 
37
               NS_LITERAL_CSTRING(":"));
 
38
    key.AppendInt(port);
 
39
}
 
40
 
 
41
// return true if the two strings are equal or both empty.  an empty string
 
42
// is either null or zero length.
 
43
static PRBool
 
44
StrEquivalent(const PRUnichar *a, const PRUnichar *b)
 
45
{
 
46
    static const PRUnichar emptyStr[] = {0};
 
47
 
 
48
    if (!a)
 
49
        a = emptyStr;
 
50
    if (!b)
 
51
        b = emptyStr;
 
52
 
 
53
    return nsCRT::strcmp(a, b) == 0;
 
54
}
 
55
 
 
56
//-----------------------------------------------------------------------------
 
57
// nsHttpAuthCache <public>
 
58
//-----------------------------------------------------------------------------
 
59
 
 
60
nsHttpAuthCache::nsHttpAuthCache()
 
61
    : mDB(nsnull)
 
62
{
 
63
}
 
64
 
 
65
nsHttpAuthCache::~nsHttpAuthCache()
 
66
{
 
67
    if (mDB)
 
68
        ClearAll();
 
69
}
 
70
 
 
71
nsresult
 
72
nsHttpAuthCache::Init()
 
73
{
 
74
    NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED);
 
75
 
 
76
    LOG(("nsHttpAuthCache::Init\n"));
 
77
 
 
78
    mDB = PL_NewHashTable(128, (PLHashFunction) PL_HashString,
 
79
                               (PLHashComparator) PL_CompareStrings,
 
80
                               (PLHashComparator) 0, &gHashAllocOps, this);
 
81
    if (!mDB)
 
82
        return NS_ERROR_OUT_OF_MEMORY;
 
83
 
 
84
    return NS_OK;
 
85
}
 
86
 
 
87
nsresult
 
88
nsHttpAuthCache::GetAuthEntryForPath(const char *scheme,
 
89
                                     const char *host,
 
90
                                     PRInt32     port,
 
91
                                     const char *path,
 
92
                                     nsHttpAuthEntry **entry)
 
93
{
 
94
    LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
 
95
        scheme, host, port, path));
 
96
 
 
97
    nsCAutoString key;
 
98
    nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
 
99
    if (!node)
 
100
        return NS_ERROR_NOT_AVAILABLE;
 
101
 
 
102
    *entry = node->LookupEntryByPath(path);
 
103
    return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
 
104
}
 
105
 
 
106
nsresult
 
107
nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
 
108
                                       const char *host,
 
109
                                       PRInt32     port,
 
110
                                       const char *realm,
 
111
                                       nsHttpAuthEntry **entry)
 
112
 
 
113
{
 
114
    LOG(("nsHttpAuthCache::GetAuthEntryForDomain [key=%s://%s:%d realm=%s]\n",
 
115
        scheme, host, port, realm));
 
116
 
 
117
    nsCAutoString key;
 
118
    nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
 
119
    if (!node)
 
120
        return NS_ERROR_NOT_AVAILABLE;
 
121
 
 
122
    *entry = node->LookupEntryByRealm(realm);
 
123
    return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
 
124
}
 
125
 
 
126
nsresult
 
127
nsHttpAuthCache::SetAuthEntry(const char *scheme,
 
128
                              const char *host,
 
129
                              PRInt32     port,
 
130
                              const char *path,
 
131
                              const char *realm,
 
132
                              const char *creds,
 
133
                              const char *challenge,
 
134
                              const nsHttpAuthIdentity &ident,
 
135
                              nsISupports *metadata)
 
136
{
 
137
    nsresult rv;
 
138
 
 
139
    LOG(("nsHttpAuthCache::SetAuthEntry [key=%s://%s:%d realm=%s path=%s metadata=%x]\n",
 
140
        scheme, host, port, realm, path, metadata));
 
141
 
 
142
    if (!mDB) {
 
143
        rv = Init();
 
144
        if (NS_FAILED(rv)) return rv;
 
145
    }
 
146
 
 
147
    nsCAutoString key;
 
148
    nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, key);
 
149
 
 
150
    if (!node) {
 
151
        // create a new entry node and set the given entry
 
152
        node = new nsHttpAuthNode();
 
153
        if (!node)
 
154
            return NS_ERROR_OUT_OF_MEMORY;
 
155
        rv = node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
 
156
        if (NS_FAILED(rv))
 
157
            delete node;
 
158
        else
 
159
            PL_HashTableAdd(mDB, nsCRT::strdup(key.get()), node);
 
160
        return rv;
 
161
    }
 
162
 
 
163
    return node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
 
164
}
 
165
 
 
166
void
 
167
nsHttpAuthCache::ClearAuthEntry(const char *scheme,
 
168
                                const char *host,
 
169
                                PRInt32     port,
 
170
                                const char *realm)
 
171
{
 
172
    if (!mDB)
 
173
        return;
 
174
 
 
175
    nsCAutoString key;
 
176
    GetAuthKey(scheme, host, port, key);
 
177
    PL_HashTableRemove(mDB, key.get());
 
178
}
 
179
 
 
180
nsresult
 
181
nsHttpAuthCache::ClearAll()
 
182
{
 
183
    LOG(("nsHttpAuthCache::ClearAll\n"));
 
184
 
 
185
    if (mDB) {
 
186
        PL_HashTableDestroy(mDB);
 
187
        mDB = 0;
 
188
    }
 
189
    return NS_OK;
 
190
}
 
191
 
 
192
//-----------------------------------------------------------------------------
 
193
// nsHttpAuthCache <private>
 
194
//-----------------------------------------------------------------------------
 
195
 
 
196
nsHttpAuthNode *
 
197
nsHttpAuthCache::LookupAuthNode(const char *scheme,
 
198
                                const char *host,
 
199
                                PRInt32     port,
 
200
                                nsCString  &key)
 
201
{
 
202
    if (!mDB)
 
203
        return nsnull;
 
204
 
 
205
    GetAuthKey(scheme, host, port, key);
 
206
 
 
207
    return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
 
208
}
 
209
 
 
210
void *
 
211
nsHttpAuthCache::AllocTable(void *self, PRSize size)
 
212
{
 
213
    return malloc(size);
 
214
}
 
215
 
 
216
void
 
217
nsHttpAuthCache::FreeTable(void *self, void *item)
 
218
{
 
219
    free(item);
 
220
}
 
221
 
 
222
PLHashEntry *
 
223
nsHttpAuthCache::AllocEntry(void *self, const void *key)
 
224
{
 
225
    return (PLHashEntry *) malloc(sizeof(PLHashEntry));
 
226
}
 
227
 
 
228
void
 
229
nsHttpAuthCache::FreeEntry(void *self, PLHashEntry *he, PRUintn flag)
 
230
{
 
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");
 
236
    }
 
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);
 
241
        free(he);
 
242
    }
 
243
}
 
244
 
 
245
PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
 
246
{
 
247
    nsHttpAuthCache::AllocTable,
 
248
    nsHttpAuthCache::FreeTable,
 
249
    nsHttpAuthCache::AllocEntry,
 
250
    nsHttpAuthCache::FreeEntry
 
251
};
 
252
 
 
253
//-----------------------------------------------------------------------------
 
254
// nsHttpAuthIdentity
 
255
//-----------------------------------------------------------------------------
 
256
 
 
257
nsresult
 
258
nsHttpAuthIdentity::Set(const PRUnichar *domain,
 
259
                        const PRUnichar *user,
 
260
                        const PRUnichar *pass)
 
261
{
 
262
    PRUnichar *newUser, *newPass, *newDomain;
 
263
 
 
264
    int domainLen = domain ? nsCRT::strlen(domain) : 0;
 
265
    int userLen   = user   ? nsCRT::strlen(user)   : 0;
 
266
    int passLen   = pass   ? nsCRT::strlen(pass)   : 0; 
 
267
 
 
268
    int len = userLen + 1 + passLen + 1 + domainLen + 1;
 
269
    newUser = (PRUnichar *) malloc(len * sizeof(PRUnichar));
 
270
    if (!newUser)
 
271
        return NS_ERROR_OUT_OF_MEMORY;
 
272
 
 
273
    if (user)
 
274
        memcpy(newUser, user, userLen * sizeof(PRUnichar));
 
275
    newUser[userLen] = 0;
 
276
 
 
277
    newPass = &newUser[userLen + 1];
 
278
    if (pass)
 
279
        memcpy(newPass, pass, passLen * sizeof(PRUnichar));
 
280
    newPass[passLen] = 0;
 
281
 
 
282
    newDomain = &newPass[passLen + 1];
 
283
    if (domain)
 
284
        memcpy(newDomain, domain, domainLen * sizeof(PRUnichar));
 
285
    newDomain[domainLen] = 0;
 
286
 
 
287
    // wait until the end to clear member vars in case input params
 
288
    // reference our members!
 
289
    if (mUser)
 
290
        free(mUser);
 
291
    mUser = newUser;
 
292
    mPass = newPass;
 
293
    mDomain = newDomain;
 
294
    return NS_OK;
 
295
}
 
296
 
 
297
void
 
298
nsHttpAuthIdentity::Clear()
 
299
{
 
300
    if (mUser) {
 
301
        free(mUser);
 
302
        mUser = nsnull;
 
303
        mPass = nsnull;
 
304
        mDomain = nsnull;
 
305
    }
 
306
}
 
307
 
 
308
PRBool
 
309
nsHttpAuthIdentity::Equals(const nsHttpAuthIdentity &ident) const
 
310
{
 
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);
 
315
}
 
316
 
 
317
//-----------------------------------------------------------------------------
 
318
// nsHttpAuthEntry
 
319
//-----------------------------------------------------------------------------
 
320
 
 
321
nsHttpAuthEntry::~nsHttpAuthEntry()
 
322
{
 
323
    if (mRealm)
 
324
        free(mRealm);
 
325
 
 
326
    while (mRoot) {
 
327
        nsHttpAuthPath *ap = mRoot;
 
328
        mRoot = mRoot->mNext;
 
329
        free(ap);
 
330
    }
 
331
}
 
332
 
 
333
nsresult
 
334
nsHttpAuthEntry::AddPath(const char *aPath)
 
335
{
 
336
    // null path matches empty path
 
337
    if (!aPath)
 
338
        aPath = "";
 
339
 
 
340
    nsHttpAuthPath *tempPtr = mRoot;
 
341
    while (tempPtr) {
 
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
 
345
 
 
346
        tempPtr = tempPtr->mNext;
 
347
 
 
348
    }
 
349
    
 
350
    //Append the aPath
 
351
    nsHttpAuthPath *newAuthPath;
 
352
    int newpathLen = nsCRT::strlen(aPath);
 
353
    newAuthPath = (nsHttpAuthPath *) malloc(sizeof(nsHttpAuthPath) + newpathLen);
 
354
    if (!newAuthPath)
 
355
        return NS_ERROR_OUT_OF_MEMORY;
 
356
 
 
357
    memcpy(newAuthPath->mPath, aPath, newpathLen+1);
 
358
    newAuthPath->mNext = nsnull;
 
359
 
 
360
    if (!mRoot)
 
361
        mRoot = newAuthPath; //first entry
 
362
    else
 
363
        mTail->mNext = newAuthPath; // Append newAuthPath
 
364
 
 
365
    //update the tail pointer.
 
366
    mTail = newAuthPath;
 
367
    return NS_OK;
 
368
}
 
369
 
 
370
nsresult
 
371
nsHttpAuthEntry::Set(const char *path,
 
372
                     const char *realm,
 
373
                     const char *creds,
 
374
                     const char *chall,
 
375
                     const nsHttpAuthIdentity &ident,
 
376
                     nsISupports *metadata)
 
377
{
 
378
    char *newRealm, *newCreds, *newChall;
 
379
 
 
380
    int realmLen = realm ? nsCRT::strlen(realm) : 0;
 
381
    int credsLen = creds ? nsCRT::strlen(creds) : 0;
 
382
    int challLen = chall ? nsCRT::strlen(chall) : 0;
 
383
 
 
384
    int len = realmLen + 1 + credsLen + 1 + challLen + 1;
 
385
    newRealm = (char *) malloc(len);
 
386
    if (!newRealm)
 
387
        return NS_ERROR_OUT_OF_MEMORY;
 
388
 
 
389
    if (realm)
 
390
        memcpy(newRealm, realm, realmLen);
 
391
    newRealm[realmLen] = 0;
 
392
 
 
393
    newCreds = &newRealm[realmLen + 1];
 
394
    if (creds)
 
395
        memcpy(newCreds, creds, credsLen);
 
396
    newCreds[credsLen] = 0;
 
397
 
 
398
    newChall = &newCreds[credsLen + 1];
 
399
    if (chall)
 
400
        memcpy(newChall, chall, challLen);
 
401
    newChall[challLen] = 0;
 
402
 
 
403
    nsresult rv = mIdent.Set(ident);
 
404
    if (NS_FAILED(rv)) {
 
405
        free(newRealm);
 
406
        return rv;
 
407
    }
 
408
 
 
409
    rv = AddPath(path);
 
410
    if (NS_FAILED(rv)) {
 
411
        free(newRealm);
 
412
        return rv;
 
413
    }
 
414
 
 
415
    // wait until the end to clear member vars in case input params
 
416
    // reference our members!
 
417
    if (mRealm)
 
418
        free(mRealm);
 
419
 
 
420
    mRealm = newRealm;
 
421
    mCreds = newCreds;
 
422
    mChallenge = newChall;
 
423
    mMetaData = metadata;
 
424
 
 
425
    return NS_OK;
 
426
}
 
427
 
 
428
//-----------------------------------------------------------------------------
 
429
// nsHttpAuthNode
 
430
//-----------------------------------------------------------------------------
 
431
 
 
432
nsHttpAuthNode::nsHttpAuthNode()
 
433
{
 
434
    LOG(("Creating nsHttpAuthNode @%x\n", this));
 
435
}
 
436
 
 
437
nsHttpAuthNode::~nsHttpAuthNode()
 
438
{
 
439
    LOG(("Destroying nsHttpAuthNode @%x\n", this));
 
440
 
 
441
    PRInt32 i;
 
442
    for (i=0; i<mList.Count(); ++i)
 
443
        delete (nsHttpAuthEntry *) mList[i];
 
444
    mList.Clear();
 
445
}
 
446
 
 
447
nsHttpAuthEntry *
 
448
nsHttpAuthNode::LookupEntryByPath(const char *path)
 
449
{
 
450
    nsHttpAuthEntry *entry;
 
451
 
 
452
    // null path matches empty path
 
453
    if (!path)
 
454
        path = "";
 
455
 
 
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();
 
462
        while (authPath) {
 
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') {
 
467
                if (path[0] == '\0')
 
468
                    return entry;
 
469
            }
 
470
            else if (strncmp(path, entryPath, nsCRT::strlen(entryPath)) == 0)
 
471
                return entry;
 
472
 
 
473
            authPath = authPath->mNext;
 
474
        }
 
475
    }
 
476
    return nsnull;
 
477
}
 
478
 
 
479
nsHttpAuthEntry *
 
480
nsHttpAuthNode::LookupEntryByRealm(const char *realm)
 
481
{
 
482
    nsHttpAuthEntry *entry;
 
483
 
 
484
    // null realm matches empty realm
 
485
    if (!realm)
 
486
        realm = "";
 
487
 
 
488
    // look for an entry that matches this realm
 
489
    PRInt32 i;
 
490
    for (i=0; i<mList.Count(); ++i) {
 
491
        entry = (nsHttpAuthEntry *) mList[i];
 
492
        if (strcmp(realm, entry->Realm()) == 0)
 
493
            return entry;
 
494
    }
 
495
    return nsnull;
 
496
}
 
497
 
 
498
nsresult
 
499
nsHttpAuthNode::SetAuthEntry(const char *path,
 
500
                             const char *realm,
 
501
                             const char *creds,
 
502
                             const char *challenge,
 
503
                             const nsHttpAuthIdentity &ident,
 
504
                             nsISupports *metadata)
 
505
{
 
506
    // look for an entry with a matching realm
 
507
    nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
 
508
    if (!entry) {
 
509
        entry = new nsHttpAuthEntry(path, realm, creds, challenge, ident, metadata);
 
510
        if (!entry)
 
511
            return NS_ERROR_OUT_OF_MEMORY;
 
512
        mList.AppendElement(entry);
 
513
    }
 
514
    else {
 
515
        // update the entry...
 
516
        entry->Set(path, realm, creds, challenge, ident, metadata);
 
517
    }
 
518
 
 
519
    return NS_OK;
 
520
}
 
521
 
 
522
void
 
523
nsHttpAuthNode::ClearAuthEntry(const char *realm)
 
524
{
 
525
    nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
 
526
    if (entry) {
 
527
        mList.RemoveElement(entry); // double search OK
 
528
        delete entry;
 
529
    }
 
530
}