blob: e40a42b7ead74c7787c21bc5a4802416c5e777df [file] [log] [blame]
/*
* Copyright (C) 2012 Research In Motion Limited. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "AuthenticationChallengeManager.h"
#include "Credential.h"
#include "KURL.h"
#include "PageClientBlackBerry.h"
#include "ProtectionSpace.h"
#include <BlackBerryPlatformAssert.h>
#include <BlackBerryPlatformLog.h>
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
#include <wtf/text/CString.h>
namespace WebCore {
typedef HashMap<PageClientBlackBerry*, bool> PageVisibilityMap;
struct ChallengeInfo {
ChallengeInfo(const KURL&, const ProtectionSpace&, const Credential&, AuthenticationChallengeClient*, PageClientBlackBerry*);
KURL url;
ProtectionSpace space;
Credential credential;
AuthenticationChallengeClient* authClient;
PageClientBlackBerry* pageClient;
bool blocked;
};
ChallengeInfo::ChallengeInfo(const KURL& aUrl,
const ProtectionSpace& aSpace,
const Credential& aCredential,
AuthenticationChallengeClient* anAuthClient,
PageClientBlackBerry* aPageClient)
: url(aUrl)
, space(aSpace)
, credential(aCredential)
, authClient(anAuthClient)
, pageClient(aPageClient)
, blocked(false)
{
}
class AuthenticationChallengeManagerPrivate {
public:
AuthenticationChallengeManagerPrivate();
bool resumeAuthenticationChallenge(PageClientBlackBerry*);
void startAuthenticationChallenge(ChallengeInfo*);
bool pageExists(PageClientBlackBerry*);
ChallengeInfo* m_activeChallenge;
PageVisibilityMap m_pageVisibilityMap;
Vector<OwnPtr<ChallengeInfo> > m_challenges;
};
AuthenticationChallengeManagerPrivate::AuthenticationChallengeManagerPrivate()
: m_activeChallenge(0)
{
}
bool AuthenticationChallengeManagerPrivate::resumeAuthenticationChallenge(PageClientBlackBerry* client)
{
ASSERT(!m_activeChallenge);
for (size_t i = 0; i < m_challenges.size(); ++i) {
if (m_challenges[i]->pageClient == client && m_challenges[i]->blocked) {
startAuthenticationChallenge(m_challenges[i].get());
return true;
}
}
return false;
}
void AuthenticationChallengeManagerPrivate::startAuthenticationChallenge(ChallengeInfo* info)
{
m_activeChallenge = info;
m_activeChallenge->blocked = false;
m_activeChallenge->pageClient->authenticationChallenge(m_activeChallenge->url,
m_activeChallenge->space,
m_activeChallenge->credential);
}
bool AuthenticationChallengeManagerPrivate::pageExists(PageClientBlackBerry* client)
{
return m_pageVisibilityMap.find(client) != m_pageVisibilityMap.end();
}
AuthenticationChallengeManager::AuthenticationChallengeManager()
: d(adoptPtr(new AuthenticationChallengeManagerPrivate))
{
}
void AuthenticationChallengeManager::pageCreated(PageClientBlackBerry* client)
{
d->m_pageVisibilityMap.add(client, true);
}
void AuthenticationChallengeManager::pageDeleted(PageClientBlackBerry* client)
{
d->m_pageVisibilityMap.remove(client);
if (d->m_activeChallenge && d->m_activeChallenge->pageClient == client)
d->m_activeChallenge = 0;
Vector<OwnPtr<ChallengeInfo> > existing;
d->m_challenges.swap(existing);
for (size_t i = 0; i < existing.size(); ++i) {
if (existing[i]->pageClient != client)
d->m_challenges.append(existing[i].release());
}
}
void AuthenticationChallengeManager::pageVisibilityChanged(PageClientBlackBerry* client, bool visible)
{
PageVisibilityMap::iterator iter = d->m_pageVisibilityMap.find(client);
ASSERT(iter != d->m_pageVisibilityMap.end());
if (iter == d->m_pageVisibilityMap.end()) {
d->m_pageVisibilityMap.add(client, visible);
return;
}
if (iter->second == visible)
return;
iter->second = visible;
if (!visible)
return;
if (d->m_activeChallenge)
return;
d->resumeAuthenticationChallenge(client);
}
void AuthenticationChallengeManager::authenticationChallenge(const KURL& url,
const ProtectionSpace& space,
const Credential& credential,
AuthenticationChallengeClient* authClient,
PageClientBlackBerry* pageClient)
{
BLACKBERRY_ASSERT(authClient);
BLACKBERRY_ASSERT(pageClient);
ChallengeInfo* info = new ChallengeInfo(url, space, credential, authClient, pageClient);
d->m_challenges.append(adoptPtr(info));
if (d->m_activeChallenge || !pageClient->isVisible()) {
info->blocked = true;
return;
}
d->startAuthenticationChallenge(info);
}
void AuthenticationChallengeManager::cancelAuthenticationChallenge(AuthenticationChallengeClient* client)
{
BLACKBERRY_ASSERT(client);
if (d->m_activeChallenge && d->m_activeChallenge->authClient == client)
d->m_activeChallenge = 0;
Vector<OwnPtr<ChallengeInfo> > existing;
d->m_challenges.swap(existing);
ChallengeInfo* next = 0;
PageClientBlackBerry* page = 0;
for (size_t i = 0; i < existing.size(); ++i) {
if (existing[i]->authClient != client) {
if (page && !next && existing[i]->pageClient == page)
next = existing[i].get();
d->m_challenges.append(existing[i].release());
} else if (d->m_activeChallenge == existing[i].get())
page = existing[i]->pageClient;
}
if (next)
d->startAuthenticationChallenge(next);
}
void AuthenticationChallengeManager::notifyChallengeResult(const KURL& url,
const ProtectionSpace& space,
AuthenticationChallengeResult result,
const Credential& credential)
{
d->m_activeChallenge = 0;
Vector<OwnPtr<ChallengeInfo> > existing;
d->m_challenges.swap(existing);
ChallengeInfo* next = 0;
PageClientBlackBerry* page = 0;
for (size_t i = 0; i < existing.size(); ++i) {
if (existing[i]->space != space) {
if (page && !next && existing[i]->pageClient == page)
next = existing[i].get();
d->m_challenges.append(existing[i].release());
} else {
page = existing[i]->pageClient;
existing[i]->authClient->notifyChallengeResult(existing[i]->url, space, result, credential);
// After calling notifyChallengeResult(), page could be destroyed or something.
if (!d->pageExists(page) || !page->isVisible())
page = 0;
}
}
if (next)
d->startAuthenticationChallenge(next);
}
// Keep following code at the end of this file!!!
static AuthenticationChallengeManager* s_manager = 0;
AuthenticationChallengeManager* AuthenticationChallengeManager::instance()
{
ASSERT(s_manager);
return s_manager;
}
void AuthenticationChallengeManager::init()
{
ASSERT(!s_manager);
s_manager = new AuthenticationChallengeManager();
}
// No more code after this line, all new code should come before s_manager declaration!!!
} // namespace WebCore