1231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block/* 2231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2009 Apple Inc. All Rights Reserved. 3231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 4231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Redistribution and use in source and binary forms, with or without 5231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * modification, are permitted provided that the following conditions 6231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * are met: 7231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 1. Redistributions of source code must retain the above copyright 8231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * notice, this list of conditions and the following disclaimer. 9231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 2. Redistributions in binary form must reproduce the above copyright 10231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * notice, this list of conditions and the following disclaimer in the 11231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * documentation and/or other materials provided with the distribution. 12231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 13231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block */ 25231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 26231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "config.h" 27231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "CredentialStorage.h" 28231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 29231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Credential.h" 30231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "KURL.h" 31231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ProtectionSpaceHash.h" 32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/text/StringConcatenate.h> 33f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include <wtf/text/StringHash.h> 34d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <wtf/HashMap.h> 35d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <wtf/HashSet.h> 36231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <wtf/StdLibExtras.h> 37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 38231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocknamespace WebCore { 39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 40231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktypedef HashMap<ProtectionSpace, Credential> ProtectionSpaceToCredentialMap; 41231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap() 42231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block DEFINE_STATIC_LOCAL(ProtectionSpaceToCredentialMap, map, ()); 44231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return map; 45231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 46231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 47cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockstatic HashSet<String>& originsWithCredentials() 48231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 49cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block DEFINE_STATIC_LOCAL(HashSet<String>, set, ()); 50cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return set; 51cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block} 52cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 53cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blocktypedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap; 54cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockstatic PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap() 55cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{ 56cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block DEFINE_STATIC_LOCAL(PathToDefaultProtectionSpaceMap, map, ()); 57231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return map; 58231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 59cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 60231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockstatic String originStringFromURL(const KURL& url) 61231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 62231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (url.port()) 63a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return makeString(url.protocol(), "://", url.host(), ':', String::number(url.port()), '/'); 64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return makeString(url.protocol(), "://", url.host(), '/'); 66231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 67231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 68cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockstatic String protectionSpaceMapKeyFromURL(const KURL& url) 69cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{ 70cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(url.isValid()); 71cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 72cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // Remove the last path component that is not a directory to determine the subtree for which credentials will apply. 73cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // We keep a leading slash, but remove a trailing one. 74cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block String directoryURL = url.string().substring(0, url.pathEnd()); 75cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block unsigned directoryURLPathStart = url.pathStart(); 76cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(directoryURL[directoryURLPathStart] == '/'); 77cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (directoryURL.length() > directoryURLPathStart + 1) { 78f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick size_t index = directoryURL.reverseFind('/'); 79f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick ASSERT(index != notFound); 80f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick directoryURL = directoryURL.substring(0, (index != directoryURLPathStart) ? index : directoryURLPathStart + 1); 81cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block } 82cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 83cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return directoryURL; 84cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block} 85cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 86231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url) 87231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 88643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ASSERT(protectionSpace.isProxy() || url.protocolInHTTPFamily()); 89643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ASSERT(protectionSpace.isProxy() || url.isValid()); 90231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 91231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block protectionSpaceToCredentialMap().set(protectionSpace, credential); 92643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if (!protectionSpace.isProxy()) { 93643ca7872b450ea4efacab6188849e5aac2ba161Steve Block originsWithCredentials().add(originStringFromURL(url)); 94643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 95643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); 96643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) { 97643ca7872b450ea4efacab6188849e5aac2ba161Steve Block // The map can contain both a path and its subpath - while redundant, this makes lookups faster. 98643ca7872b450ea4efacab6188849e5aac2ba161Steve Block pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace); 99643ca7872b450ea4efacab6188849e5aac2ba161Steve Block } 100231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 101231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 102231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 103231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockCredential CredentialStorage::get(const ProtectionSpace& protectionSpace) 104231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 105231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return protectionSpaceToCredentialMap().get(protectionSpace); 106231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 107231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 108967717af5423377c967781471ee106e2bb4e11c8Ben Murdochvoid CredentialStorage::remove(const ProtectionSpace& protectionSpace) 109967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 110967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch protectionSpaceToCredentialMap().remove(protectionSpace); 111967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch} 112967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 113cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockstatic PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const KURL& url) 114231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 115231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT(url.protocolInHTTPFamily()); 116cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(url.isValid()); 117cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 118cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block PathToDefaultProtectionSpaceMap& map = pathToDefaultProtectionSpaceMap(); 119cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 120cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // Don't spend time iterating the path for origins that don't have any credentials. 121cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (!originsWithCredentials().contains(originStringFromURL(url))) 122cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return map.end(); 123cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 124cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block String directoryURL = protectionSpaceMapKeyFromURL(url); 125cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block unsigned directoryURLPathStart = url.pathStart(); 126cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block while (true) { 127cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block PathToDefaultProtectionSpaceMap::iterator iter = map.find(directoryURL); 128cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (iter != map.end()) 129cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return iter; 130cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 131cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (directoryURL.length() == directoryURLPathStart + 1) // path is "/" already, cannot shorten it any more 132cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return map.end(); 133cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 134f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick size_t index = directoryURL.reverseFind('/', directoryURL.length() - 2); 135f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick ASSERT(index != notFound); 136f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick directoryURL = directoryURL.substring(0, (index == directoryURLPathStart) ? index + 1 : index); 137cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(directoryURL.length() > directoryURLPathStart); 138cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/'); 139231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 140cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block} 141cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 142cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Blockbool CredentialStorage::set(const Credential& credential, const KURL& url) 143cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{ 144cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(url.protocolInHTTPFamily()); 145cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(url.isValid()); 146cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url); 147cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (iter == pathToDefaultProtectionSpaceMap().end()) 148cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return false; 149cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block ASSERT(originsWithCredentials().contains(originStringFromURL(url))); 150cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block protectionSpaceToCredentialMap().set(iter->second, credential); 151cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return true; 152cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block} 153cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block 154cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve BlockCredential CredentialStorage::get(const KURL& url) 155cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block{ 156cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url); 157cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (iter == pathToDefaultProtectionSpaceMap().end()) 158cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return Credential(); 159cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block return protectionSpaceToCredentialMap().get(iter->second); 160231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 161231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 162231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} // namespace WebCore 163