| Index: Source/platform/weborigin/SecurityOrigin.cpp
|
| diff --git a/Source/platform/weborigin/SecurityOrigin.cpp b/Source/platform/weborigin/SecurityOrigin.cpp
|
| index b33955e0ec34ebf4481f60a5f19fd344f373f523..babd11cc59d2e611250828c068be3865ea5de26c 100644
|
| --- a/Source/platform/weborigin/SecurityOrigin.cpp
|
| +++ b/Source/platform/weborigin/SecurityOrigin.cpp
|
| @@ -29,6 +29,7 @@
|
| #include "config.h"
|
| #include "platform/weborigin/SecurityOrigin.h"
|
|
|
| +#include "platform/RuntimeEnabledFeatures.h"
|
| #include "platform/weborigin/KURL.h"
|
| #include "platform/weborigin/KnownPorts.h"
|
| #include "platform/weborigin/SchemeRegistry.h"
|
| @@ -37,6 +38,7 @@
|
| #include "url/url_canon_ip.h"
|
| #include "wtf/HexNumber.h"
|
| #include "wtf/MainThread.h"
|
| +#include "wtf/NotFound.h"
|
| #include "wtf/StdLibExtras.h"
|
| #include "wtf/text/StringBuilder.h"
|
|
|
| @@ -62,6 +64,12 @@ static SecurityOrigin* cachedOrigin(const KURL& url)
|
| return 0;
|
| }
|
|
|
| +static bool sameSuborigin(const SecurityOrigin* origin1, const SecurityOrigin* origin2)
|
| +{
|
| + // If either origin has a suborigin set, both must have the same suborigin.
|
| + return origin1->suboriginName() == origin2->suboriginName();
|
| +}
|
| +
|
| bool SecurityOrigin::shouldUseInnerURL(const KURL& url)
|
| {
|
| // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin>/<UUID>", so treating the part after "blob:" as a URL is incorrect.
|
| @@ -116,6 +124,27 @@ static bool shouldTreatAsUniqueOrigin(const KURL& url)
|
| return false;
|
| }
|
|
|
| +bool deserializeSuboriginAndProtocol(const String& oldProtocol, String& suboriginName, String& newProtocol)
|
| +{
|
| + if (!RuntimeEnabledFeatures::suboriginsEnabled())
|
| + return false;
|
| +
|
| + const char suboriginPrefix[] = "suborigin+";
|
| + if (!oldProtocol.startsWith(suboriginPrefix))
|
| + return false;
|
| +
|
| + size_t suboriginStart = strlen(suboriginPrefix);
|
| + size_t protocolStart = oldProtocol.find('+', suboriginStart + 1);
|
| +
|
| + if (protocolStart == kNotFound)
|
| + return false;
|
| +
|
| + suboriginName = oldProtocol.substring(suboriginStart, protocolStart - suboriginStart);
|
| + newProtocol = oldProtocol.substring(protocolStart + 1);
|
| +
|
| + return true;
|
| +}
|
| +
|
| SecurityOrigin::SecurityOrigin(const KURL& url)
|
| : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
|
| , m_host(url.host().isNull() ? "" : url.host().lower())
|
| @@ -126,6 +155,11 @@ SecurityOrigin::SecurityOrigin(const KURL& url)
|
| , m_enforceFilePathSeparation(false)
|
| , m_needsDatabaseIdentifierQuirkForFiles(false)
|
| {
|
| + // Suborigins are serialized into the protocol, so extract it if necessary.
|
| + String suboriginName;
|
| + if (deserializeSuboriginAndProtocol(m_protocol, suboriginName, m_protocol))
|
| + addSuborigin(suboriginName);
|
| +
|
| // document.domain starts as m_host, but can be set by the DOM.
|
| m_domain = m_host;
|
|
|
| @@ -158,6 +192,7 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
|
| , m_host(other->m_host.isolatedCopy())
|
| , m_domain(other->m_domain.isolatedCopy())
|
| , m_filePath(other->m_filePath.isolatedCopy())
|
| + , m_suboriginName(other->m_suboriginName)
|
| , m_port(other->m_port)
|
| , m_isUnique(other->m_isUnique)
|
| , m_universalAccess(other->m_universalAccess)
|
| @@ -200,6 +235,16 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique()
|
| return origin.release();
|
| }
|
|
|
| +void SecurityOrigin::addSuborigin(const String& suborigin)
|
| +{
|
| + ASSERT(RuntimeEnabledFeatures::suboriginsEnabled());
|
| + // Changing suborigins midstream is bad. Very bad. It should not happen.
|
| + // This is, in fact, one of the very basic invariants that makes suborigins
|
| + // an effective security tool.
|
| + RELEASE_ASSERT(m_suboriginName.isNull() || m_suboriginName == suborigin);
|
| + m_suboriginName = suborigin;
|
| +}
|
| +
|
| PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const
|
| {
|
| return adoptRef(new SecurityOrigin(this));
|
| @@ -235,6 +280,9 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const
|
| if (isUnique() || other->isUnique())
|
| return false;
|
|
|
| + if (!sameSuborigin(this, other))
|
| + return false;
|
| +
|
| // Here are two cases where we should permit access:
|
| //
|
| // 1) Neither document has set document.domain. In this case, we insist
|
| @@ -298,6 +346,9 @@ bool SecurityOrigin::canRequest(const KURL& url) const
|
| if (targetOrigin->isUnique())
|
| return false;
|
|
|
| + if (!sameSuborigin(this, targetOrigin.get()))
|
| + return false;
|
| +
|
| // We call isSameSchemeHostPort here instead of canAccess because we want
|
| // to ignore document.domain effects.
|
| if (isSameSchemeHostPort(targetOrigin.get()))
|
| @@ -392,6 +443,8 @@ SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const
|
| return AlwaysAllow;
|
| if (isUnique())
|
| return AlwaysDeny;
|
| + if (hasSuborigin())
|
| + return AlwaysDeny;
|
| return Ask;
|
| }
|
|
|
| @@ -483,7 +536,14 @@ AtomicString SecurityOrigin::toRawAtomicString() const
|
|
|
| inline void SecurityOrigin::buildRawString(StringBuilder& builder) const
|
| {
|
| - builder.reserveCapacity(m_protocol.length() + m_host.length() + 10);
|
| + if (hasSuborigin()) {
|
| + builder.reserveCapacity(11 + m_suboriginName.length() + m_protocol.length() + m_host.length() + 10);
|
| + builder.appendLiteral("suborigin+");
|
| + builder.append(m_suboriginName);
|
| + builder.append('+');
|
| + } else {
|
| + builder.reserveCapacity(m_protocol.length() + m_host.length() + 10);
|
| + }
|
| builder.append(m_protocol);
|
| builder.appendLiteral("://");
|
| builder.append(m_host);
|
| @@ -509,6 +569,9 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const
|
|
|
| bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
|
| {
|
| + if (!sameSuborigin(this, other))
|
| + return false;
|
| +
|
| if (m_host != other->m_host)
|
| return false;
|
|
|
|
|