CORS-RFC1918: Teach ResourceRequest about "external" requests

As defined in https://mikewest.github.io/cors-rfc1918/#external-request.
This patch converts the "reserved IP range" flag on 'ResourceRequest'
into an "external request" flag, and ensures that the flag is set
correctly for requests that run through 'ThreadableLoader' and
'ResourceFetcher'.

The new flag is locked to a new RuntimeEnabledFeature, which is enabled
in test only. If that feature isn't enabled, no request is marked as
being external.

BUG=591052

Review URL: https://codereview.chromium.org/1749153002

Cr-Commit-Position: refs/heads/master@{#378730}
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 5194a0a..7dcaff4 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4918,8 +4918,7 @@
 {
     ASSERT(!securityOrigin());
 
-    if (initializer.isHostedInReservedIPRange())
-        setHostedInReservedIPRange();
+    setHostedInReservedIPRange(initializer.isHostedInReservedIPRange());
 
     if (!initializer.hasSecurityContext()) {
         // No source for a security context.
diff --git a/third_party/WebKit/Source/core/dom/SecurityContext.cpp b/third_party/WebKit/Source/core/dom/SecurityContext.cpp
index 015f65d5..8dda10f 100644
--- a/third_party/WebKit/Source/core/dom/SecurityContext.cpp
+++ b/third_party/WebKit/Source/core/dom/SecurityContext.cpp
@@ -68,4 +68,12 @@
     }
 }
 
+WebURLRequest::AddressSpace SecurityContext::addressSpace() const
+{
+    if (m_hostedInReservedIPRange)
+        return securityOrigin()->isLocalhost() ? WebURLRequest::AddressSpaceLocal : WebURLRequest::AddressSpacePrivate;
+
+    return WebURLRequest::AddressSpacePublic;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/SecurityContext.h b/third_party/WebKit/Source/core/dom/SecurityContext.h
index 091d4a65..9593926e 100644
--- a/third_party/WebKit/Source/core/dom/SecurityContext.h
+++ b/third_party/WebKit/Source/core/dom/SecurityContext.h
@@ -30,6 +30,7 @@
 #include "core/CoreExport.h"
 #include "core/dom/SandboxFlags.h"
 #include "platform/heap/Handle.h"
+#include "public/platform/WebURLRequest.h"
 #include "wtf/HashSet.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/PassRefPtr.h"
@@ -69,8 +70,8 @@
     bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; }
     void enforceSandboxFlags(SandboxFlags mask);
 
-    void setHostedInReservedIPRange() { m_hostedInReservedIPRange = true; }
-    bool isHostedInReservedIPRange() const { return m_hostedInReservedIPRange; }
+    void setHostedInReservedIPRange(bool value) { m_hostedInReservedIPRange = value; }
+    WebURLRequest::AddressSpace addressSpace() const;
 
     void setInsecureRequestsPolicy(InsecureRequestsPolicy policy) { m_insecureRequestsPolicy = policy; }
     InsecureRequestsPolicy getInsecureRequestsPolicy() const { return m_insecureRequestsPolicy; }
diff --git a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp
index bf1a6f6..d09c8db 100644
--- a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp
+++ b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp
@@ -98,6 +98,7 @@
 
     // Construct and load the request.
     ResourceRequest request(m_urlForReading);
+    request.setExternalRequestStateFromRequestorAddressSpace(executionContext.securityContext().addressSpace());
 
     // FIXME: Should this really be 'internal'? Do we know anything about the actual request that generated this fetch?
     request.setRequestContext(WebURLRequest::RequestContextInternal);
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 4bd3c40..1df10fbf 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -113,7 +113,7 @@
     }
 
     if (m_document)
-        request.setOriginatesFromReservedIPRange(m_document->isHostedInReservedIPRange());
+        request.setExternalRequestStateFromRequestorAddressSpace(m_document->addressSpace());
 
     // The remaining modifications are only necessary for HTTP and HTTPS.
     if (!request.url().isEmpty() && !request.url().protocolIsInHTTPFamily())
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
index 758f798..ed0444f0 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -580,4 +580,147 @@
     fetchContext->dispatchDidLoadResourceFromMemoryCache(resource.get(), WebURLRequest::FrameTypeNone, WebURLRequest::RequestContextImage);
 }
 
