netwerk/protocol/http/nsHttpAuthCache.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // HttpLog.h should generally be included first
     7 #include "HttpLog.h"
     9 #include "nsHttpAuthCache.h"
    11 #include <stdlib.h>
    13 #include "mozilla/Attributes.h"
    14 #include "nsString.h"
    15 #include "nsCRT.h"
    16 #include "mozIApplicationClearPrivateDataParams.h"
    17 #include "nsIObserverService.h"
    18 #include "mozilla/Services.h"
    19 #include "nsNetUtil.h"
    21 namespace mozilla {
    22 namespace net {
    24 static inline void
    25 GetAuthKey(const char *scheme, const char *host, int32_t port, uint32_t appId, bool inBrowserElement, nsCString &key)
    26 {
    27     key.Truncate();
    28     key.AppendInt(appId);
    29     key.Append(':');
    30     key.AppendInt(inBrowserElement);
    31     key.Append(':');
    32     key.Append(scheme);
    33     key.AppendLiteral("://");
    34     key.Append(host);
    35     key.Append(':');
    36     key.AppendInt(port);
    37 }
    39 // return true if the two strings are equal or both empty.  an empty string
    40 // is either null or zero length.
    41 static bool
    42 StrEquivalent(const char16_t *a, const char16_t *b)
    43 {
    44     static const char16_t emptyStr[] = {0};
    46     if (!a)
    47         a = emptyStr;
    48     if (!b)
    49         b = emptyStr;
    51     return nsCRT::strcmp(a, b) == 0;
    52 }
    54 //-----------------------------------------------------------------------------
    55 // nsHttpAuthCache <public>
    56 //-----------------------------------------------------------------------------
    58 nsHttpAuthCache::nsHttpAuthCache()
    59     : mDB(nullptr)
    60     , mObserver(new AppDataClearObserver(MOZ_THIS_IN_INITIALIZER_LIST()))
    61 {
    62     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
    63     if (obsSvc) {
    64         obsSvc->AddObserver(mObserver, "webapps-clear-data", false);
    65     }
    66 }
    68 nsHttpAuthCache::~nsHttpAuthCache()
    69 {
    70     if (mDB)
    71         ClearAll();
    72     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
    73     if (obsSvc) {
    74         obsSvc->RemoveObserver(mObserver, "webapps-clear-data");
    75         mObserver->mOwner = nullptr;
    76     }
    77 }
    79 nsresult
    80 nsHttpAuthCache::Init()
    81 {
    82     NS_ENSURE_TRUE(!mDB, NS_ERROR_ALREADY_INITIALIZED);
    84     LOG(("nsHttpAuthCache::Init\n"));
    86     mDB = PL_NewHashTable(128, (PLHashFunction) PL_HashString,
    87                                (PLHashComparator) PL_CompareStrings,
    88                                (PLHashComparator) 0, &gHashAllocOps, this);
    89     if (!mDB)
    90         return NS_ERROR_OUT_OF_MEMORY;
    92     return NS_OK;
    93 }
    95 nsresult
    96 nsHttpAuthCache::GetAuthEntryForPath(const char *scheme,
    97                                      const char *host,
    98                                      int32_t     port,
    99                                      const char *path,
   100                                      uint32_t    appId,
   101                                      bool        inBrowserElement,
   102                                      nsHttpAuthEntry **entry)
   103 {
   104     LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
   105         scheme, host, port, path));
   107     nsAutoCString key;
   108     nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
   109     if (!node)
   110         return NS_ERROR_NOT_AVAILABLE;
   112     *entry = node->LookupEntryByPath(path);
   113     return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   114 }
   116 nsresult
   117 nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
   118                                        const char *host,
   119                                        int32_t     port,
   120                                        const char *realm,
   121                                        uint32_t    appId,
   122                                        bool        inBrowserElement,
   123                                        nsHttpAuthEntry **entry)
   125 {
   126     LOG(("nsHttpAuthCache::GetAuthEntryForDomain [key=%s://%s:%d realm=%s]\n",
   127         scheme, host, port, realm));
   129     nsAutoCString key;
   130     nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
   131     if (!node)
   132         return NS_ERROR_NOT_AVAILABLE;
   134     *entry = node->LookupEntryByRealm(realm);
   135     return *entry ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   136 }
   138 nsresult
   139 nsHttpAuthCache::SetAuthEntry(const char *scheme,
   140                               const char *host,
   141                               int32_t     port,
   142                               const char *path,
   143                               const char *realm,
   144                               const char *creds,
   145                               const char *challenge,
   146                               uint32_t    appId,
   147                               bool        inBrowserElement,
   148                               const nsHttpAuthIdentity *ident,
   149                               nsISupports *metadata)
   150 {
   151     nsresult rv;
   153     LOG(("nsHttpAuthCache::SetAuthEntry [key=%s://%s:%d realm=%s path=%s metadata=%x]\n",
   154         scheme, host, port, realm, path, metadata));
   156     if (!mDB) {
   157         rv = Init();
   158         if (NS_FAILED(rv)) return rv;
   159     }
   161     nsAutoCString key;
   162     nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
   164     if (!node) {
   165         // create a new entry node and set the given entry
   166         node = new nsHttpAuthNode();
   167         if (!node)
   168             return NS_ERROR_OUT_OF_MEMORY;
   169         rv = node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
   170         if (NS_FAILED(rv))
   171             delete node;
   172         else
   173             PL_HashTableAdd(mDB, strdup(key.get()), node);
   174         return rv;
   175     }
   177     return node->SetAuthEntry(path, realm, creds, challenge, ident, metadata);
   178 }
   180 void
   181 nsHttpAuthCache::ClearAuthEntry(const char *scheme,
   182                                 const char *host,
   183                                 int32_t     port,
   184                                 const char *realm,
   185                                 uint32_t    appId,
   186                                 bool        inBrowserElement)
   187 {
   188     if (!mDB)
   189         return;
   191     nsAutoCString key;
   192     GetAuthKey(scheme, host, port, appId, inBrowserElement, key);
   193     PL_HashTableRemove(mDB, key.get());
   194 }
   196 nsresult
   197 nsHttpAuthCache::ClearAll()
   198 {
   199     LOG(("nsHttpAuthCache::ClearAll\n"));
   201     if (mDB) {
   202         PL_HashTableDestroy(mDB);
   203         mDB = 0;
   204     }
   205     return NS_OK;
   206 }
   208 //-----------------------------------------------------------------------------
   209 // nsHttpAuthCache <private>
   210 //-----------------------------------------------------------------------------
   212 nsHttpAuthNode *
   213 nsHttpAuthCache::LookupAuthNode(const char *scheme,
   214                                 const char *host,
   215                                 int32_t     port,
   216                                 uint32_t    appId,
   217                                 bool        inBrowserElement,
   218                                 nsCString  &key)
   219 {
   220     if (!mDB)
   221         return nullptr;
   223     GetAuthKey(scheme, host, port, appId, inBrowserElement, key);
   225     return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
   226 }
   228 void *
   229 nsHttpAuthCache::AllocTable(void *self, size_t size)
   230 {
   231     return malloc(size);
   232 }
   234 void
   235 nsHttpAuthCache::FreeTable(void *self, void *item)
   236 {
   237     free(item);
   238 }
   240 PLHashEntry *
   241 nsHttpAuthCache::AllocEntry(void *self, const void *key)
   242 {
   243     return (PLHashEntry *) malloc(sizeof(PLHashEntry));
   244 }
   246 void
   247 nsHttpAuthCache::FreeEntry(void *self, PLHashEntry *he, unsigned flag)
   248 {
   249     if (flag == HT_FREE_VALUE) {
   250         // this would only happen if PL_HashTableAdd were to replace an
   251         // existing entry in the hash table, but we _always_ do a lookup
   252         // before adding a new entry to avoid this case.
   253         NS_NOTREACHED("should never happen");
   254     }
   255     else if (flag == HT_FREE_ENTRY) {
   256         // three wonderful flavors of freeing memory ;-)
   257         delete (nsHttpAuthNode *) he->value;
   258         free((char *) he->key);
   259         free(he);
   260     }
   261 }
   263 PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
   264 {
   265     nsHttpAuthCache::AllocTable,
   266     nsHttpAuthCache::FreeTable,
   267     nsHttpAuthCache::AllocEntry,
   268     nsHttpAuthCache::FreeEntry
   269 };
   271 NS_IMPL_ISUPPORTS(nsHttpAuthCache::AppDataClearObserver, nsIObserver)
   273 NS_IMETHODIMP
   274 nsHttpAuthCache::AppDataClearObserver::Observe(nsISupports *subject,
   275                                                const char *      topic,
   276                                                const char16_t * data_unicode)
   277 {
   278     NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_AVAILABLE);
   280     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
   281             do_QueryInterface(subject);
   282     if (!params) {
   283         NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
   284         return NS_ERROR_UNEXPECTED;
   285     }
   287     uint32_t appId;
   288     bool browserOnly;
   290     nsresult rv = params->GetAppId(&appId);
   291     NS_ENSURE_SUCCESS(rv, rv);
   292     rv = params->GetBrowserOnly(&browserOnly);
   293     NS_ENSURE_SUCCESS(rv, rv);
   295     MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
   296     mOwner->ClearAppData(appId, browserOnly);
   297     return NS_OK;
   298 }
   300 static int
   301 RemoveEntriesForApp(PLHashEntry *entry, int32_t number, void *arg)
   302 {
   303     nsDependentCString key(static_cast<const char*>(entry->key));
   304     nsAutoCString* prefix = static_cast<nsAutoCString*>(arg);
   305     if (StringBeginsWith(key, *prefix)) {
   306         return HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE;
   307     }
   308     return HT_ENUMERATE_NEXT;
   309 }
   311 void
   312 nsHttpAuthCache::ClearAppData(uint32_t appId, bool browserOnly)
   313 {
   314     if (!mDB) {
   315         return;
   316     }
   317     nsAutoCString keyPrefix;
   318     keyPrefix.AppendInt(appId);
   319     keyPrefix.Append(':');
   320     if (browserOnly) {
   321         keyPrefix.AppendInt(browserOnly);
   322         keyPrefix.Append(':');
   323     }
   324     PL_HashTableEnumerateEntries(mDB, RemoveEntriesForApp, &keyPrefix);
   325 }
   327 //-----------------------------------------------------------------------------
   328 // nsHttpAuthIdentity
   329 //-----------------------------------------------------------------------------
   331 nsresult
   332 nsHttpAuthIdentity::Set(const char16_t *domain,
   333                         const char16_t *user,
   334                         const char16_t *pass)
   335 {
   336     char16_t *newUser, *newPass, *newDomain;
   338     int domainLen = domain ? NS_strlen(domain) : 0;
   339     int userLen   = user   ? NS_strlen(user)   : 0;
   340     int passLen   = pass   ? NS_strlen(pass)   : 0;
   342     int len = userLen + 1 + passLen + 1 + domainLen + 1;
   343     newUser = (char16_t *) malloc(len * sizeof(char16_t));
   344     if (!newUser)
   345         return NS_ERROR_OUT_OF_MEMORY;
   347     if (user)
   348         memcpy(newUser, user, userLen * sizeof(char16_t));
   349     newUser[userLen] = 0;
   351     newPass = &newUser[userLen + 1];
   352     if (pass)
   353         memcpy(newPass, pass, passLen * sizeof(char16_t));
   354     newPass[passLen] = 0;
   356     newDomain = &newPass[passLen + 1];
   357     if (domain)
   358         memcpy(newDomain, domain, domainLen * sizeof(char16_t));
   359     newDomain[domainLen] = 0;
   361     // wait until the end to clear member vars in case input params
   362     // reference our members!
   363     if (mUser)
   364         free(mUser);
   365     mUser = newUser;
   366     mPass = newPass;
   367     mDomain = newDomain;
   368     return NS_OK;
   369 }
   371 void
   372 nsHttpAuthIdentity::Clear()
   373 {
   374     if (mUser) {
   375         free(mUser);
   376         mUser = nullptr;
   377         mPass = nullptr;
   378         mDomain = nullptr;
   379     }
   380 }
   382 bool
   383 nsHttpAuthIdentity::Equals(const nsHttpAuthIdentity &ident) const
   384 {
   385     // we could probably optimize this with a single loop, but why bother?
   386     return StrEquivalent(mUser, ident.mUser) &&
   387            StrEquivalent(mPass, ident.mPass) &&
   388            StrEquivalent(mDomain, ident.mDomain);
   389 }
   391 //-----------------------------------------------------------------------------
   392 // nsHttpAuthEntry
   393 //-----------------------------------------------------------------------------
   395 nsHttpAuthEntry::~nsHttpAuthEntry()
   396 {
   397     if (mRealm)
   398         free(mRealm);
   400     while (mRoot) {
   401         nsHttpAuthPath *ap = mRoot;
   402         mRoot = mRoot->mNext;
   403         free(ap);
   404     }
   405 }
   407 nsresult
   408 nsHttpAuthEntry::AddPath(const char *aPath)
   409 {
   410     // null path matches empty path
   411     if (!aPath)
   412         aPath = "";
   414     nsHttpAuthPath *tempPtr = mRoot;
   415     while (tempPtr) {
   416         const char *curpath = tempPtr->mPath;
   417         if (strncmp(aPath, curpath, strlen(curpath)) == 0)
   418             return NS_OK; // subpath already exists in the list
   420         tempPtr = tempPtr->mNext;
   422     }
   424     //Append the aPath
   425     nsHttpAuthPath *newAuthPath;
   426     int newpathLen = strlen(aPath);
   427     newAuthPath = (nsHttpAuthPath *) malloc(sizeof(nsHttpAuthPath) + newpathLen);
   428     if (!newAuthPath)
   429         return NS_ERROR_OUT_OF_MEMORY;
   431     memcpy(newAuthPath->mPath, aPath, newpathLen+1);
   432     newAuthPath->mNext = nullptr;
   434     if (!mRoot)
   435         mRoot = newAuthPath; //first entry
   436     else
   437         mTail->mNext = newAuthPath; // Append newAuthPath
   439     //update the tail pointer.
   440     mTail = newAuthPath;
   441     return NS_OK;
   442 }
   444 nsresult
   445 nsHttpAuthEntry::Set(const char *path,
   446                      const char *realm,
   447                      const char *creds,
   448                      const char *chall,
   449                      const nsHttpAuthIdentity *ident,
   450                      nsISupports *metadata)
   451 {
   452     char *newRealm, *newCreds, *newChall;
   454     int realmLen = realm ? strlen(realm) : 0;
   455     int credsLen = creds ? strlen(creds) : 0;
   456     int challLen = chall ? strlen(chall) : 0;
   458     int len = realmLen + 1 + credsLen + 1 + challLen + 1;
   459     newRealm = (char *) malloc(len);
   460     if (!newRealm)
   461         return NS_ERROR_OUT_OF_MEMORY;
   463     if (realm)
   464         memcpy(newRealm, realm, realmLen);
   465     newRealm[realmLen] = 0;
   467     newCreds = &newRealm[realmLen + 1];
   468     if (creds)
   469         memcpy(newCreds, creds, credsLen);
   470     newCreds[credsLen] = 0;
   472     newChall = &newCreds[credsLen + 1];
   473     if (chall)
   474         memcpy(newChall, chall, challLen);
   475     newChall[challLen] = 0;
   477     nsresult rv = NS_OK;
   478     if (ident) {
   479         rv = mIdent.Set(*ident);
   480     }
   481     else if (mIdent.IsEmpty()) {
   482         // If we are not given an identity and our cached identity has not been
   483         // initialized yet (so is currently empty), initialize it now by
   484         // filling it with nulls.  We need to do that because consumers expect
   485         // that mIdent is initialized after this function returns.
   486         rv = mIdent.Set(nullptr, nullptr, nullptr);
   487     }
   488     if (NS_FAILED(rv)) {
   489         free(newRealm);
   490         return rv;
   491     }
   493     rv = AddPath(path);
   494     if (NS_FAILED(rv)) {
   495         free(newRealm);
   496         return rv;
   497     }
   499     // wait until the end to clear member vars in case input params
   500     // reference our members!
   501     if (mRealm)
   502         free(mRealm);
   504     mRealm = newRealm;
   505     mCreds = newCreds;
   506     mChallenge = newChall;
   507     mMetaData = metadata;
   509     return NS_OK;
   510 }
   512 //-----------------------------------------------------------------------------
   513 // nsHttpAuthNode
   514 //-----------------------------------------------------------------------------
   516 nsHttpAuthNode::nsHttpAuthNode()
   517 {
   518     LOG(("Creating nsHttpAuthNode @%x\n", this));
   519 }
   521 nsHttpAuthNode::~nsHttpAuthNode()
   522 {
   523     LOG(("Destroying nsHttpAuthNode @%x\n", this));
   525     mList.Clear();
   526 }
   528 nsHttpAuthEntry *
   529 nsHttpAuthNode::LookupEntryByPath(const char *path)
   530 {
   531     nsHttpAuthEntry *entry;
   533     // null path matches empty path
   534     if (!path)
   535         path = "";
   537     // look for an entry that either matches or contains this directory.
   538     // ie. we'll give out credentials if the given directory is a sub-
   539     // directory of an existing entry.
   540     for (uint32_t i=0; i<mList.Length(); ++i) {
   541         entry = mList[i];
   542         nsHttpAuthPath *authPath = entry->RootPath();
   543         while (authPath) {
   544             const char *entryPath = authPath->mPath;
   545             // proxy auth entries have no path, so require exact match on
   546             // empty path string.
   547             if (entryPath[0] == '\0') {
   548                 if (path[0] == '\0')
   549                     return entry;
   550             }
   551             else if (strncmp(path, entryPath, strlen(entryPath)) == 0)
   552                 return entry;
   554             authPath = authPath->mNext;
   555         }
   556     }
   557     return nullptr;
   558 }
   560 nsHttpAuthEntry *
   561 nsHttpAuthNode::LookupEntryByRealm(const char *realm)
   562 {
   563     nsHttpAuthEntry *entry;
   565     // null realm matches empty realm
   566     if (!realm)
   567         realm = "";
   569     // look for an entry that matches this realm
   570     uint32_t i;
   571     for (i=0; i<mList.Length(); ++i) {
   572         entry = mList[i];
   573         if (strcmp(realm, entry->Realm()) == 0)
   574             return entry;
   575     }
   576     return nullptr;
   577 }
   579 nsresult
   580 nsHttpAuthNode::SetAuthEntry(const char *path,
   581                              const char *realm,
   582                              const char *creds,
   583                              const char *challenge,
   584                              const nsHttpAuthIdentity *ident,
   585                              nsISupports *metadata)
   586 {
   587     // look for an entry with a matching realm
   588     nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
   589     if (!entry) {
   590         entry = new nsHttpAuthEntry(path, realm, creds, challenge, ident, metadata);
   591         if (!entry)
   592             return NS_ERROR_OUT_OF_MEMORY;
   593         mList.AppendElement(entry);
   594     }
   595     else {
   596         // update the entry...
   597         entry->Set(path, realm, creds, challenge, ident, metadata);
   598     }
   600     return NS_OK;
   601 }
   603 void
   604 nsHttpAuthNode::ClearAuthEntry(const char *realm)
   605 {
   606     nsHttpAuthEntry *entry = LookupEntryByRealm(realm);
   607     if (entry) {
   608         mList.RemoveElement(entry); // double search OK
   609     }
   610 }
   612 } // namespace mozilla::net
   613 } // namespace mozilla

mercurial