b9af422aef2efab48b4949f9b634f5097093f87c
[WebKit-https.git] / Source / WebCore / platform / network / CredentialStorage.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "CredentialStorage.h"
28
29 #include "NetworkStorageSession.h"
30 #include <wtf/URL.h>
31
32 #if PLATFORM(IOS_FAMILY)
33 #include "WebCoreThread.h"
34 #endif
35
36 namespace WebCore {
37
38 CredentialStorage& CredentialStorage::defaultCredentialStorage()
39 {
40     return NetworkStorageSession::defaultStorageSession().credentialStorage();
41 }
42
43 static String originStringFromURL(const URL& url)
44 {
45     return makeString(url.protocol(), "://", url.hostAndPort(), '/');
46 }
47
48 static String protectionSpaceMapKeyFromURL(const URL& url)
49 {
50     ASSERT(url.isValid());
51
52     // Remove the last path component that is not a directory to determine the subtree for which credentials will apply.
53     // We keep a leading slash, but remove a trailing one.
54     String directoryURL = url.string().substring(0, url.pathEnd());
55     unsigned directoryURLPathStart = url.pathStart();
56     ASSERT(directoryURL[directoryURLPathStart] == '/');
57     if (directoryURL.length() > directoryURLPathStart + 1) {
58         size_t index = directoryURL.reverseFind('/');
59         ASSERT(index != notFound);
60         directoryURL = directoryURL.substring(0, (index != directoryURLPathStart) ? index : directoryURLPathStart + 1);
61     }
62
63     return directoryURL;
64 }
65
66 void CredentialStorage::set(const String& partitionName, const Credential& credential, const ProtectionSpace& protectionSpace, const URL& url)
67 {
68     ASSERT(protectionSpace.isProxy() || protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeClientCertificateRequested || url.protocolIsInHTTPFamily());
69     ASSERT(protectionSpace.isProxy() || protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeClientCertificateRequested || url.isValid());
70
71     m_protectionSpaceToCredentialMap.set(std::make_pair(partitionName, protectionSpace), credential);
72
73     if (!protectionSpace.isProxy() && protectionSpace.authenticationScheme() != ProtectionSpaceAuthenticationSchemeClientCertificateRequested) {
74         m_originsWithCredentials.add(originStringFromURL(url));
75
76         ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme();
77         if (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault) {
78             // The map can contain both a path and its subpath - while redundant, this makes lookups faster.
79             m_pathToDefaultProtectionSpaceMap.set(protectionSpaceMapKeyFromURL(url), protectionSpace);
80         }
81     }
82 }
83
84 Credential CredentialStorage::get(const String& partitionName, const ProtectionSpace& protectionSpace)
85 {
86     return m_protectionSpaceToCredentialMap.get(std::make_pair(partitionName, protectionSpace));
87 }
88
89 void CredentialStorage::remove(const String& partitionName, const ProtectionSpace& protectionSpace)
90 {
91     m_protectionSpaceToCredentialMap.remove(std::make_pair(partitionName, protectionSpace));
92 }
93
94 HashMap<String, ProtectionSpace>::iterator CredentialStorage::findDefaultProtectionSpaceForURL(const URL& url)
95 {
96     ASSERT(url.protocolIsInHTTPFamily());
97     ASSERT(url.isValid());
98
99     // Don't spend time iterating the path for origins that don't have any credentials.
100     if (!m_originsWithCredentials.contains(originStringFromURL(url)))
101         return m_pathToDefaultProtectionSpaceMap.end();
102
103     String directoryURL = protectionSpaceMapKeyFromURL(url);
104     unsigned directoryURLPathStart = url.pathStart();
105     while (true) {
106         PathToDefaultProtectionSpaceMap::iterator iter = m_pathToDefaultProtectionSpaceMap.find(directoryURL);
107         if (iter != m_pathToDefaultProtectionSpaceMap.end())
108             return iter;
109
110         if (directoryURL.length() == directoryURLPathStart + 1)  // path is "/" already, cannot shorten it any more
111             return m_pathToDefaultProtectionSpaceMap.end();
112
113         size_t index = directoryURL.reverseFind('/', directoryURL.length() - 2);
114         ASSERT(index != notFound);
115         directoryURL = directoryURL.substring(0, (index == directoryURLPathStart) ? index + 1 : index);
116         ASSERT(directoryURL.length() > directoryURLPathStart);
117     }
118 }
119
120 bool CredentialStorage::set(const String& partitionName, const Credential& credential, const URL& url)
121 {
122     ASSERT(url.protocolIsInHTTPFamily());
123     ASSERT(url.isValid());
124     PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
125     if (iter == m_pathToDefaultProtectionSpaceMap.end())
126         return false;
127     ASSERT(m_originsWithCredentials.contains(originStringFromURL(url)));
128     m_protectionSpaceToCredentialMap.set(std::make_pair(partitionName, iter->value), credential);
129     return true;
130 }
131
132 Credential CredentialStorage::get(const String& partitionName, const URL& url)
133 {
134     PathToDefaultProtectionSpaceMap::iterator iter = findDefaultProtectionSpaceForURL(url);
135     if (iter == m_pathToDefaultProtectionSpaceMap.end())
136         return Credential();
137     return m_protectionSpaceToCredentialMap.get(std::make_pair(partitionName, iter->value));
138 }
139
140 void CredentialStorage::clearCredentials()
141 {
142     m_protectionSpaceToCredentialMap.clear();
143     m_originsWithCredentials.clear();
144     m_pathToDefaultProtectionSpaceMap.clear();
145 }
146
147 } // namespace WebCore