+TEST_F(FrameFetchContextTest, SetIsExternalRequestForPublicDocument)
+{
+    EXPECT_EQ(WebURLRequest::AddressSpacePublic, document->addressSpace());
+
+    struct TestCase {
+        const char* url;
+        bool isExternalExpectation;
+    } cases[] = {
+        { "data:text/html,whatever", false },
+        { "file:///etc/passwd", false },
+        { "blob:http://example.com/", false },
+
+        { "http://example.com/", false },
+        { "https://example.com/", false },
+
+        { "http://192.168.1.1:8000/", true },
+        { "http://10.1.1.1:8000/", true },
+
+        { "http://localhost/", true },
+        { "http://127.0.0.1/", true },
+        { "http://127.0.0.1:8000/", true }
+    };
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(false);
+    for (const auto& test : cases) {
+        SCOPED_TRACE(test.url);
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_FALSE(mainRequest.isExternalRequest());
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_FALSE(subRequest.isExternalRequest());
+    }
+
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(true);
+    for (const auto& test : cases) {
+        SCOPED_TRACE(test.url);
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_EQ(mainRequest.isExternalRequest(), test.isExternalExpectation);
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_EQ(subRequest.isExternalRequest(), test.isExternalExpectation);
+    }
+}
+
+TEST_F(FrameFetchContextTest, SetIsExternalRequestForPrivateDocument)
+{
+    document->setHostedInReservedIPRange(true);
+    EXPECT_EQ(WebURLRequest::AddressSpacePrivate, document->addressSpace());
+
+    struct TestCase {
+        const char* url;
+        bool isExternalExpectation;
+    } cases[] = {
+        { "data:text/html,whatever", false },
+        { "file:///etc/passwd", false },
+        { "blob:http://example.com/", false },
+
+        { "http://example.com/", false },
+        { "https://example.com/", false },
+
+        { "http://192.168.1.1:8000/", false },
+        { "http://10.1.1.1:8000/", false },
+
+        { "http://localhost/", true },
+        { "http://127.0.0.1/", true },
+        { "http://127.0.0.1:8000/", true }
+    };
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(false);
+    for (const auto& test : cases) {
+        SCOPED_TRACE(test.url);
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_FALSE(mainRequest.isExternalRequest());
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_FALSE(subRequest.isExternalRequest());
+    }
+
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(true);
+    for (const auto& test : cases) {
+        SCOPED_TRACE(test.url);
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_EQ(mainRequest.isExternalRequest(), test.isExternalExpectation);
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_EQ(subRequest.isExternalRequest(), test.isExternalExpectation);
+    }
+}
+
+TEST_F(FrameFetchContextTest, SetIsExternalRequestForLocalDocument)
+{
+    document->setSecurityOrigin(SecurityOrigin::create(KURL(KURL(), "http://localhost/")));
+    document->setHostedInReservedIPRange(true);
+    EXPECT_EQ(WebURLRequest::AddressSpaceLocal, document->addressSpace());
+
+    struct TestCase {
+        const char* url;
+        bool isExternalExpectation;
+    } cases[] = {
+        { "data:text/html,whatever", false },
+        { "file:///etc/passwd", false },
+        { "blob:http://example.com/", false },
+
+        { "http://example.com/", false },
+        { "https://example.com/", false },
+
+        { "http://192.168.1.1:8000/", false },
+        { "http://10.1.1.1:8000/", false },
+
+        { "http://localhost/", false },
+        { "http://127.0.0.1/", false },
+        { "http://127.0.0.1:8000/", false }
+    };
+
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(false);
+    for (const auto& test : cases) {
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_FALSE(mainRequest.isExternalRequest());
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_FALSE(subRequest.isExternalRequest());
+    }
+
+    RuntimeEnabledFeatures::setCorsRFC1918Enabled(true);
+    for (const auto& test : cases) {
+        ResourceRequest mainRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(mainRequest, FetchMainResource);
+        EXPECT_EQ(mainRequest.isExternalRequest(), test.isExternalExpectation);
+
+        ResourceRequest subRequest(test.url);
+        fetchContext->addAdditionalRequestHeaders(subRequest, FetchSubresource);
+        EXPECT_EQ(subRequest.isExternalRequest(), test.isExternalExpectation);
+    }
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
index bc0aff5..5f11c90 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -464,7 +464,7 @@
         return;
 
     // Just count these for the moment, don't block them.
-    if (Platform::current()->isReservedIPAddress(resourceIPAddress) && !frame->document()->isHostedInReservedIPRange())
+    if (Platform::current()->isReservedIPAddress(resourceIPAddress) && frame->document()->addressSpace() == WebURLRequest::AddressSpacePublic)
         UseCounter::count(frame->document(), UseCounter::MixedContentPrivateHostnameInPublicHostname);
 }
 
