Commit 5ce4f5e6 authored by estark@chromium.org's avatar estark@chromium.org

Attach mixed content status to resource requests when sent to devtools

This CL computes the mixed content status (blockable, optionally
blockable, or not mixed) of resource requests before they are sent to
DevTools via the InspectorResourceAgent. The ResourceRequests's mixed
content status gets sent to DevTools as part of the Request parameter to
the requestWillBeSent event. The mixed content status will be used to
display mixed resources in the Security panel.

BUG=518065

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

git-svn-id: svn://svn.chromium.org/blink/trunk@200936 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 6814dc1a
CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/inspector-protocol/resources/active-mixed-content-iframe.html' was loaded over HTTPS, but requested an insecure script 'http://127.0.0.1:8000/inspector-protocol/resources/blank.js'. This content should also be served over HTTPS.
CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/inspector-protocol/resources/passive-mixed-content-iframe.html' was loaded over HTTPS, but requested an insecure image 'http://127.0.0.1:8000/resources/square.png'. This content should also be served over HTTPS.
Tests that willSendRequest contains the correct mixed content status.
Network agent enabled
Mixed content type of https://127.0.0.1:8443/inspector-protocol/resources/no-mixed-content-iframe.html: none
Mixed content type of https://127.0.0.1:8443/inspector-protocol/resources/active-mixed-content-iframe.html: none
Mixed content type of https://127.0.0.1:8443/inspector-protocol/resources/passive-mixed-content-iframe.html: none
Mixed content type of https://127.0.0.1:8443/inspector-protocol/resources/blank.js: none
Mixed content type of http://127.0.0.1:8000/inspector-protocol/resources/blank.js: blockable
Mixed content type of http://127.0.0.1:8000/resources/square.png: optionally-blockable
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../inspector-protocol/inspector-protocol-test.js"></script>
<script src="/resources/get-host-info.js"></script>
<script>
if (window.testRunner) {
testRunner.overridePreference("WebKitAllowRunningInsecureContent", true);
testRunner.overridePreference("WebKitAllowDisplayingInsecureContent", true);
}
function noMixedContent()
{
var iframe = document.createElement("iframe");
iframe.src = get_host_info().HTTPS_ORIGIN + "/inspector-protocol/resources/no-mixed-content-iframe.html";
document.body.appendChild(iframe);
}
function blockableMixedContent()
{
var iframe = document.createElement("iframe");
iframe.src = get_host_info().HTTPS_ORIGIN + "/inspector-protocol/resources/active-mixed-content-iframe.html";
document.body.appendChild(iframe);
}
function optionallyBlockableMixedContent()
{
var iframe = document.createElement("iframe");
iframe.src = get_host_info().HTTPS_ORIGIN + "/inspector-protocol/resources/passive-mixed-content-iframe.html";
document.body.appendChild(iframe);
}
function test()
{
InspectorTest.eventHandler["Network.requestWillBeSent"] = onRequestWillBeSent;
InspectorTest.sendCommand("Network.enable", {}, didEnableNetwork);
function didEnableNetwork(messageObject)
{
if (messageObject.error) {
InspectorTest.log("FAIL: Couldn't enable network agent" + messageObject.error.message);
InspectorTest.completeTest();
return;
}
InspectorTest.log("Network agent enabled");
// FIXME(estark): use Runtime.evaluate callbacks instead of
// firing these off all at once and tracking state in
// onRequestWillBeSent().
InspectorTest.sendCommand("Runtime.evaluate", { "expression": "noMixedContent()" });
InspectorTest.sendCommand("Runtime.evaluate", { "expression": "blockableMixedContent()" });
InspectorTest.sendCommand("Runtime.evaluate", { "expression": "optionallyBlockableMixedContent()" });
}
var num_requests = 0;
var num_expected_requests = 6;
function onRequestWillBeSent(event) {
var req = event.params.request;
InspectorTest.log("Mixed content type of " + req.url + ": " + req.mixedContentType);
num_requests++;
if (num_requests == num_expected_requests)
InspectorTest.completeTest();
}
}
</script>
</head>
<body onload="runTest()">
<p>Tests that willSendRequest contains the correct mixed content status.</p>
</body>
</html>
<script src="http://127.0.0.1:8000/inspector-protocol/resources/blank.js"></script>
......@@ -225,7 +225,7 @@ interface InspectorInstrumentation {
void applyUserAgentOverride(LocalFrame*, String* userAgent);
[Resource]
void willSendRequest(LocalFrame*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo&);
void willSendRequest([Keep] LocalFrame*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo&);
[Resource]
void markResourceAsCached(LocalFrame*, unsigned long identifier);
......
......@@ -58,6 +58,7 @@
#include "core/inspector/ScriptCallStack.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/FrameLoader.h"
#include "core/loader/MixedContentChecker.h"
#include "core/loader/ThreadableLoaderClient.h"
#include "core/page/Page.h"
#include "core/xmlhttprequest/XMLHttpRequest.h"
......@@ -176,6 +177,21 @@ KURL urlWithoutFragment(const KURL& url)
return result;
}
TypeBuilder::Network::Request::MixedContentType::Enum mixedContentTypeForContextType(MixedContentChecker::ContextType contextType)
{
switch (contextType) {
case MixedContentChecker::ContextTypeNotMixedContent:
return TypeBuilder::Network::Request::MixedContentType::None;
case MixedContentChecker::ContextTypeBlockable:
return TypeBuilder::Network::Request::MixedContentType::Blockable;
case MixedContentChecker::ContextTypeOptionallyBlockable:
case MixedContentChecker::ContextTypeShouldBeBlockable:
return TypeBuilder::Network::Request::MixedContentType::Optionally_blockable;
}
return TypeBuilder::Network::Request::MixedContentType::None;
}
} // namespace
void InspectorResourceAgent::restore()
......@@ -349,7 +365,7 @@ DEFINE_TRACE(InspectorResourceAgent)
InspectorBaseAgent::trace(visitor);
}
void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
void InspectorResourceAgent::willSendRequest(LocalFrame* frame, unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
{
// Ignore the request initiated internally.
if (initiatorInfo.name == FetchInitiatorTypeNames::internal)
......@@ -398,6 +414,8 @@ void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentL
RefPtr<TypeBuilder::Network::Request> requestInfo(buildObjectForResourceRequest(request));
requestInfo->setMixedContentType(mixedContentTypeForContextType(MixedContentChecker::contextTypeForInspector(frame, request)));
if (!m_hostId.isEmpty())
request.addHTTPHeaderField(kDevToolsEmulateNetworkConditionsClientId, AtomicString(m_hostId));
......
......@@ -83,7 +83,7 @@ public:
DECLARE_VIRTUAL_TRACE();
// Called from instrumentation.
void willSendRequest(unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo&);
void willSendRequest(LocalFrame*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, const FetchInitiatorInfo&);
void markResourceAsCached(unsigned long identifier);
void didReceiveResourceResponse(LocalFrame*, unsigned long identifier, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
void didReceiveData(LocalFrame*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
......
......@@ -496,21 +496,9 @@ bool FrameFetchContext::canRequest(Resource::Type type, const ResourceRequest& r
// Last of all, check for mixed content. We do this last so that when
// folks block mixed content with a CSP policy, they don't get a warning.
// They'll still get a warning in the console about CSP blocking the load.
// If we're loading the main resource of a subframe, ensure that we check
// against the parent of the active frame, rather than the frame itself.
LocalFrame* effectiveFrame = frame();
if (resourceRequest.frameType() == WebURLRequest::FrameTypeNested) {
// FIXME: Deal with RemoteFrames.
Frame* parentFrame = effectiveFrame->tree().parent();
ASSERT(parentFrame);
if (parentFrame->isLocalFrame())
effectiveFrame = toLocalFrame(parentFrame);
}
MixedContentChecker::ReportingStatus mixedContentReporting = forPreload ?
MixedContentChecker::SuppressReport : MixedContentChecker::SendReport;
return !MixedContentChecker::shouldBlockFetch(effectiveFrame, resourceRequest, url, mixedContentReporting);
return !MixedContentChecker::shouldBlockFetch(MixedContentChecker::effectiveFrameForFrameType(frame(), resourceRequest.frameType()), resourceRequest, url, mixedContentReporting);
}
bool FrameFetchContext::isControlledByServiceWorker() const
......
......@@ -342,6 +342,9 @@ bool MixedContentChecker::shouldBlockFetch(LocalFrame* frame, WebURLRequest::Req
if (allowed)
client->didDisplayInsecureContent();
break;
case ContextTypeNotMixedContent:
ASSERT_NOT_REACHED();
break;
};
if (reportingStatus == SendReport)
......@@ -427,4 +430,35 @@ void MixedContentChecker::checkMixedPrivatePublic(LocalFrame* frame, const Atomi
UseCounter::count(frame->document(), UseCounter::MixedContentPrivateHostnameInPublicHostname);
}
LocalFrame* MixedContentChecker::effectiveFrameForFrameType(LocalFrame* frame, WebURLRequest::FrameType frameType)
{
// If we're loading the main resource of a subframe, ensure that we check
// against the parent of the active frame, rather than the frame itself.
LocalFrame* effectiveFrame = frame;
if (frameType == WebURLRequest::FrameTypeNested) {
// FIXME: Deal with RemoteFrames.
Frame* parentFrame = effectiveFrame->tree().parent();
ASSERT(parentFrame);
if (parentFrame->isLocalFrame())
effectiveFrame = toLocalFrame(parentFrame);
}
return effectiveFrame;
}
MixedContentChecker::ContextType MixedContentChecker::contextTypeForInspector(LocalFrame* frame, const ResourceRequest& request)
{
LocalFrame* effectiveFrame = effectiveFrameForFrameType(frame, request.frameType());
LocalFrame* mixedFrame = inWhichFrameIsContentMixed(effectiveFrame, request.frameType(), request.url());
if (!mixedFrame)
return ContextTypeNotMixedContent;
// See comment in shouldBlockFetch() about loading the main resource of a subframe.
if (request.frameType() == WebURLRequest::FrameTypeNested && !SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())) {
return ContextTypeOptionallyBlockable;
}
return contextTypeFromContext(request.requestContext(), mixedFrame);
}
} // namespace blink
......@@ -48,6 +48,13 @@ class CORE_EXPORT MixedContentChecker final {
WTF_MAKE_NONCOPYABLE(MixedContentChecker);
DISALLOW_ALLOCATION();
public:
enum ContextType {
ContextTypeNotMixedContent,
ContextTypeBlockable,
ContextTypeOptionallyBlockable,
ContextTypeShouldBeBlockable,
};
enum ReportingStatus { SendReport, SuppressReport };
static bool shouldBlockFetch(LocalFrame*, WebURLRequest::RequestContext, WebURLRequest::FrameType, const KURL&, ReportingStatus = SendReport);
static bool shouldBlockFetch(LocalFrame* frame, const ResourceRequest& request, const KURL& url, ReportingStatus status = SendReport)
......@@ -62,6 +69,12 @@ public:
static void checkMixedPrivatePublic(LocalFrame*, const AtomicString& resourceIPAddress);
static ContextType contextTypeForInspector(LocalFrame*, const ResourceRequest&);
// Returns the frame that should be considered the effective frame
// for a mixed content check for the given frame type.
static LocalFrame* effectiveFrameForFrameType(LocalFrame*, WebURLRequest::FrameType);
private:
enum MixedContentType {
Display,
......@@ -70,12 +83,6 @@ private:
Submission
};
enum ContextType {
ContextTypeBlockable,
ContextTypeOptionallyBlockable,
ContextTypeShouldBeBlockable,
};
static LocalFrame* inWhichFrameIsContentMixed(LocalFrame*, WebURLRequest::FrameType, const KURL&);
static ContextType contextTypeFromContext(WebURLRequest::RequestContext, LocalFrame*);
......
......@@ -5,6 +5,7 @@
#include "config.h"
#include "core/loader/MixedContentChecker.h"
#include "core/testing/DummyPageHolder.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "wtf/RefPtr.h"
......@@ -43,4 +44,28 @@ TEST(MixedContentCheckerTest, IsMixedContent)
}
}
TEST(MixedContentCheckerTest, ContextTypeForInspector)
{
OwnPtr<DummyPageHolder> dummyPageHolder = DummyPageHolder::create(IntSize(1, 1));
dummyPageHolder->frame().document()->setSecurityOrigin(SecurityOrigin::createFromString("http://example.test"));
ResourceRequest notMixedContent("https://example.test/foo.jpg");
notMixedContent.setFrameType(WebURLRequest::FrameTypeAuxiliary);
notMixedContent.setRequestContext(WebURLRequest::RequestContextScript);
EXPECT_EQ(MixedContentChecker::ContextTypeNotMixedContent, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), notMixedContent));
dummyPageHolder->frame().document()->setSecurityOrigin(SecurityOrigin::createFromString("https://example.test"));
EXPECT_EQ(MixedContentChecker::ContextTypeNotMixedContent, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), notMixedContent));
ResourceRequest blockableMixedContent("http://example.test/foo.jpg");
blockableMixedContent.setFrameType(WebURLRequest::FrameTypeAuxiliary);
blockableMixedContent.setRequestContext(WebURLRequest::RequestContextScript);
EXPECT_EQ(MixedContentChecker::ContextTypeBlockable, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), blockableMixedContent));
ResourceRequest optionallyBlockableMixedContent("http://example.test/foo.jpg");
blockableMixedContent.setFrameType(WebURLRequest::FrameTypeAuxiliary);
blockableMixedContent.setRequestContext(WebURLRequest::RequestContextImage);
EXPECT_EQ(MixedContentChecker::ContextTypeOptionallyBlockable, MixedContentChecker::contextTypeForInspector(&dummyPageHolder->frame(), blockableMixedContent));
}
} // namespace blink
......@@ -1180,7 +1180,8 @@
{ "name": "url", "type": "string", "description": "Request URL." },
{ "name": "method", "type": "string", "description": "HTTP request method." },
{ "name": "headers", "$ref": "Headers", "description": "HTTP request headers." },
{ "name": "postData", "type": "string", "optional": true, "description": "HTTP POST request data." }
{ "name": "postData", "type": "string", "optional": true, "description": "HTTP POST request data." },
{ "name": "mixedContentType", "optional": true, "type": "string", "enum": ["blockable", "optionally-blockable", "none"], "description": "The mixed content status of the request, as defined in http://www.w3.org/TR/mixed-content/" }
]
},
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment