diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp | 656 |
1 files changed, 0 insertions, 656 deletions
diff --git a/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp b/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp deleted file mode 100644 index 516c533..0000000 --- a/src/3rdparty/webkit/WebCore/page/SecurityOrigin.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "SecurityOrigin.h" - -#include "CString.h" -#include "Document.h" -#include "KURL.h" -#include "OriginAccessEntry.h" -#include <wtf/StdLibExtras.h> - -namespace WebCore { - -static SecurityOrigin::LocalLoadPolicy localLoadPolicy = SecurityOrigin::AllowLocalLoadsForLocalOnly; - -typedef Vector<OriginAccessEntry> OriginAccessWhiteList; -typedef HashMap<String, OriginAccessWhiteList*> OriginAccessMap; - -static OriginAccessMap& originAccessMap() -{ - DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ()); - return originAccessMap; -} - -static URLSchemesMap& localSchemes() -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ()); - - if (localSchemes.isEmpty()) { - localSchemes.add("file"); -#if PLATFORM(MAC) - localSchemes.add("applewebdata"); -#endif -#if PLATFORM(QT) - localSchemes.add("qrc"); -#endif - } - - return localSchemes; -} - -static URLSchemesMap& secureSchemes() -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, secureSchemes, ()); - - if (secureSchemes.isEmpty()) { - secureSchemes.add("https"); - secureSchemes.add("about"); - secureSchemes.add("data"); - } - - return secureSchemes; -} - -static URLSchemesMap& schemesWithUniqueOrigins() -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, schemesWithUniqueOrigins, ()); - - // This is a willful violation of HTML5. - // See https://bugs.webkit.org/show_bug.cgi?id=11885 - if (schemesWithUniqueOrigins.isEmpty()) - schemesWithUniqueOrigins.add("data"); - - return schemesWithUniqueOrigins; -} - -static bool schemeRequiresAuthority(const String& scheme) -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, schemes, ()); - - if (schemes.isEmpty()) { - schemes.add("http"); - schemes.add("https"); - schemes.add("ftp"); - } - - return schemes.contains(scheme); -} - - -SecurityOrigin::SecurityOrigin(const KURL& url, SandboxFlags sandboxFlags) - : m_sandboxFlags(sandboxFlags) - , m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) - , m_host(url.host().isNull() ? "" : url.host().lower()) - , m_port(url.port()) - , m_isUnique(isSandboxed(SandboxOrigin) || shouldTreatURLSchemeAsNoAccess(m_protocol)) - , m_universalAccess(false) - , m_domainWasSetInDOM(false) -{ - // These protocols do not create security origins; the owner frame provides the origin - if (m_protocol == "about" || m_protocol == "javascript") - m_protocol = ""; - - // For edge case URLs that were probably misparsed, make sure that the origin is unique. - if (schemeRequiresAuthority(m_protocol) && m_host.isEmpty()) - m_isUnique = true; - - // document.domain starts as m_host, but can be set by the DOM. - m_domain = m_host; - - // By default, only local SecurityOrigins can load local resources. - m_canLoadLocalResources = isLocal(); - if (m_canLoadLocalResources) { - // Directories should never be readable. - if (!url.hasPath() || url.path().endsWith("/")) - m_isUnique = true; - } - - if (isDefaultPortForProtocol(m_port, m_protocol)) - m_port = 0; -} - -SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) - : m_sandboxFlags(other->m_sandboxFlags) - , m_protocol(other->m_protocol.threadsafeCopy()) - , m_host(other->m_host.threadsafeCopy()) - , m_encodedHost(other->m_encodedHost.threadsafeCopy()) - , m_domain(other->m_domain.threadsafeCopy()) - , m_port(other->m_port) - , m_isUnique(other->m_isUnique) - , m_universalAccess(other->m_universalAccess) - , m_domainWasSetInDOM(other->m_domainWasSetInDOM) - , m_canLoadLocalResources(other->m_canLoadLocalResources) -{ -} - -bool SecurityOrigin::isEmpty() const -{ - return m_protocol.isEmpty(); -} - -PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url, SandboxFlags sandboxFlags) -{ - if (!url.isValid()) - return adoptRef(new SecurityOrigin(KURL(), sandboxFlags)); - return adoptRef(new SecurityOrigin(url, sandboxFlags)); -} - -PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty() -{ - return create(KURL()); -} - -PassRefPtr<SecurityOrigin> SecurityOrigin::threadsafeCopy() -{ - return adoptRef(new SecurityOrigin(this)); -} - -void SecurityOrigin::setDomainFromDOM(const String& newDomain) -{ - m_domainWasSetInDOM = true; - m_domain = newDomain.lower(); -} - -static HashSet<String>& schemesForbiddenFromDomainRelaxation() -{ - DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ()); - return schemes; -} - -void SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme) -{ - if (scheme.isEmpty()) - return; - - if (forbidden) - schemesForbiddenFromDomainRelaxation().add(scheme); - else - schemesForbiddenFromDomainRelaxation().remove(scheme); -} - -bool SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(const String& scheme) -{ - if (scheme.isEmpty()) - return false; - - return schemesForbiddenFromDomainRelaxation().contains(scheme); -} - -bool SecurityOrigin::canAccess(const SecurityOrigin* other) const -{ - if (m_universalAccess) - return true; - - if (isUnique() || other->isUnique()) - return false; - - // Here are two cases where we should permit access: - // - // 1) Neither document has set document.domain. In this case, we insist - // that the scheme, host, and port of the URLs match. - // - // 2) Both documents have set document.domain. In this case, we insist - // that the documents have set document.domain to the same value and - // that the scheme of the URLs match. - // - // This matches the behavior of Firefox 2 and Internet Explorer 6. - // - // Internet Explorer 7 and Opera 9 are more strict in that they require - // the port numbers to match when both pages have document.domain set. - // - // FIXME: Evaluate whether we can tighten this policy to require matched - // port numbers. - // - // Opera 9 allows access when only one page has set document.domain, but - // this is a security vulnerability. - - if (m_protocol == other->m_protocol) { - if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) { - if (m_host == other->m_host && m_port == other->m_port) - return true; - } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) { - if (m_domain == other->m_domain) - return true; - } - } - - return false; -} - -bool SecurityOrigin::canRequest(const KURL& url) const -{ - if (m_universalAccess) - return true; - - if (isUnique()) - return false; - - RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); - if (targetOrigin->isUnique()) - return false; - - // We call isSameSchemeHostPort here instead of canAccess because we want - // to ignore document.domain effects. - if (isSameSchemeHostPort(targetOrigin.get())) - return true; - - if (OriginAccessWhiteList* list = originAccessMap().get(toString())) { - for (size_t i = 0; i < list->size(); ++i) { - if (list->at(i).matchesOrigin(*targetOrigin)) - return true; - } - } - - return false; -} - -bool SecurityOrigin::taintsCanvas(const KURL& url) const -{ - if (canRequest(url)) - return false; - - // This function exists because we treat data URLs as having a unique origin, - // contrary to the current (9/19/2009) draft of the HTML5 specification. - // We still want to let folks paint data URLs onto untainted canvases, so - // we special case data URLs below. If we change to match HTML5 w.r.t. - // data URL security, then we can remove this function in favor of - // !canRequest. - if (url.protocolIs("data")) - return false; - - return true; -} - -bool SecurityOrigin::canLoad(const KURL& url, const String& referrer, Document* document) -{ - if (!shouldTreatURLAsLocal(url.string())) - return true; - - // If we were provided a document, we let its local file policy dictate the result, - // otherwise we allow local loads only if the supplied referrer is also local. - if (document) - return document->securityOrigin()->canLoadLocalResources(); - if (!referrer.isEmpty()) - return shouldTreatURLAsLocal(referrer); - return false; -} - -void SecurityOrigin::grantLoadLocalResources() -{ - // This function exists only to support backwards compatibility with older - // versions of WebKit. Granting privileges to some, but not all, documents - // in a SecurityOrigin is a security hazard because the documents without - // the privilege can obtain the privilege by injecting script into the - // documents that have been granted the privilege. - ASSERT(allowSubstituteDataAccessToLocal()); - m_canLoadLocalResources = true; -} - -void SecurityOrigin::grantUniversalAccess() -{ - m_universalAccess = true; -} - -void SecurityOrigin::makeUnique() -{ - m_isUnique = true; -} - -bool SecurityOrigin::isLocal() const -{ - return shouldTreatURLSchemeAsLocal(m_protocol); -} - -bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const -{ - // New window created by the application - if (isEmpty()) - return true; - - RefPtr<SecurityOrigin> other = SecurityOrigin::create(url); - return canAccess(other.get()); -} - -String SecurityOrigin::toString() const -{ - if (isEmpty()) - return "null"; - - if (isUnique()) - return "null"; - - if (m_protocol == "file") - return String("file://"); - - Vector<UChar> result; - result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10); - append(result, m_protocol); - append(result, "://"); - append(result, m_host); - - if (m_port) { - append(result, ":"); - append(result, String::number(m_port)); - } - - return String::adopt(result); -} - -PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString) -{ - return SecurityOrigin::create(KURL(KURL(), originString)); -} - -static const char SeparatorCharacter = '_'; - -PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier) -{ - // Make sure there's a first separator - int separator1 = databaseIdentifier.find(SeparatorCharacter); - if (separator1 == -1) - return create(KURL()); - - // Make sure there's a second separator - int separator2 = databaseIdentifier.reverseFind(SeparatorCharacter); - if (separator2 == -1) - return create(KURL()); - - // Ensure there were at least 2 separator characters. Some hostnames on intranets have - // underscores in them, so we'll assume that any additional underscores are part of the host. - if (separator1 == separator2) - return create(KURL()); - - // Make sure the port section is a valid port number or doesn't exist - bool portOkay; - int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay); - bool portAbsent = (separator2 == static_cast<int>(databaseIdentifier.length()) - 1); - if (!(portOkay || portAbsent)) - return create(KURL()); - - if (port < 0 || port > 65535) - return create(KURL()); - - // Split out the 3 sections of data - String protocol = databaseIdentifier.substring(0, separator1); - String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1); - - host = decodeURLEscapeSequences(host); - return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port))); -} - -// The following lower-ASCII characters need escaping to be used in a filename -// across all systems, including Windows: -// - Unprintable ASCII (00-1F) -// - Space (20) -// - Double quote (22) -// - Percent (25) (escaped because it is our escape character) -// - Asterisk (2A) -// - Slash (2F) -// - Colon (3A) -// - Less-than (3C) -// - Greater-than (3E) -// - Question Mark (3F) -// - Backslash (5C) -// - Pipe (7C) -// - Delete (7F) - -static const bool needsEscaping[128] = { - /* 00-07 */ true, true, true, true, true, true, true, true, - /* 08-0F */ true, true, true, true, true, true, true, true, - - /* 10-17 */ true, true, true, true, true, true, true, true, - /* 18-1F */ true, true, true, true, true, true, true, true, - - /* 20-27 */ true, false, true, false, false, true, false, false, - /* 28-2F */ false, false, true, false, false, false, false, true, - - /* 30-37 */ false, false, false, false, false, false, false, false, - /* 38-3F */ false, false, true, false, true, false, true, true, - - /* 40-47 */ false, false, false, false, false, false, false, false, - /* 48-4F */ false, false, false, false, false, false, false, false, - - /* 50-57 */ false, false, false, false, false, false, false, false, - /* 58-5F */ false, false, false, false, true, false, false, false, - - /* 60-67 */ false, false, false, false, false, false, false, false, - /* 68-6F */ false, false, false, false, false, false, false, false, - - /* 70-77 */ false, false, false, false, false, false, false, false, - /* 78-7F */ false, false, false, false, true, false, false, true, -}; - -static inline bool shouldEscapeUChar(UChar c) -{ - return c > 127 ? false : needsEscaping[c]; -} - -static const char hexDigits[17] = "0123456789ABCDEF"; - -static String encodedHost(const String& host) -{ - unsigned length = host.length(); - Vector<UChar, 512> buffer(length * 3 + 1); - UChar* p = buffer.data(); - - const UChar* str = host.characters(); - const UChar* strEnd = str + length; - - while (str < strEnd) { - UChar c = *str++; - if (shouldEscapeUChar(c)) { - *p++ = '%'; - *p++ = hexDigits[(c >> 4) & 0xF]; - *p++ = hexDigits[c & 0xF]; - } else - *p++ = c; - } - - ASSERT(p - buffer.data() <= static_cast<int>(buffer.size())); - - return String(buffer.data(), p - buffer.data()); -} - -String SecurityOrigin::databaseIdentifier() const -{ - String separatorString(&SeparatorCharacter, 1); - - if (m_encodedHost.isEmpty()) - m_encodedHost = encodedHost(m_host); - - return m_protocol + separatorString + m_encodedHost + separatorString + String::number(m_port); -} - -bool SecurityOrigin::equal(const SecurityOrigin* other) const -{ - if (other == this) - return true; - - if (!isSameSchemeHostPort(other)) - return false; - - if (m_domainWasSetInDOM != other->m_domainWasSetInDOM) - return false; - - if (m_domainWasSetInDOM && m_domain != other->m_domain) - return false; - - return true; -} - -bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const -{ - if (m_host != other->m_host) - return false; - - if (m_protocol != other->m_protocol) - return false; - - if (m_port != other->m_port) - return false; - - return true; -} - -void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme) -{ - localSchemes().add(scheme); -} - -void SecurityOrigin::removeURLSchemeRegisteredAsLocal(const String& scheme) -{ - if (scheme == "file") - return; -#if PLATFORM(MAC) - if (scheme == "applewebdata") - return; -#endif - localSchemes().remove(scheme); -} - -const URLSchemesMap& SecurityOrigin::localURLSchemes() -{ - return localSchemes(); -} - -bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (url.length() >= 5) { - const UChar* s = url.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':') - return true; - } - - int loc = url.find(':'); - if (loc == -1) - return false; - - String scheme = url.left(loc); - return localSchemes().contains(scheme); -} - -bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (scheme.length() == 4) { - const UChar* s = scheme.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') - return true; - } - - if (scheme.isEmpty()) - return false; - - return localSchemes().contains(scheme); -} - -void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme) -{ - schemesWithUniqueOrigins().add(scheme); -} - -bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme) -{ - return schemesWithUniqueOrigins().contains(scheme); -} - -void SecurityOrigin::registerURLSchemeAsSecure(const String& scheme) -{ - secureSchemes().add(scheme); -} - -bool SecurityOrigin::shouldTreatURLSchemeAsSecure(const String& scheme) -{ - return secureSchemes().contains(scheme); -} - -bool SecurityOrigin::shouldHideReferrer(const KURL& url, const String& referrer) -{ - bool referrerIsSecureURL = protocolIs(referrer, "https"); - bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); - - if (!referrerIsWebURL) - return true; - - if (!referrerIsSecureURL) - return false; - - bool URLIsSecureURL = url.protocolIs("https"); - - return !URLIsSecureURL; -} - -void SecurityOrigin::setLocalLoadPolicy(LocalLoadPolicy policy) -{ - localLoadPolicy = policy; -} - -bool SecurityOrigin::restrictAccessToLocal() -{ - return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForAll; -} - -bool SecurityOrigin::allowSubstituteDataAccessToLocal() -{ - return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForLocalOnly; -} - -void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) -{ - ASSERT(isMainThread()); - ASSERT(!sourceOrigin.isEmpty()); - if (sourceOrigin.isEmpty()) - return; - - String sourceString = sourceOrigin.toString(); - OriginAccessWhiteList* list = originAccessMap().get(sourceString); - if (!list) { - list = new OriginAccessWhiteList; - originAccessMap().set(sourceString, list); - } - list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains)); -} - -void SecurityOrigin::resetOriginAccessWhiteLists() -{ - ASSERT(isMainThread()); - OriginAccessMap& map = originAccessMap(); - deleteAllValues(map); - map.clear(); -} - -} // namespace WebCore |