diff --git a/third_party/WebKit/Source/core/page/EventSource.cpp b/third_party/WebKit/Source/core/page/EventSource.cpp
index 6f5f3f8..cf34291 100644
--- a/third_party/WebKit/Source/core/page/EventSource.cpp
+++ b/third_party/WebKit/Source/core/page/EventSource.cpp
@@ -121,6 +121,7 @@
     request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream");
     request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache");
     request.setRequestContext(WebURLRequest::RequestContextEventSource);
+    request.setExternalRequestStateFromRequestorAddressSpace(executionContext.securityContext().addressSpace());
     if (m_parser && !m_parser->lastEventId().isEmpty()) {
         // HTTP headers are Latin-1 byte strings, but the Last-Event-ID header is encoded as UTF-8.
         // TODO(davidben): This should be captured in the type of setHTTPHeaderField's arguments.
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
index d49b7e4..0e01670 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
@@ -66,7 +66,7 @@
 {
     m_url = url;
 
-    ResourceRequest request(createResourceRequest());
+    ResourceRequest request(createResourceRequest(executionContext));
     ASSERT_WITH_SECURITY_IMPLICATION(executionContext.isWorkerGlobalScope());
 
     ThreadableLoaderOptions options;
@@ -87,7 +87,7 @@
     m_finishedCallback = finishedCallback;
     m_url = url;
 
-    ResourceRequest request(createResourceRequest());
+    ResourceRequest request(createResourceRequest(executionContext));
     ThreadableLoaderOptions options;
     options.crossOriginRequestPolicy = crossOriginRequestPolicy;
 
@@ -112,11 +112,12 @@
     return m_responseURL;
 }
 
-ResourceRequest WorkerScriptLoader::createResourceRequest()
+ResourceRequest WorkerScriptLoader::createResourceRequest(ExecutionContext& executionContext)
 {
     ResourceRequest request(m_url);
     request.setHTTPMethod(HTTPNames::GET);
     request.setRequestContext(m_requestContext);
+    request.setExternalRequestStateFromRequestorAddressSpace(executionContext.securityContext().addressSpace());
     return request;
 }
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
index a4e1d5b..cae0426 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
@@ -96,7 +96,7 @@
     WorkerScriptLoader();
     ~WorkerScriptLoader() override;
 
-    ResourceRequest createResourceRequest();
+    ResourceRequest createResourceRequest(ExecutionContext&);
     void notifyError();
     void notifyFinished();
 
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index 5a95fdf..cbe1593 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -881,6 +881,7 @@
     request.setRequestContext(WebURLRequest::RequestContextXMLHttpRequest);
     request.setFetchCredentialsMode(m_includeCredentials ? WebURLRequest::FetchCredentialsModeInclude : WebURLRequest::FetchCredentialsModeSameOrigin);
     request.setSkipServiceWorker(m_isolatedWorldSecurityOrigin);
+    request.setExternalRequestStateFromRequestorAddressSpace(executionContext.securityContext().addressSpace());
 
     InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_method, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders, m_includeCredentials);
 
diff --git a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
index 01016800..156ebe3 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
@@ -96,6 +96,7 @@
         ResourceRequest request(url);
         request.setRequestContext(WebURLRequest::RequestContextInternal);
         request.setUseStreamOnResponse(true);
+        // We intentionally skip 'setExternalRequestStateFromRequestorAddressSpace', as 'data:' can never be external.
         m_loader->start(request);
     }
 
diff --git a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
index d51c359..dbcfb64 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
@@ -539,6 +539,7 @@
     }
     request.setFetchRedirectMode(m_request->redirect());
     request.setUseStreamOnResponse(true);
+    request.setExternalRequestStateFromRequestorAddressSpace(executionContext()->securityContext().addressSpace());
 
     // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer|
     // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8
@@ -634,6 +635,7 @@
     request.setUseStreamOnResponse(true);
     request.setHTTPMethod(m_request->method());
     request.setFetchRedirectMode(WebURLRequest::FetchRedirectModeError);
