2 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "CredentialStorage.h"
29 #include "Credential.h"
31 #include "ProtectionSpaceHash.h"
32 #include <wtf/text/WTFString.h>
33 #include <wtf/text/StringHash.h>
34 #include <wtf/HashMap.h>
35 #include <wtf/HashSet.h>
36 #include <wtf/MainThread.h>
37 #include <wtf/StdLibExtras.h>
41 typedef HashMap<ProtectionSpace, Credential> ProtectionSpaceToCredentialMap;
42 static ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap()
44 ASSERT(isMainThread());
45 DEFINE_STATIC_LOCAL(ProtectionSpaceToCredentialMap, map, ());
49 static HashSet<String>& originsWithCredentials()
51 ASSERT(isMainThread());
52 DEFINE_STATIC_LOCAL(HashSet<String>, set, ());
56 typedef HashMap<String, ProtectionSpace> PathToDefaultProtectionSpaceMap;
57 static PathToDefaultProtectionSpaceMap& pathToDefaultProtectionSpaceMap()
59 ASSERT(isMainThread());
60 DEFINE_STATIC_LOCAL(PathToDefaultProtectionSpaceMap, map, ());
64 static String originStringFromURL(const KURL& url)
67 return url.protocol() + "://" + url.host() + ':' + String::number(url.port()) + '/';
69 return url.protocol() + "://" + url.host() + '/';
72 static String protectionSpaceMapKeyFromURL(const KURL& url)
74 ASSERT(url.isValid());
76 // Remove the last path component that is not a directory to determine the subtree for which credentials will apply.
77 // We keep a leading slash, but remove a trailing one.
78 String directoryURL = url.string().substring(0, url.pathEnd());
79 unsigned directoryURLPathStart = url.pathStart();
80 ASSERT(directoryURL[directoryURLPathStart] == '/');
81 if (directoryURL.length() > directoryURLPathStart + 1) {
82 size_t index = directoryURL.reverseFind('/');
83 ASSERT(index != notFound);
84 directoryURL = directoryURL.substring(0, (index != directoryURLPathStart) ? index : directoryURLPathStart + 1);
90 void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url)
92 ASSERT(protectionSpace.isProxy() || url.protocolIsInHTTPFamily());
93 ASSERT(protectionSpace.isProxy() || url.isValid());
95 protectionSpaceToCredentialMap().set(protectionSpace, credential);
96 if (!protectionSpace.isProxy()) {
97 originsWithCredentials().add(originStringFromURL(url));
99 ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme();
100 if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) {
101 // The map can contain both a path and its subpath - while redundant, this makes lookups faster.
102 pathToDefaultProtectionSpaceMap().set(protectionSpaceMapKeyFromURL(url), protectionSpace);
107 Credential CredentialStorage::get(const ProtectionSpace& protectionSpace)
109 return protectionSpaceToCredentialMap().get(protectionSpace);
112 void CredentialStorage::remove(const ProtectionSpace& protectionSpace)
114 protectionSpaceToCredentialMap().remove(protectionSpace);
117 static PathToDefaultProtectionSpaceMap::iterator findDefaultProtectionSpaceForURL(const KURL& url)
119 ASSERT(url.protocolIsInHTTPFamily());
120 ASSERT(url.isValid());
122 PathToDefaultProtectionSpaceMap& map = pathToDefaultProtectionSpaceMap();
124 // Don't spend time iterating the path for origins that don't have any credentials.
125 if (!originsWithCredentials().contains(originStringFromURL(url)))
128 String directoryURL = protectionSpaceMapKeyFromURL(url);
129 unsigned directoryURLPathStart = url.pathStart();
131 PathToDefaultProtectionSpaceMap::iterator iter = map.find(directoryURL);
132 if (iter != map.end())
135 if (directoryURL.length() == directoryURLPathStart + 1) // path is "/" already, cannot shorten it any more
138 size_t index = directoryURL.reverseFind('/', directoryURL.length() - 2);
139 ASSERT(index != notFound);
140 directoryURL = directoryURL.substring(0, (index == directoryURLPathStart) ? index + 1 : index);
141 ASSERT(directoryURL.length() > directoryURLPathStart);
142 ASSERT(directoryURL.length() == directoryURLPathStart + 1 || directoryURL[directoryURL.length() - 1] != '/');
146 bool CredentialStorage::set(const Credential& credential, const KURL& url)
148 ASSERT(url.protocolIsInHTTPFamily());
149 ASSERT(url.isValid());
150 PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
151 if (iter == pathToDefaultProtectionSpaceMap().end())
153 ASSERT(originsWithCredentials().contains(originStringFromURL(url)));
154 protectionSpaceToCredentialMap().set(iter->value, credential);
158 Credential CredentialStorage::get(const KURL& url)
160 PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
161 if (iter == pathToDefaultProtectionSpaceMap().end())
163 return protectionSpaceToCredentialMap().get(iter->value);
166 void CredentialStorage::setPrivateMode(bool mode)
169 protectionSpaceToCredentialMap().clear();
172 } // namespace WebCore