diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/resources/post-document-to-parent.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/resources/post-document-to-parent.php
index 525251d1700d3..1ad8a5027b958 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/resources/post-document-to-parent.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/resources/post-document-to-parent.php
@@ -1,6 +1,9 @@
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
index 9b21d8e54c055..8bc72a657dad3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
@@ -9,6 +9,10 @@ CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
ALERT: I am a secret
CONSOLE ERROR: Error with Suborigin header: Invalid character '@' in suborigin.
ALERT: I am a secret
-CONSOLE ERROR: Error with Suborigin header: Whitespace is not allowed in suborigin names.
+CONSOLE ERROR: Error with Suborigin header: Invalid character 'b' in suborigin policy. Suborigin policy options must start and end with a single quote.
+ALERT: I am a secret
+CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
+ALERT: I am a secret
+CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
ALERT: I am a secret
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
index 9e6c141a3d09c..da3c35cbe6ac1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
@@ -23,6 +23,8 @@
"foo'bar",
"foob@r",
"foo bar",
+ "Foobar",
+ "FOOBAR",
];
var iframe;
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-unsafe-postmessage-send.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-unsafe-postmessage-send.html
new file mode 100644
index 0000000000000..a913d8faffc53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-unsafe-postmessage-send.html
@@ -0,0 +1,36 @@
+
+
+
+Validate that unsafe-postmessage-send allows Suborigin to send messages as physical origin via postMessage.
+
+
+
+
+
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
index 41ab95fda2d4c..7f0c9b9309512 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
@@ -4,6 +4,4 @@ ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from a
ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
index 31800588c6413..f784e2a199b8c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
@@ -18,8 +18,6 @@
var test_suborigin_names = [
"foobar",
"foob4r",
- "Foobar",
- "FOOBAR",
"42",
"foo-bar",
"-foobar",
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index a57f379f1b64d..9e447dc44ab89 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -2563,8 +2563,6 @@
'dom/StyleSheetCandidate.h',
'dom/StyleSheetCollection.cpp',
'dom/StyleSheetCollection.h',
- 'dom/Suborigin.cpp',
- 'dom/Suborigin.h',
'dom/TagCollection.cpp',
'dom/TagCollection.h',
'dom/Text.cpp',
@@ -3928,7 +3926,6 @@
'dom/SelectorQueryTest.cpp',
'dom/StyleElementTest.cpp',
'dom/StyleEngineTest.cpp',
- 'dom/SuboriginTest.cpp',
'dom/TextTest.cpp',
'dom/TreeScopeStyleSheetCollectionTest.cpp',
'dom/TreeScopeTest.cpp',
@@ -4037,7 +4034,6 @@
'loader/LinkHeaderTest.cpp',
'loader/LinkLoaderTest.cpp',
'loader/MixedContentCheckerTest.cpp',
- 'origin_trials/DocumentOriginTrialContextTest.cpp',
'origin_trials/OriginTrialContextTest.cpp',
'page/ChromeClientTest.cpp',
'page/ContextMenuControllerTest.cpp',
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index cfb9c34809da7..92c4893c36f14 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5005,7 +5005,7 @@ void Document::initSecurityContext(const DocumentInit& initializer)
}
if (getSecurityOrigin()->hasSuborigin())
- enforceSuborigin(getSecurityOrigin()->suboriginName());
+ enforceSuborigin(*getSecurityOrigin()->suborigin());
if (Settings* settings = initializer.settings()) {
if (!settings->webSecurityEnabled()) {
@@ -5030,6 +5030,9 @@ void Document::initSecurityContext(const DocumentInit& initializer)
if (getSecurityOrigin()->isUnique() && SecurityOrigin::create(m_url)->isPotentiallyTrustworthy())
getSecurityOrigin()->setUniqueOriginIsPotentiallyTrustworthy(true);
+
+ if (getSecurityOrigin()->hasSuborigin())
+ enforceSuborigin(*getSecurityOrigin()->suborigin());
}
void Document::initContentSecurityPolicy(PassRefPtrWillBeRawPtr csp)
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index efc719fdd0df6..58602d6d61886 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -327,7 +327,7 @@ class CORE_EXPORT Document : public ContainerNode, public TreeScope, public Secu
void setHasXMLDeclaration(bool hasXMLDeclaration) { m_hasXMLDeclaration = hasXMLDeclaration ? 1 : 0; }
String origin() const { return getSecurityOrigin()->toString(); }
- String suborigin() const { return getSecurityOrigin()->suboriginName(); }
+ String suborigin() const { return getSecurityOrigin()->hasSuborigin() ? getSecurityOrigin()->suborigin()->name() : String(); }
String visibilityState() const;
PageVisibilityState pageVisibilityState() const;
diff --git a/third_party/WebKit/Source/core/dom/SecurityContext.cpp b/third_party/WebKit/Source/core/dom/SecurityContext.cpp
index b0ed8c7c08f1e..cc420920da3c0 100644
--- a/third_party/WebKit/Source/core/dom/SecurityContext.cpp
+++ b/third_party/WebKit/Source/core/dom/SecurityContext.cpp
@@ -90,34 +90,20 @@ String SecurityContext::addressSpaceForBindings() const
return "public";
}
-bool SecurityContext::hasSuborigin()
-{
- ASSERT(m_securityOrigin.get());
- return m_securityOrigin->hasSuborigin();
-}
-
-String SecurityContext::suboriginName()
-{
- ASSERT(m_securityOrigin.get());
- return m_securityOrigin->suboriginName();
-}
-
// Enforces the given suborigin as part of the security origin for this
// security context. |name| must not be empty, although it may be null. A null
// name represents a lack of a suborigin.
// See: https://w3c.github.io/webappsec-suborigins/index.html
-void SecurityContext::enforceSuborigin(const String& name)
+void SecurityContext::enforceSuborigin(const Suborigin& suborigin)
{
if (!RuntimeEnabledFeatures::suboriginsEnabled())
return;
- if (name.isNull())
- return;
- ASSERT(!name.isEmpty());
+ ASSERT(!suborigin.name().isEmpty());
ASSERT(RuntimeEnabledFeatures::suboriginsEnabled());
ASSERT(m_securityOrigin.get());
- ASSERT(!m_securityOrigin->hasSuborigin() || m_securityOrigin->suboriginName() == name);
- m_securityOrigin->addSuborigin(name);
+ ASSERT(!m_securityOrigin->hasSuborigin() || m_securityOrigin->suborigin()->name() == suborigin.name());
+ m_securityOrigin->addSuborigin(suborigin);
didUpdateSecurityOrigin();
}
diff --git a/third_party/WebKit/Source/core/dom/SecurityContext.h b/third_party/WebKit/Source/core/dom/SecurityContext.h
index 952e1cd6692f1..f1f9483e65608 100644
--- a/third_party/WebKit/Source/core/dom/SecurityContext.h
+++ b/third_party/WebKit/Source/core/dom/SecurityContext.h
@@ -30,7 +30,9 @@
#include "core/CoreExport.h"
#include "core/dom/SandboxFlags.h"
#include "platform/heap/Handle.h"
+#include "platform/weborigin/Suborigin.h"
#include "public/platform/WebAddressSpace.h"
+#include "public/platform/WebURLRequest.h"
#include "wtf/HashSet.h"
#include "wtf/Noncopyable.h"
#include "wtf/PassRefPtr.h"
@@ -83,9 +85,7 @@ class CORE_EXPORT SecurityContext : public WillBeGarbageCollectedMixin {
void setShouldEnforceStrictMixedContentChecking(bool shouldEnforce) { m_enforceStrictMixedContentChecking = shouldEnforce; }
bool shouldEnforceStrictMixedContentChecking() { return m_enforceStrictMixedContentChecking; }
- void enforceSuborigin(const String& name);
- bool hasSuborigin();
- String suboriginName();
+ void enforceSuborigin(const Suborigin&);
protected:
SecurityContext();
diff --git a/third_party/WebKit/Source/core/dom/Suborigin.cpp b/third_party/WebKit/Source/core/dom/Suborigin.cpp
deleted file mode 100644
index 7f3794a039b57..0000000000000
--- a/third_party/WebKit/Source/core/dom/Suborigin.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/dom/Suborigin.h"
-
-#include "core/dom/Document.h"
-#include "core/inspector/ConsoleMessage.h"
-#include "platform/ParsingUtilities.h"
-#include "wtf/ASCIICType.h"
-
-namespace blink {
-
-template static inline bool isASCIIAlphanumericOrHyphen(CharType c)
-{
- return isASCIIAlphanumeric(c) || c == '-';
-}
-
-void SuboriginPolicy::logSuboriginHeaderError(Document& document, const String& message)
-{
- document.addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Error with Suborigin header: " + message));
-}
-
-String SuboriginPolicy::parseSuboriginName(Document& document, const String& header)
-{
- Vector headers;
- header.split(',', true, headers);
-
- if (headers.size() > 1)
- logSuboriginHeaderError(document, "Multiple Suborigin headers found. Ignoring all but the first.");
-
- Vector characters;
- headers[0].appendTo(characters);
-
- const UChar* position = characters.data();
- const UChar* end = position + characters.size();
-
- // Parse the name of the suborigin (no spaces, single string)
- skipWhile(position, end);
- if (position == end) {
- logSuboriginHeaderError(document, "No Suborigin name specified.");
- return String();
- }
-
- const UChar* begin = position;
-
- skipWhile(position, end);
- if (position != end && !isASCIISpace(*position)) {
- logSuboriginHeaderError(document, "Invalid character \'" + String(position, 1) + "\' in suborigin.");
- return String();
- }
- size_t length = position - begin;
- skipWhile(position, end);
- if (position != end) {
- logSuboriginHeaderError(document, "Whitespace is not allowed in suborigin names.");
- return String();
- }
-
- return String(begin, length);
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Suborigin.h b/third_party/WebKit/Source/core/dom/Suborigin.h
deleted file mode 100644
index 157a6c91417f2..0000000000000
--- a/third_party/WebKit/Source/core/dom/Suborigin.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef Suborigin_h
-#define Suborigin_h
-
-#include "core/CoreExport.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-
-class Document;
-
-class CORE_EXPORT SuboriginPolicy {
-public:
- static void logSuboriginHeaderError(Document&, const String& message);
- static String parseSuboriginName(Document&, const String& header);
-};
-
-} // namespace blink
-
-#endif // Suborigin_h
diff --git a/third_party/WebKit/Source/core/dom/SuboriginTest.cpp b/third_party/WebKit/Source/core/dom/SuboriginTest.cpp
deleted file mode 100644
index 5498167a1a104..0000000000000
--- a/third_party/WebKit/Source/core/dom/SuboriginTest.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/dom/Suborigin.h"
-
-#include "core/dom/Document.h"
-#include "platform/heap/Handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace blink {
-
-class SuboriginTest : public ::testing::Test {
-protected:
- virtual void SetUp()
- {
- m_document = Document::create();
- }
-
- RefPtrWillBePersistent m_document;
-};
-
-TEST_F(SuboriginTest, ParseValidHeaders)
-{
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo"));
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, " foo "));
- EXPECT_EQ("Foo", SuboriginPolicy::parseSuboriginName(*m_document, "Foo"));
- EXPECT_EQ("FOO", SuboriginPolicy::parseSuboriginName(*m_document, "FOO"));
- EXPECT_EQ("f0o", SuboriginPolicy::parseSuboriginName(*m_document, "f0o"));
- EXPECT_EQ("42", SuboriginPolicy::parseSuboriginName(*m_document, "42"));
- EXPECT_EQ("foo-bar", SuboriginPolicy::parseSuboriginName(*m_document, "foo-bar"));
- EXPECT_EQ("-foobar", SuboriginPolicy::parseSuboriginName(*m_document, "-foobar"));
- EXPECT_EQ("foobar-", SuboriginPolicy::parseSuboriginName(*m_document, "foobar-"));
-
- // Mulitple headers should only give the first name
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo, bar"));
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo,bar"));
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo , bar"));
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo,"));
-
- // If the second value in multiple headers is invalid, it is still ignored.
- EXPECT_EQ("foo", SuboriginPolicy::parseSuboriginName(*m_document, "foo, @bar"));
-}
-
-TEST_F(SuboriginTest, ParseInvalidHeaders)
-{
- // Single header, invalid value
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, ""));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "foo bar"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "'foobar'"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "foobar'"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "foo'bar"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "foob@r"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "foo bar"));
-
- // Multiple headers, invalid value(s)
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, ", bar"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, ","));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "f@oo, bar"));
- EXPECT_EQ(String(), SuboriginPolicy::parseSuboriginName(*m_document, "f@oo, b@r"));
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp b/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
index 16b3c4584dade..1836da81c5d64 100644
--- a/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
+++ b/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
@@ -146,7 +146,7 @@ bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
// which implies that all Suborigins are okay as well.
if (securityOrigin->hasSuborigin() && allowOriginHeaderValue != starAtom) {
const AtomicString& allowSuboriginHeaderValue = response.httpHeaderField(allowSuboriginHeaderName);
- AtomicString atomicSuboriginName(securityOrigin->suboriginName());
+ AtomicString atomicSuboriginName(securityOrigin->suborigin()->name());
if (allowSuboriginHeaderValue != starAtom && allowSuboriginHeaderValue != atomicSuboriginName) {
errorDescription = buildAccessControlFailureMessage("The 'Access-Control-Allow-Suborigin' header has a value '" + allowSuboriginHeaderValue + "' that is not equal to the supplied suborigin.", securityOrigin);
return false;
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
index 26aee8fe4d63e..4022728a837a7 100644
--- a/third_party/WebKit/Source/core/frame/DOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
@@ -28,6 +28,7 @@
#include "core/page/Page.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityOrigin.h"
+#include "platform/weborigin/Suborigin.h"
namespace blink {
@@ -199,8 +200,13 @@ void DOMWindow::postMessage(PassRefPtr message, const Mes
// in order to capture the source of the message correctly.
if (!sourceDocument)
return;
- String sourceOrigin = sourceDocument->getSecurityOrigin()->toString();
- String sourceSuborigin = sourceDocument->getSecurityOrigin()->suboriginName();
+
+ const SecurityOrigin* securityOrigin = sourceDocument->getSecurityOrigin();
+ bool hasSuborigin = sourceDocument->getSecurityOrigin()->hasSuborigin();
+ Suborigin::SuboriginPolicyOptions unsafeSendOpt = Suborigin::SuboriginPolicyOptions::UnsafePostMessageSend;
+
+ String sourceOrigin = (hasSuborigin && securityOrigin->suborigin()->policyContains(unsafeSendOpt)) ? securityOrigin->toPhysicalOriginString() : securityOrigin->toString();
+ String sourceSuborigin = hasSuborigin ? securityOrigin->suborigin()->name() : String();
KURL targetUrl = isLocalDOMWindow() ? document()->url() : KURL(KURL(), frame()->securityContext()->getSecurityOrigin()->toString());
if (MixedContentChecker::isMixedContent(sourceDocument->getSecurityOrigin(), targetUrl))
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index c5b90833586a9..dc4df7cdec3a7 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -31,7 +31,6 @@
#include "core/dom/Document.h"
#include "core/dom/DocumentParser.h"
-#include "core/dom/Suborigin.h"
#include "core/dom/WeakIdentifierMap.h"
#include "core/events/Event.h"
#include "core/fetch/CSSStyleSheetResource.h"
@@ -66,6 +65,7 @@
#include "platform/UserGestureIndicator.h"
#include "platform/mhtml/ArchiveResource.h"
#include "platform/network/ContentSecurityPolicyResponseHeaders.h"
+#include "platform/network/HTTPParsers.h"
#include "platform/plugins/PluginData.h"
#include "platform/weborigin/SchemeRegistry.h"
#include "platform/weborigin/SecurityPolicy.h"
@@ -436,9 +436,6 @@ void DocumentLoader::responseReceived(Resource* resource, const ResourceResponse
}
}
}
- HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(HTTPNames::Suborigin);
- if (it != response.httpHeaderFields().end())
- m_suboriginName = SuboriginPolicy::parseSuboriginName(*frame()->document(), it->value);
ASSERT(!m_frame->page()->defersLoading());
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.h b/third_party/WebKit/Source/core/loader/DocumentLoader.h
index ec207782b4d1a..27d1a2b180458 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.h
@@ -142,8 +142,6 @@ class CORE_EXPORT DocumentLoader : public RefCountedWillBeGarbageCollectedFinali
void setWasBlockedAfterXFrameOptionsOrCSP() { m_wasBlockedAfterXFrameOptionsOrCSP = true; }
bool wasBlockedAfterXFrameOptionsOrCSP() { return m_wasBlockedAfterXFrameOptionsOrCSP; }
- String suboriginName() const { return m_suboriginName; }
-
Resource* startPreload(Resource::Type, FetchRequest&);
DECLARE_VIRTUAL_TRACE();
@@ -220,7 +218,6 @@ class CORE_EXPORT DocumentLoader : public RefCountedWillBeGarbageCollectedFinali
RefPtrWillBeMember m_contentSecurityPolicy;
ClientHintsPreferences m_clientHintsPreferences;
InitialScrollState m_initialScrollState;
- String m_suboriginName;
bool m_wasBlockedAfterXFrameOptionsOrCSP;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 79fd95656d747..e6d04948a281b 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -90,6 +90,7 @@
#include "platform/scroll/ScrollAnimatorBase.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityPolicy.h"
+#include "platform/weborigin/Suborigin.h"
#include "public/platform/WebURLRequest.h"
#include "wtf/TemporaryChange.h"
#include "wtf/text/CString.h"
@@ -447,8 +448,20 @@ void FrameLoader::didBeginDocument(bool dispatch)
dispatchDidClearDocumentOfWindowObject();
m_frame->document()->initContentSecurityPolicy(m_documentLoader ? m_documentLoader->releaseContentSecurityPolicy() : ContentSecurityPolicy::create());
- if (m_documentLoader && !m_documentLoader->suboriginName().isNull())
- m_frame->document()->enforceSuborigin(m_documentLoader->suboriginName());
+
+ if (m_documentLoader) {
+ String suboriginHeader = m_documentLoader->response().httpHeaderField(HTTPNames::Suborigin);
+ if (!suboriginHeader.isNull()) {
+ Vector messages;
+ Suborigin suborigin;
+ if (parseSuboriginHeader(suboriginHeader, &suborigin, messages))
+ m_frame->document()->enforceSuborigin(suborigin);
+
+ for (auto& message : messages)
+ m_frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Error with Suborigin header: " + message));
+ }
+ }
+
if (m_documentLoader) {
m_frame->document()->clientHintsPreferences().updateFrom(m_documentLoader->clientHintsPreferences());
LinkLoader::loadLinksFromHeader(m_documentLoader->response().httpHeaderField(HTTPNames::Link), m_documentLoader->response().url(),
diff --git a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
index 2f5f664fea700..26447d3b2f3e8 100644
--- a/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
+++ b/third_party/WebKit/Source/core/loader/HttpEquiv.cpp
@@ -6,7 +6,6 @@
#include "core/dom/Document.h"
#include "core/dom/StyleEngine.h"
-#include "core/dom/Suborigin.h"
#include "core/fetch/ClientHintsPreferences.h"
#include "core/frame/UseCounter.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
@@ -42,7 +41,7 @@ void HttpEquiv::process(Document& document, const AtomicString& equiv, const Ato
else
document.contentSecurityPolicy()->reportMetaOutsideHead(content);
} else if (equalIgnoringCase(equiv, "suborigin")) {
- SuboriginPolicy::logSuboriginHeaderError(document, "Suborigin header with value '" + content + "' was delivered via a element and not an HTTP header, which is disallowed. The Suborigin has been ignored.");
+ document.addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Error with Suborigin header: Suborigin header with value '" + content + "' was delivered via a element and not an HTTP header, which is disallowed. The Suborigin has been ignored."));
}
}
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 67d39538bc4ff..e743a95f8ee0f 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -1115,6 +1115,8 @@
'weborigin/SecurityOriginHash.h',
'weborigin/SecurityPolicy.cpp',
'weborigin/SecurityPolicy.h',
+ 'weborigin/Suborigin.cpp',
+ 'weborigin/Suborigin.h',
],
'platform_test_files': [
'DecimalTest.cpp',
diff --git a/third_party/WebKit/Source/platform/network/HTTPParsers.cpp b/third_party/WebKit/Source/platform/network/HTTPParsers.cpp
index edf10dc217328..2f002fdb60cd3 100644
--- a/third_party/WebKit/Source/platform/network/HTTPParsers.cpp
+++ b/third_party/WebKit/Source/platform/network/HTTPParsers.cpp
@@ -32,6 +32,8 @@
#include "platform/network/HTTPParsers.h"
+#include "platform/ParsingUtilities.h"
+#include "platform/weborigin/Suborigin.h"
#include "wtf/DateMath.h"
#include "wtf/MathExtras.h"
#include "wtf/text/CString.h"
@@ -106,6 +108,72 @@ static inline bool skipValue(const String& str, unsigned& pos)
return pos != start;
}
+template static inline bool isASCIILowerAlphaOrDigitOrHyphen(CharType c)
+{
+ return isASCIILower(c) || isASCIIDigit(c) || c == '-';
+}
+
+static Suborigin::SuboriginPolicyOptions getSuboriginPolicyOptionFromString(const String& policyOptionName)
+{
+ if (policyOptionName == "'unsafe-postmessage-send'")
+ return Suborigin::SuboriginPolicyOptions::UnsafePostMessageSend;
+
+ return Suborigin::SuboriginPolicyOptions::None;
+}
+
+
+static const UChar* parseSuboriginName(const UChar* begin, const UChar* end, String& name, WTF::Vector& messages)
+{
+ // Parse the name of the suborigin (no spaces, single string)
+ skipWhile(begin, end);
+ if (begin == end) {
+ messages.append(String("No Suborigin name specified."));
+ return nullptr;
+ }
+
+ const UChar* position = begin;
+
+ skipWhile(position, end);
+ if (position != end && !isASCIISpace(*position)) {
+ messages.append("Invalid character \'" + String(position, 1) + "\' in suborigin.");
+ return nullptr;
+ }
+ size_t length = position - begin;
+ skipWhile(position, end);
+
+ name = String(begin, length).lower();
+ return position;
+}
+
+static const UChar* parseSuboriginPolicyOption(const UChar* begin, const UChar* end, String& option, WTF::Vector& messages)
+{
+ const UChar* position = begin;
+
+ if (*position != '\'') {
+ messages.append("Invalid character \'" + String(position, 1) + "\' in suborigin policy. Suborigin policy options must start and end with a single quote.");
+ return nullptr;
+ }
+ position = position + 1;
+
+ skipWhile(position, end);
+ if (position == end || isASCIISpace(*position)) {
+ messages.append(String("Expected \' to end policy option."));
+ return nullptr;
+ }
+
+ if (*position != '\'') {
+ messages.append("Invalid character \'" + String(position, 1) + "\' in suborigin policy.");
+ return nullptr;
+ }
+
+ ASSERT(position > begin);
+ size_t length = (position + 1) - begin;
+
+ option = String(begin, length);
+ return position + 1;
+}
+
+
bool isValidHTTPHeaderValue(const String& name)
{
// FIXME: This should really match name against
@@ -628,4 +696,60 @@ void parseCommaDelimitedHeader(const String& headerValue, CommaDelimitedHeaderSe
headerSet.add(value.stripWhiteSpace(isWhitespace));
}
+bool parseSuboriginHeader(const String& header, Suborigin* suborigin, WTF::Vector& messages)
+{
+ Vector headers;
+ header.split(',', true, headers);
+
+ if (headers.size() > 1)
+ messages.append("Multiple Suborigin headers found. Ignoring all but the first.");
+
+ Vector characters;
+ headers[0].appendTo(characters);
+
+ const UChar* position = characters.data();
+ const UChar* end = position + characters.size();
+
+ skipWhile(position, end);
+
+ String name;
+ position = parseSuboriginName(position, end, name, messages);
+ if (!position)
+ return false;
+
+ suborigin->setName(name);
+
+ while (position < end) {
+ skipWhile(position, end);
+ if (position == end)
+ return true;
+
+ String optionName;
+ position = parseSuboriginPolicyOption(position, end, optionName, messages);
+
+ if (!position) {
+ suborigin->clear();
+ return false;
+ }
+
+ Suborigin::SuboriginPolicyOptions option = getSuboriginPolicyOptionFromString(optionName);
+ if (option == Suborigin::SuboriginPolicyOptions::None)
+ messages.append("Ignoring unknown suborigin policy option " + optionName + ".");
+ else
+ suborigin->addPolicyOption(option);
+
+ skipWhile(position, end);
+ if (position == end || *position != ';') {
+ String found = (position == end) ? "end of string" : String(position, 1);
+ messages.append("Invalid suborigin policy Expected ';' at end of policy option. Found \'" + found + "\' instead.");
+ suborigin->clear();
+ return false;
+ }
+
+ position++;
+ }
+
+ return true;
+}
+
} // namespace blink
diff --git a/third_party/WebKit/Source/platform/network/HTTPParsers.h b/third_party/WebKit/Source/platform/network/HTTPParsers.h
index 10ea6f9de741f..8fe5d2e95d6e5 100644
--- a/third_party/WebKit/Source/platform/network/HTTPParsers.h
+++ b/third_party/WebKit/Source/platform/network/HTTPParsers.h
@@ -40,6 +40,8 @@
namespace blink {
+class Suborigin;
+
typedef enum {
ContentDispositionNone,
ContentDispositionInline,
@@ -110,6 +112,11 @@ PLATFORM_EXPORT ReflectedXSSDisposition parseXSSProtectionHeader(const String& h
PLATFORM_EXPORT XFrameOptionsDisposition parseXFrameOptionsHeader(const String&);
PLATFORM_EXPORT CacheControlHeader parseCacheControlDirectives(const AtomicString& cacheControlHeader, const AtomicString& pragmaHeader);
PLATFORM_EXPORT void parseCommaDelimitedHeader(const String& headerValue, CommaDelimitedHeaderSet&);
+// Returns true on success, otherwise false. The Suborigin argument must be a
+// non-null return argument. |messages| is a list of messages based on any
+// parse warnings or errors. Even if parseSuboriginHeader returns true, there
+// may be Strings in |messages|.
+PLATFORM_EXPORT bool parseSuboriginHeader(const String& header, Suborigin*, WTF::Vector& messages);
PLATFORM_EXPORT ContentTypeOptionsDisposition parseContentTypeOptionsHeader(const String& header);
diff --git a/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp b/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp
index 2349c27ee4f71..3304ac0dd0847 100644
--- a/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp
+++ b/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp
@@ -4,8 +4,11 @@
#include "platform/network/HTTPParsers.h"
+#include "platform/heap/Handle.h"
+#include "platform/weborigin/Suborigin.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "wtf/MathExtras.h"
+#include "wtf/dtoa/utils.h"
#include "wtf/text/AtomicString.h"
namespace blink {
@@ -165,4 +168,106 @@ TEST(HTTPParsersTest, ExtractMIMETypeFromMediaType)
EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("t e x t / h t m l")));
}
+void expectParseNamePass(const char* message, String header, String expectedName)
+{
+ SCOPED_TRACE(message);
+
+ Vector messages;
+ Suborigin suborigin;
+ EXPECT_TRUE(parseSuboriginHeader(header, &suborigin, messages));
+ EXPECT_EQ(expectedName, suborigin.name());
+}
+
+void expectParseNameFail(const char* message, String header)
+{
+ SCOPED_TRACE(message);
+
+ Vector messages;
+ Suborigin suborigin;
+ EXPECT_FALSE(parseSuboriginHeader(header, &suborigin, messages));
+ EXPECT_EQ(String(), suborigin.name());
+}
+
+void expectParsePolicyPass(const char* message, String header, const Suborigin::SuboriginPolicyOptions expectedPolicy[], size_t numPolicies)
+{
+ SCOPED_TRACE(message);
+
+ Vector messages;
+ Suborigin suborigin;
+ EXPECT_TRUE(parseSuboriginHeader(header, &suborigin, messages));
+ unsigned policiesMask = 0;
+ for (size_t i = 0; i < numPolicies; i++)
+ policiesMask |= static_cast(expectedPolicy[i]);
+ EXPECT_EQ(policiesMask, suborigin.optionsMask());
+}
+
+void expectParsePolicyFail(const char* message, String header)
+{
+ SCOPED_TRACE(message);
+
+ Vector messages;
+ Suborigin suborigin;
+ EXPECT_FALSE(parseSuboriginHeader(header, &suborigin, messages));
+ EXPECT_EQ(String(), suborigin.name());
+}
+
+TEST(HTTPParsersTest, SuboriginParseValidNames)
+{
+ // Single headers
+ expectParseNamePass("Alpha", "foo", "foo");
+ expectParseNamePass("Whitespace alpha", " foo ", "foo");
+ expectParseNamePass("Alphanumeric", "f0o", "f0o");
+ expectParseNamePass("Numeric", "42", "42");
+ expectParseNamePass("Hyphen middle", "foo-bar", "foo-bar");
+ expectParseNamePass("Hyphen start", "-foobar", "-foobar");
+ expectParseNamePass("Hyphen end", "foobar-", "foobar-");
+
+ // Mulitple headers should only give the first name
+ expectParseNamePass("Multiple headers, no whitespace", "foo,bar", "foo");
+ expectParseNamePass("Multiple headers, whitespace before second", "foo, bar", "foo");
+ expectParseNamePass("Multiple headers, whitespace after first and before second", "foo, bar", "foo");
+ expectParseNamePass("Multiple headers, empty second ignored", "foo, bar", "foo");
+ expectParseNamePass("Multiple headers, invalid second ignored", "foo, bar", "foo");
+}
+
+TEST(HTTPParsersTest, SuboriginParseInvalidNames)
+{
+ // Single header, invalid value
+ expectParseNameFail("Empty header", "");
+ expectParseNameFail("Whitespace in middle", "foo bar");
+ expectParseNameFail("Invalid character at end of name", "foobar'");
+ expectParseNameFail("Invalid character at start of name", "'foobar");
+ expectParseNameFail("Invalid character in middle of name", "foo'bar");
+ expectParseNameFail("Alternate invalid character in middle of name", "foob@r");
+ expectParseNameFail("First cap", "Foo");
+ expectParseNameFail("All cap", "FOO");
+
+ // Multiple headers, invalid value(s)
+ expectParseNameFail("Multple headers, empty first header", ", bar");
+ expectParseNameFail("Multple headers, both empty headers", ",");
+ expectParseNameFail("Multple headers, invalid character in first header", "f@oo, bar");
+ expectParseNameFail("Multple headers, invalid character in both headers", "f@oo, b@r");
+}
+
+TEST(HTTPParsersTest, SuboriginParseValidPolicy)
+{
+ const Suborigin::SuboriginPolicyOptions unsafePostmessageSend[] = { Suborigin::SuboriginPolicyOptions::UnsafePostMessageSend };
+
+ expectParsePolicyPass("One policy", "foobar 'unsafe-postmessage-send';", unsafePostmessageSend, ARRAY_SIZE(unsafePostmessageSend));
+ expectParsePolicyPass("One policy, whitespace all around", "foobar 'unsafe-postmessage-send' ; ", unsafePostmessageSend, ARRAY_SIZE(unsafePostmessageSend));
+ expectParsePolicyPass("Multiple, same policies", "foobar 'unsafe-postmessage-send'; 'unsafe-postmessage-send';", unsafePostmessageSend, ARRAY_SIZE(unsafePostmessageSend));
+ expectParsePolicyPass("One policy, unknown option", "foobar 'unknown-option';", {}, 0);
+}
+
+TEST(HTTPParsersTest, SuboriginParseInvalidPolicy)
+{
+ expectParsePolicyFail("One policy, no suborigin name", "'unsafe-postmessage-send';");
+ expectParsePolicyFail("One policy, invalid characters", "foobar 'un$afe-postmessage-send';");
+ expectParsePolicyFail("One policy, caps", "foobar 'UNSAFE-POSTMESSAGE-SEND';");
+ expectParsePolicyFail("One policy, missing first quote", "foobar unsafe-postmessage-send';");
+ expectParsePolicyFail("One policy, missing last quote", "foobar 'unsafe-postmessage-send;");
+ expectParsePolicyFail("One policy, missing semicolon at end", "foobar 'unsafe-postmessage-send'");
+ expectParsePolicyFail("One policy, missing semicolon between options", "foobar 'unsafe-postmessage-send' 'unsafe-postmessage-send';");
+}
+
} // namespace blink
diff --git a/third_party/WebKit/Source/platform/network/ResourceRequest.cpp b/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
index a42de218596f5..39dfcac65bc3a 100644
--- a/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
+++ b/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
@@ -232,7 +232,7 @@ void ResourceRequest::setHTTPOrigin(PassRefPtr origin)
{
setHTTPHeaderField(HTTPNames::Origin, origin->toAtomicString());
if (origin->hasSuborigin())
- setHTTPHeaderField(HTTPNames::Suborigin, AtomicString(origin->suboriginName()));
+ setHTTPHeaderField(HTTPNames::Suborigin, AtomicString(origin->suborigin()->name()));
}
void ResourceRequest::clearHTTPOrigin()
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
index 4cac0e825fdbd..f8d132a275777 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
@@ -131,7 +131,7 @@ SecurityOrigin::SecurityOrigin(const KURL& url)
// Suborigins are serialized into the host, so extract it if necessary.
String suboriginName;
if (deserializeSuboriginAndHost(m_host, suboriginName, m_host))
- addSuborigin(suboriginName);
+ m_suborigin.setName(suboriginName);
// document.domain starts as m_host, but can be set by the DOM.
m_domain = m_host;
@@ -147,7 +147,6 @@ SecurityOrigin::SecurityOrigin()
: m_protocol("")
, m_host("")
, m_domain("")
- , m_suboriginName(WTF::String())
, m_port(InvalidPort)
, m_effectivePort(InvalidPort)
, m_isUnique(true)
@@ -163,7 +162,7 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
: m_protocol(other->m_protocol.isolatedCopy())
, m_host(other->m_host.isolatedCopy())
, m_domain(other->m_domain.isolatedCopy())
- , m_suboriginName(other->m_suboriginName.isolatedCopy())
+ , m_suborigin(other->m_suborigin)
, m_port(other->m_port)
, m_effectivePort(other->m_effectivePort)
, m_isUnique(other->m_isUnique)
@@ -198,16 +197,6 @@ PassRefPtr 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::isolatedCopy() const
{
return adoptRef(new SecurityOrigin(this));
@@ -275,7 +264,7 @@ bool SecurityOrigin::canAccessCheckSuborigins(const SecurityOrigin* other) const
if (hasSuborigin() != other->hasSuborigin())
return false;
- if (hasSuborigin() && suboriginName() != other->suboriginName())
+ if (hasSuborigin() && suborigin()->name() != other->suborigin()->name())
return false;
return canAccess(other);
@@ -391,6 +380,16 @@ void SecurityOrigin::grantUniversalAccess()
m_universalAccess = true;
}
+void SecurityOrigin::addSuborigin(const Suborigin& 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_suborigin.name().isNull() || (m_suborigin.name() == suborigin.name()));
+ m_suborigin.setTo(suborigin);
+}
+
void SecurityOrigin::blockLocalAccessFromLocalOrigin()
{
ASSERT(isLocal());
@@ -443,13 +442,32 @@ AtomicString SecurityOrigin::toAtomicString() const
return toRawAtomicString();
}
+String SecurityOrigin::toPhysicalOriginString() const
+{
+ if (isUnique())
+ return "null";
+ if (isLocal() && m_blockLocalAccessFromLocalOrigin)
+ return "null";
+ return toRawStringIgnoreSuborigin();
+}
+
String SecurityOrigin::toRawString() const
{
if (m_protocol == "file")
return "file://";
StringBuilder result;
- buildRawString(result);
+ buildRawString(result, true);
+ return result.toString();
+}
+
+String SecurityOrigin::toRawStringIgnoreSuborigin() const
+{
+ if (m_protocol == "file")
+ return "file://";
+
+ StringBuilder result;
+ buildRawString(result, false);
return result.toString();
}
@@ -478,16 +496,16 @@ AtomicString SecurityOrigin::toRawAtomicString() const
return AtomicString("file://", AtomicString::ConstructFromLiteral);
StringBuilder result;
- buildRawString(result);
+ buildRawString(result, true);
return result.toAtomicString();
}
-void SecurityOrigin::buildRawString(StringBuilder& builder) const
+void SecurityOrigin::buildRawString(StringBuilder& builder, bool includeSuborigin) const
{
builder.append(m_protocol);
builder.appendLiteral("://");
- if (hasSuborigin()) {
- builder.append(m_suboriginName);
+ if (includeSuborigin && hasSuborigin()) {
+ builder.append(m_suborigin.name());
builder.appendLiteral("_");
}
builder.append(m_host);
@@ -531,7 +549,8 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
bool SecurityOrigin::isSameSchemeHostPortAndSuborigin(const SecurityOrigin* other) const
{
- return isSameSchemeHostPort(other) && (suboriginName() == other->suboriginName());
+ bool sameSuborigins = (hasSuborigin() == other->hasSuborigin()) && (!hasSuborigin() || (suborigin()->name() == other->suborigin()->name()));
+ return isSameSchemeHostPort(other) && sameSuborigins;
}
const KURL& SecurityOrigin::urlWithUniqueSecurityOrigin()
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
index af13d6c3bfa12..6594a9fb6b3a1 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -31,6 +31,7 @@
#include "base/gtest_prod_util.h"
#include "platform/PlatformExport.h"
+#include "platform/weborigin/Suborigin.h"
#include "wtf/Noncopyable.h"
#include "wtf/ThreadSafeRefCounted.h"
#include "wtf/text/WTFString.h"
@@ -202,9 +203,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted {
// only ever be called once per SecurityOrigin(). If it is called on a
// SecurityOrigin that has already had a suborigin assigned, it will hit a
// RELEASE_ASSERT().
- void addSuborigin(const String&);
- bool hasSuborigin() const { return !m_suboriginName.isNull(); }
- const String& suboriginName() const { return m_suboriginName; }
+ bool hasSuborigin() const { return !m_suborigin.name().isNull(); }
+ const Suborigin* suborigin() const { return &m_suborigin; }
+ void addSuborigin(const Suborigin&);
// By default 'file:' URLs may access other 'file:' URLs. This method
// denies access. If either SecurityOrigin sets this flag, the access
@@ -223,6 +224,9 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted {
// we shouldTreatURLSchemeAsNoAccess.
String toString() const;
AtomicString toAtomicString() const;
+ // Same as toString above, but ignores Suborigin, if present. This is
+ // generally not what you want.
+ String toPhysicalOriginString() const;
// Similar to toString(), but does not take into account any factors that
// could make the string return "null".
@@ -264,14 +268,15 @@ class PLATFORM_EXPORT SecurityOrigin : public RefCounted {
// FIXME: Rename this function to something more semantic.
bool passesFileCheck(const SecurityOrigin*) const;
- void buildRawString(StringBuilder&) const;
+ void buildRawString(StringBuilder&, bool includeSuborigin) const;
+ String toRawStringIgnoreSuborigin() const;
static bool deserializeSuboriginAndHost(const String&, String&, String&);
String m_protocol;
String m_host;
String m_domain;
- String m_suboriginName;
+ Suborigin m_suborigin;
unsigned short m_port;
unsigned short m_effectivePort;
bool m_isUnique;
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h b/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h
index 7f6972075617f..f396d760c3f5d 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h
@@ -44,7 +44,7 @@ struct SecurityOriginHash {
origin->protocol().impl() ? origin->protocol().impl()->hash() : 0,
origin->host().impl() ? origin->host().impl()->hash() : 0,
origin->port(),
- origin->suboriginName().impl() ? origin->suboriginName().impl()->hash() : 0
+ (origin->suborigin()->name().impl()) ? origin->suborigin()->name().impl()->hash() : 0
};
return StringHasher::hashMemory(hashCodes);
}
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
index c74840def2154..483f19a2e671c 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
@@ -34,6 +34,7 @@
#include "platform/blob/BlobURL.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityPolicy.h"
+#include "platform/weborigin/Suborigin.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
@@ -220,19 +221,21 @@ TEST_F(SecurityOriginTest, Suborigins)
RuntimeEnabledFeatures::setSuboriginsEnabled(true);
RefPtr origin = SecurityOrigin::createFromString("https://test.com");
+ Suborigin suborigin;
+ suborigin.setName("foobar");
EXPECT_FALSE(origin->hasSuborigin());
- origin->addSuborigin("foobar");
+ origin->addSuborigin(suborigin);
EXPECT_TRUE(origin->hasSuborigin());
- EXPECT_EQ("foobar", origin->suboriginName());
+ EXPECT_EQ("foobar", origin->suborigin()->name());
origin = SecurityOrigin::createFromString("https://foobar_test.com");
EXPECT_EQ("https", origin->protocol());
EXPECT_EQ("test.com", origin->host());
- EXPECT_EQ("foobar", origin->suboriginName());
+ EXPECT_EQ("foobar", origin->suborigin()->name());
origin = SecurityOrigin::createFromString("https://foobar_test.com");
EXPECT_TRUE(origin->hasSuborigin());
- EXPECT_EQ("foobar", origin->suboriginName());
+ EXPECT_EQ("foobar", origin->suborigin()->name());
origin = SecurityOrigin::createFromString("https://foobar+test.com");
EXPECT_FALSE(origin->hasSuborigin());
@@ -244,7 +247,8 @@ TEST_F(SecurityOriginTest, Suborigins)
EXPECT_FALSE(origin->hasSuborigin());
origin = SecurityOrigin::createFromString("https://foobar_test.com");
- EXPECT_DEATH(origin->addSuborigin("shouldhitassert"), "");
+ Suborigin emptySuborigin;
+ EXPECT_DEATH(origin->addSuborigin(emptySuborigin), "");
}
TEST_F(SecurityOriginTest, SuboriginsParsing)
@@ -263,14 +267,26 @@ TEST_F(SecurityOriginTest, SuboriginsParsing)
StringBuilder builder;
origin = SecurityOrigin::createFromString("https://foobar_test.com");
- origin->buildRawString(builder);
+ origin->buildRawString(builder, true);
EXPECT_EQ("https://foobar_test.com", builder.toString());
+ EXPECT_EQ("https://foobar_test.com", origin->toString());
+ builder.clear();
+ origin->buildRawString(builder, false);
+ EXPECT_EQ("https://test.com", builder.toString());
+ EXPECT_EQ("https://test.com", origin->toPhysicalOriginString());
+ Suborigin suboriginObj;
+ suboriginObj.setName("foobar");
builder.clear();
origin = SecurityOrigin::createFromString("https://test.com");
- origin->addSuborigin("foobar");
- origin->buildRawString(builder);
+ origin->addSuborigin(suboriginObj);
+ origin->buildRawString(builder, true);
EXPECT_EQ("https://foobar_test.com", builder.toString());
+ EXPECT_EQ("https://foobar_test.com", origin->toString());
+ builder.clear();
+ origin->buildRawString(builder, false);
+ EXPECT_EQ("https://test.com", builder.toString());
+ EXPECT_EQ("https://test.com", origin->toPhysicalOriginString());
}
TEST_F(SecurityOriginTest, SuboriginsIsSameSchemeHostPortAndSuborigin)
diff --git a/third_party/WebKit/Source/platform/weborigin/Suborigin.cpp b/third_party/WebKit/Source/platform/weborigin/Suborigin.cpp
new file mode 100644
index 0000000000000..89361c7357c8d
--- /dev/null
+++ b/third_party/WebKit/Source/platform/weborigin/Suborigin.cpp
@@ -0,0 +1,47 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/weborigin/Suborigin.h"
+
+#include "platform/ParsingUtilities.h"
+#include "wtf/ASCIICType.h"
+
+namespace blink {
+
+static unsigned emptyPolicy = static_cast(Suborigin::SuboriginPolicyOptions::None);
+
+Suborigin::Suborigin()
+ : m_optionsMask(emptyPolicy)
+{
+}
+
+Suborigin::Suborigin(const Suborigin* other)
+ : m_name(other->m_name.isolatedCopy())
+ , m_optionsMask(other->m_optionsMask)
+{
+}
+
+void Suborigin::setTo(const Suborigin& other)
+{
+ m_name = other.m_name;
+ m_optionsMask = other.m_optionsMask;
+}
+
+void Suborigin::addPolicyOption(SuboriginPolicyOptions option)
+{
+ m_optionsMask |= static_cast(option);
+}
+
+bool Suborigin::policyContains(SuboriginPolicyOptions option) const
+{
+ return m_optionsMask & static_cast(option);
+}
+
+void Suborigin::clear()
+{
+ m_name = String();
+ m_optionsMask = emptyPolicy;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/weborigin/Suborigin.h b/third_party/WebKit/Source/platform/weborigin/Suborigin.h
new file mode 100644
index 0000000000000..42dbfe0a34d54
--- /dev/null
+++ b/third_party/WebKit/Source/platform/weborigin/Suborigin.h
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef Suborigin_h
+#define Suborigin_h
+
+#include "platform/PlatformExport.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/ThreadSafeRefCounted.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT Suborigin {
+public:
+ enum class SuboriginPolicyOptions : unsigned {
+ None = 0,
+ UnsafePostMessageSend = 1 << 0
+ };
+
+ Suborigin();
+ explicit Suborigin(const Suborigin*);
+
+ void setTo(const Suborigin&);
+ String name() const { return m_name; }
+ void setName(const String& name) { m_name = name; }
+ void addPolicyOption(SuboriginPolicyOptions);
+ bool policyContains(SuboriginPolicyOptions) const;
+ void clear();
+ // For testing
+ unsigned optionsMask() const { return m_optionsMask; }
+
+private:
+ String m_name;
+ unsigned m_optionsMask;
+};
+
+} // namespace blink
+
+#endif // Suborigin_h