+    // We intentionally skip 'setExternalRequestStateFromRequestorAddressSpace', as 'data:' can never be external.
 
     ResourceLoaderOptions resourceLoaderOptions;
     resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index cedd972..93e28d5 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -35,6 +35,7 @@
 CompositedSelectionUpdate
 CompositorWorker status=experimental
 ContextMenu status=experimental
+CorsRFC1918 status=test
 CredentialManager status=stable
 CSS3Text status=experimental
 CSS3TextDecorations status=experimental
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
index 400ff5d..e3946b0 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -435,14 +435,9 @@
     m_private->m_resourceRequest->setUIStartTime(time);
 }
 
-bool WebURLRequest::originatesFromReservedIPRange() const
+bool WebURLRequest::isExternalRequest() const
 {
-    return m_private->m_resourceRequest->originatesFromReservedIPRange();
-}
-
-void WebURLRequest::setOriginatesFromReservedIPRange(bool value)
-{
-    m_private->m_resourceRequest->setOriginatesFromReservedIPRange(value);
+    return m_private->m_resourceRequest->isExternalRequest();
 }
 
 WebURLRequest::InputToLoadPerfMetricReportPolicy WebURLRequest::inputPerfMetricReportPolicy() const
diff --git a/third_party/WebKit/Source/platform/network/ResourceRequest.cpp b/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
index 94f716c..045c964 100644
--- a/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
+++ b/third_party/WebKit/Source/platform/network/ResourceRequest.cpp
@@ -27,7 +27,9 @@
 #include "platform/network/ResourceRequest.h"
 
 #include "platform/HTTPNames.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/Platform.h"
 #include "public/platform/WebURLRequest.h"
 
 namespace blink {
@@ -68,7 +70,7 @@
     m_didSetHTTPReferrer = data->m_didSetHTTPReferrer;
     m_checkForBrowserSideNavigation = data->m_checkForBrowserSideNavigation;
     m_uiStartTime = data->m_uiStartTime;
-    m_originatesFromReservedIPRange = data->m_originatesFromReservedIPRange;
+    m_isExternalRequest = data->m_isExternalRequest;
     m_inputPerfMetricReportPolicy = data->m_inputPerfMetricReportPolicy;
     m_followedRedirect = data->m_followedRedirect;
 }
@@ -108,7 +110,7 @@
     data->m_didSetHTTPReferrer = m_didSetHTTPReferrer;
     data->m_checkForBrowserSideNavigation = m_checkForBrowserSideNavigation;
     data->m_uiStartTime = m_uiStartTime;
-    data->m_originatesFromReservedIPRange = m_originatesFromReservedIPRange;
+    data->m_isExternalRequest = m_isExternalRequest;
     data->m_inputPerfMetricReportPolicy = m_inputPerfMetricReportPolicy;
     data->m_followedRedirect = m_followedRedirect;
     return data.release();
@@ -371,6 +373,28 @@
     return true;
 }
 
+void ResourceRequest::setExternalRequestStateFromRequestorAddressSpace(WebURLRequest::AddressSpace requestorSpace)
+{
+    static_assert(WebURLRequest::AddressSpaceLocal < WebURLRequest::AddressSpacePrivate, "Local is inside Private");
+    static_assert(WebURLRequest::AddressSpaceLocal < WebURLRequest::AddressSpacePublic, "Local is inside Public");
+    static_assert(WebURLRequest::AddressSpacePrivate < WebURLRequest::AddressSpacePublic, "Private is inside Public");
+
+    // TODO(mkwst): This only checks explicit IP addresses. We'll have to move all this up to //net and //content in
+    // order to have any real impact on gateway attacks. That turns out to be a TON of work. https://crbug.com/378566
+    if (!RuntimeEnabledFeatures::corsRFC1918Enabled()) {
+        m_isExternalRequest = false;
+        return;
+    }
+
+    WebURLRequest::AddressSpace targetSpace = WebURLRequest::AddressSpacePublic;
+    if (Platform::current()->isReservedIPAddress(m_url.host()))
+        targetSpace = WebURLRequest::AddressSpacePrivate;
+    if (SecurityOrigin::create(m_url)->isLocalhost())
+        targetSpace = WebURLRequest::AddressSpaceLocal;
+
+    m_isExternalRequest = requestorSpace > targetSpace;
+}
+
 bool ResourceRequest::isConditional() const
 {
     return (m_httpHeaderFields.contains(HTTPNames::If_Match)
@@ -439,7 +463,7 @@
     m_didSetHTTPReferrer = false;
     m_checkForBrowserSideNavigation = true;
     m_uiStartTime = 0;
-    m_originatesFromReservedIPRange = false;
+    m_isExternalRequest = false;
     m_inputPerfMetricReportPolicy = InputToLoadPerfMetricReportPolicy::NoReport;
     m_followedRedirect = false;
     m_requestorOrigin = SecurityOrigin::createUnique();
diff --git a/third_party/WebKit/Source/platform/network/ResourceRequest.h b/third_party/WebKit/Source/platform/network/ResourceRequest.h
index 18bd19fd..3eb22e04 100644
--- a/third_party/WebKit/Source/platform/network/ResourceRequest.h
+++ b/third_party/WebKit/Source/platform/network/ResourceRequest.h
@@ -238,8 +238,9 @@
     double uiStartTime() const { return m_uiStartTime; }
     void setUIStartTime(double uiStartTime) { m_uiStartTime = uiStartTime; }
 
-    bool originatesFromReservedIPRange() const { return m_originatesFromReservedIPRange; }
-    void setOriginatesFromReservedIPRange(bool value) { m_originatesFromReservedIPRange = value; }
+    // https://mikewest.github.io/cors-rfc1918/#external-request
+    bool isExternalRequest() const { return m_isExternalRequest; }
+    void setExternalRequestStateFromRequestorAddressSpace(WebURLRequest::AddressSpace);
 
     InputToLoadPerfMetricReportPolicy inputPerfMetricReportPolicy() const { return m_inputPerfMetricReportPolicy; }
     void setInputPerfMetricReportPolicy(InputToLoadPerfMetricReportPolicy inputPerfMetricReportPolicy) { m_inputPerfMetricReportPolicy = inputPerfMetricReportPolicy; }
@@ -284,7 +285,7 @@
     bool m_didSetHTTPReferrer;
     bool m_checkForBrowserSideNavigation;
     double m_uiStartTime;
-    bool m_originatesFromReservedIPRange;
+    bool m_isExternalRequest;
     InputToLoadPerfMetricReportPolicy m_inputPerfMetricReportPolicy;
 
     mutable CacheControlHeader m_cacheControlHeaderCache;
@@ -335,7 +336,7 @@
     bool m_didSetHTTPReferrer;
     bool m_checkForBrowserSideNavigation;
     double m_uiStartTime;
-    bool m_originatesFromReservedIPRange;
+    bool m_isExternalRequest;
     InputToLoadPerfMetricReportPolicy m_inputPerfMetricReportPolicy;
     bool m_followedRedirect;
 };
diff --git a/third_party/WebKit/public/platform/WebURLRequest.h b/third_party/WebKit/public/platform/WebURLRequest.h
index f493a31..e21ac7f 100644
--- a/third_party/WebKit/public/platform/WebURLRequest.h
+++ b/third_party/WebKit/public/platform/WebURLRequest.h
@@ -64,6 +64,14 @@
         PriorityVeryHigh,
     };
 
+    // The ordering is important, as it's used to determine whether preflights are required,
+    // as per https://mikewest.github.io/cors-rfc1918/#framework
+    enum AddressSpace {
+        AddressSpaceLocal = 0, // loopback, link local
+        AddressSpacePrivate, // Reserved by RFC1918
+        AddressSpacePublic // Everything else
+    };
+
     // Corresponds to Fetch's "context": http://fetch.spec.whatwg.org/#concept-request-context
     enum RequestContext {
         RequestContextUnspecified = 0,
@@ -307,10 +315,8 @@
     BLINK_PLATFORM_EXPORT WebURLRequest::InputToLoadPerfMetricReportPolicy inputPerfMetricReportPolicy() const;
     BLINK_PLATFORM_EXPORT void setInputPerfMetricReportPolicy(WebURLRequest::InputToLoadPerfMetricReportPolicy);
 
-    // Does the request originate from a SecurityContext hosted in a reserved
-    // (RFC1918) IP range?
-    BLINK_PLATFORM_EXPORT bool originatesFromReservedIPRange() const;
-    BLINK_PLATFORM_EXPORT void setOriginatesFromReservedIPRange(bool);
+    // https://mikewest.github.io/cors-rfc1918/#external-request
+    BLINK_PLATFORM_EXPORT bool isExternalRequest() const;
 
 #if INSIDE_BLINK
     BLINK_PLATFORM_EXPORT ResourceRequest& toMutableResourceRequest();