Commit d8dfdb9b authored by estark@chromium.org's avatar estark@chromium.org

Implement referrerpolicy attribute for img elements

The 'referrerpolicy' attribute controls the referrer for the outgoing
request when an image is loaded.

BUG=490608

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

git-svn-id: svn://svn.chromium.org/blink/trunk@200940 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent fb4895d7
<!DOCTYPE html>
<html>
<body>
<meta name="referrer" content="origin">
<img src="resources/green250x50.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green250x50.png" />
</body>
</html
<!DOCTYPE html>
<html>
<head>
<script src="/resources/get-host-info.js"></script>
</head>
<body>
<script>
if (window.testRunner)
testRunner.waitUntilDone();
if (window.location.origin != get_host_info().HTTPS_ORIGIN) {
window.location = get_host_info().HTTPS_ORIGIN + window.location.pathname;
} else {
var img = document.createElement("img");
img.src = "http://127.0.0.1:8000/security/resources/green-if-no-referrer.php";
img.referrerpolicy = "no-referrer-when-downgrade";
document.body.appendChild(img);
testRunner.notifyDone();
}
</script>
</body>
</html
<!DOCTYPE html>
<html>
<body>
<meta name="referrer" content="origin">
<img src="resources/green-if-no-referrer.php"
referrerpolicy="no-referrer" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green250x50.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green250x50.png" />
<img src="resources/green250x50.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="http://localhost:8000/security/resources/green-if-referrer-is-origin.php"
referrerpolicy="origin-when-crossorigin" />
<img src="resources/green-if-referrer-is-full-url-origin-when-crossorigin.php"
referrerpolicy="origin-when-crossorigin" />
</body>
</html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green-if-referrer-is-origin.php"
referrerpolicy="origin" />
</body>
</html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green250x50.png" />
<img src="resources/green250x50.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<picture>
<source srcset="resources/abe.png" media="(false)">
<img src="resources/green-if-no-referrer.php"
referrerpolicy="no-referrer" />
</picture>
<picture>
<source srcset="resources/green-if-no-referrer.php" type="image/png">
<img src="resources/abe.png"
referrerpolicy="no-referrer" />
</picture>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/red200x100.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="http://127.0.0.1:8000/security/resources/green-if-referrer-is-origin.php"
referrerpolicy="origin" id="image" />
<script>
// Remove the image's referrerpolicy attribute and set a new
// src to send a new request.
var img = document.getElementById("image");
img.removeAttribute("referrerpolicy");
img.src = "http://127.0.0.1:8000/security/resources/green-if-no-referrer.php";
// The expected result is a red square because a referrer will be
// sent according to the default referrerpolicy.
</script>
</body>
</html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="resources/green250x50.png" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="http://localhost:8000/security/resources/green-if-referrer-is-full-url.php"
referrerpolicy="unsafe-url" />
</body>
</html
...@@ -9,9 +9,15 @@ ...@@ -9,9 +9,15 @@
var anch = document.createElement("a"); var anch = document.createElement("a");
anch.href = "http://localhost:8000/security/resources/referrer-attr-anchor-target.html#no-policy"; anch.href = "http://localhost:8000/security/resources/referrer-attr-anchor-target.html#no-policy";
document.body.appendChild(anch); document.body.appendChild(anch);
var img = document.createElement("img");
img.src = "http://localhost:8000/security/resources/compass.jpg";
document.body.appendChild(img);
test(function () { test(function () {
assert_equals(anch.referrerpolicy, ""); assert_equals(anch.referrerpolicy, "");
}, "Dynamically created anchor has empty referrerpolicy"); assert_equals(img.referrerpolicy, "");
}, "Dynamically created elements have empty referrerpolicy");
anch.click(); anch.click();
</script> </script>
</body> </body>
......
<?php
header('Content-Type: image/png');
if ($_SERVER['HTTP_REFERER'] != 'http://127.0.0.1:8000/security/referrer-policy-attribute-img-origin-when-crossorigin.html') {
$img = 'red200x100.png';
} else {
$img = 'green250x50.png';
}
echo file_get_contents($img);
?>
\ No newline at end of file
<?php
header('Content-Type: image/png');
if ($_SERVER['HTTP_REFERER'] != 'http://127.0.0.1:8000/security/referrer-policy-attribute-img-unsafe-url.html') {
$img = 'red200x100.png';
} else {
$img = 'green250x50.png';
}
echo file_get_contents($img);
?>
\ No newline at end of file
<?php
header('Content-Type: image/png');
if ($_SERVER['HTTP_REFERER'] != 'http://127.0.0.1:8000/') {
$img = 'red200x100.png';
} else {
$img = 'green250x50.png';
}
echo file_get_contents($img);
?>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
else if (hash === "unsafe-url") else if (hash === "unsafe-url")
expected_referrer = "http://127.0.0.1:8000/security/referrer-policy-attribute-anchor-unsafe-url.html"; expected_referrer = "http://127.0.0.1:8000/security/referrer-policy-attribute-anchor-unsafe-url.html";
else if (hash === "no-policy") else if (hash === "no-policy")
expected_referrer = "http://127.0.0.1:8000/security/referrer-policy-attribute-anchor-no-policy.html"; expected_referrer = "http://127.0.0.1:8000/security/referrer-policy-attribute-no-policy.html";
else if (hash === "origin-when-crossorigin") else if (hash === "origin-when-crossorigin")
expected_referrer = "http://127.0.0.1:8000/"; expected_referrer = "http://127.0.0.1:8000/";
else if (hash === "no-referrer" || else if (hash === "no-referrer" ||
......
...@@ -572,6 +572,7 @@ html element img ...@@ -572,6 +572,7 @@ html element img
property name property name
property naturalHeight property naturalHeight
property naturalWidth property naturalWidth
property referrerpolicy
property sizes property sizes
property src property src
property srcset property srcset
......
...@@ -2108,6 +2108,7 @@ interface HTMLImageElement ...@@ -2108,6 +2108,7 @@ interface HTMLImageElement
getter name getter name
getter naturalHeight getter naturalHeight
getter naturalWidth getter naturalWidth
getter referrerpolicy
getter sizes getter sizes
getter src getter src
getter srcset getter srcset
...@@ -2127,6 +2128,7 @@ interface HTMLImageElement ...@@ -2127,6 +2128,7 @@ interface HTMLImageElement
setter longDesc setter longDesc
setter lowsrc setter lowsrc
setter name setter name
setter referrerpolicy
setter sizes setter sizes
setter src setter src
setter srcset setter srcset
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include "platform/EventDispatchForbiddenScope.h" #include "platform/EventDispatchForbiddenScope.h"
#include "platform/MIMETypeRegistry.h" #include "platform/MIMETypeRegistry.h"
#include "platform/RuntimeEnabledFeatures.h" #include "platform/RuntimeEnabledFeatures.h"
#include "platform/weborigin/SecurityPolicy.h"
namespace blink { namespace blink {
...@@ -91,6 +92,7 @@ HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form, bo ...@@ -91,6 +92,7 @@ HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form, bo
, m_intrinsicSizingViewportDependant(false) , m_intrinsicSizingViewportDependant(false)
, m_useFallbackContent(false) , m_useFallbackContent(false)
, m_isFallbackImage(false) , m_isFallbackImage(false)
, m_referrerPolicy(ReferrerPolicyDefault)
{ {
setHasCustomStyleCallbacks(); setHasCustomStyleCallbacks();
if (form && form->inDocument()) { if (form && form->inDocument()) {
...@@ -268,6 +270,10 @@ void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr ...@@ -268,6 +270,10 @@ void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr
selectSourceURL(ImageLoader::UpdateIgnorePreviousError); selectSourceURL(ImageLoader::UpdateIgnorePreviousError);
} else if (name == usemapAttr) { } else if (name == usemapAttr) {
setIsLink(!value.isNull()); setIsLink(!value.isNull());
} else if (name == referrerpolicyAttr) {
m_referrerPolicy = ReferrerPolicyDefault;
if (!value.isNull())
SecurityPolicy::referrerPolicyFromString(value, &m_referrerPolicy);
} else { } else {
HTMLElement::parseAttribute(name, value); HTMLElement::parseAttribute(name, value);
} }
...@@ -389,7 +395,7 @@ Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* ...@@ -389,7 +395,7 @@ Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode*
// If we have been inserted from a layoutObject-less document, // If we have been inserted from a layoutObject-less document,
// our loader may have not fetched the image, so do it now. // our loader may have not fetched the image, so do it now.
if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified) if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified)
imageLoader().updateFromElement(ImageLoader::UpdateNormal); imageLoader().updateFromElement(ImageLoader::UpdateNormal, m_referrerPolicy);
return HTMLElement::insertedInto(insertionPoint); return HTMLElement::insertedInto(insertionPoint);
} }
...@@ -660,7 +666,7 @@ float HTMLImageElement::sourceSize(Element& element) ...@@ -660,7 +666,7 @@ float HTMLImageElement::sourceSize(Element& element)
void HTMLImageElement::forceReload() const void HTMLImageElement::forceReload() const
{ {
imageLoader().updateFromElement(ImageLoader::UpdateForcedReload); imageLoader().updateFromElement(ImageLoader::UpdateForcedReload, m_referrerPolicy);
} }
void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior) void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior)
...@@ -683,7 +689,7 @@ void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior be ...@@ -683,7 +689,7 @@ void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior be
m_listener = ViewportChangeListener::create(this); m_listener = ViewportChangeListener::create(this);
document().mediaQueryMatcher().addViewportListener(m_listener); document().mediaQueryMatcher().addViewportListener(m_listener);
} }
imageLoader().updateFromElement(behavior); imageLoader().updateFromElement(behavior, m_referrerPolicy);
if (imageLoader().image() || (imageLoader().hasPendingActivity() && !imageSourceURL().isEmpty())) if (imageLoader().image() || (imageLoader().hasPendingActivity() && !imageSourceURL().isEmpty()))
ensurePrimaryContent(); ensurePrimaryContent();
......
...@@ -170,6 +170,8 @@ private: ...@@ -170,6 +170,8 @@ private:
unsigned m_intrinsicSizingViewportDependant : 1; unsigned m_intrinsicSizingViewportDependant : 1;
unsigned m_useFallbackContent : 1; unsigned m_useFallbackContent : 1;
unsigned m_isFallbackImage : 1; unsigned m_isFallbackImage : 1;
ReferrerPolicy m_referrerPolicy;
}; };
} // namespace blink } // namespace blink
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
readonly attribute long naturalHeight; readonly attribute long naturalHeight;
readonly attribute boolean complete; readonly attribute boolean complete;
readonly attribute DOMString currentSrc; readonly attribute DOMString currentSrc;
[RuntimeEnabled=ReferrerPolicyAttribute, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerpolicy;
// obsolete members // obsolete members
// https://html.spec.whatwg.org/#HTMLImageElement-partial // https://html.spec.whatwg.org/#HTMLImageElement-partial
......
...@@ -123,6 +123,8 @@ public: ...@@ -123,6 +123,8 @@ public:
, m_defer(FetchRequest::NoDefer) , m_defer(FetchRequest::NoDefer)
, m_allowCredentials(DoNotAllowStoredCredentials) , m_allowCredentials(DoNotAllowStoredCredentials)
, m_mediaValues(mediaValues) , m_mediaValues(mediaValues)
, m_referrerPolicySet(false)
, m_referrerPolicy(ReferrerPolicyDefault)
{ {
ASSERT(m_mediaValues->isCached()); ASSERT(m_mediaValues->isCached());
if (match(m_tagImpl, imgTag) if (match(m_tagImpl, imgTag)
...@@ -174,7 +176,7 @@ public: ...@@ -174,7 +176,7 @@ public:
} }
} }
PassOwnPtr<PreloadRequest> createPreloadRequest(const KURL& predictedBaseURL, const SegmentedString& source, const ClientHintsPreferences& clientHintsPreferences, const PictureData& pictureData, const ReferrerPolicy referrerPolicy) PassOwnPtr<PreloadRequest> createPreloadRequest(const KURL& predictedBaseURL, const SegmentedString& source, const ClientHintsPreferences& clientHintsPreferences, const PictureData& pictureData, const ReferrerPolicy documentReferrerPolicy)
{ {
PreloadRequest::RequestType requestType = PreloadRequest::RequestTypePreload; PreloadRequest::RequestType requestType = PreloadRequest::RequestTypePreload;
if (shouldPreconnect()) if (shouldPreconnect())
...@@ -195,6 +197,8 @@ public: ...@@ -195,6 +197,8 @@ public:
resourceWidth.isSet = true; resourceWidth.isSet = true;
} }
// The element's 'referrerpolicy' attribute (if present) takes precedence over the document's referrer policy.
ReferrerPolicy referrerPolicy = m_referrerPolicy != ReferrerPolicyDefault ? m_referrerPolicy : documentReferrerPolicy;
OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), position, m_urlToLoad, predictedBaseURL, resourceType(), referrerPolicy, resourceWidth, clientHintsPreferences, requestType); OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), position, m_urlToLoad, predictedBaseURL, resourceType(), referrerPolicy, resourceWidth, clientHintsPreferences, requestType);
if (isCORSEnabled()) if (isCORSEnabled())
request->setCrossOriginEnabled(allowStoredCredentials()); request->setCrossOriginEnabled(allowStoredCredentials());
...@@ -237,6 +241,9 @@ private: ...@@ -237,6 +241,9 @@ private:
m_srcsetImageCandidate = bestFitSourceForSrcsetAttribute(m_mediaValues->devicePixelRatio(), m_sourceSize, m_srcsetAttributeValue); m_srcsetImageCandidate = bestFitSourceForSrcsetAttribute(m_mediaValues->devicePixelRatio(), m_sourceSize, m_srcsetAttributeValue);
setUrlToLoad(bestFitSourceForImageAttributes(m_mediaValues->devicePixelRatio(), m_sourceSize, m_imgSrcUrl, m_srcsetImageCandidate), AllowURLReplacement); setUrlToLoad(bestFitSourceForImageAttributes(m_mediaValues->devicePixelRatio(), m_sourceSize, m_imgSrcUrl, m_srcsetImageCandidate), AllowURLReplacement);
} }
} else if (!m_referrerPolicySet && match(attributeName, referrerpolicyAttr) && !attributeValue.isNull()) {
m_referrerPolicySet = true;
SecurityPolicy::referrerPolicyFromString(attributeValue, &m_referrerPolicy);
} }
} }
...@@ -411,6 +418,8 @@ private: ...@@ -411,6 +418,8 @@ private:
FetchRequest::DeferOption m_defer; FetchRequest::DeferOption m_defer;
StoredCredentials m_allowCredentials; StoredCredentials m_allowCredentials;
RefPtrWillBeMember<MediaValues> m_mediaValues; RefPtrWillBeMember<MediaValues> m_mediaValues;
bool m_referrerPolicySet;
ReferrerPolicy m_referrerPolicy;
}; };
TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, PassOwnPtr<CachedDocumentParameters> documentParameters) TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, PassOwnPtr<CachedDocumentParameters> documentParameters)
......
...@@ -34,6 +34,16 @@ struct PreconnectTestCase { ...@@ -34,6 +34,16 @@ struct PreconnectTestCase {
CrossOriginAttributeValue crossOrigin; CrossOriginAttributeValue crossOrigin;
}; };
struct ReferrerPolicyTestCase {
const char* baseURL;
const char* inputHTML;
const char* preloadedURL; // Or nullptr if no preload is expected.
const char* outputBaseURL;
Resource::Type type;
int resourceWidth;
ReferrerPolicy referrerPolicy;
};
class MockHTMLResourcePreloader : public ResourcePreloader { class MockHTMLResourcePreloader : public ResourcePreloader {
public: public:
void preloadRequestVerification(Resource::Type type, const char* url, const char* baseURL, int width, const ClientHintsPreferences& preferences) void preloadRequestVerification(Resource::Type type, const char* url, const char* baseURL, int width, const ClientHintsPreferences& preferences)
...@@ -52,6 +62,12 @@ public: ...@@ -52,6 +62,12 @@ public:
EXPECT_EQ(preferences.shouldSendViewportWidth(), m_preloadRequest->preferences().shouldSendViewportWidth()); EXPECT_EQ(preferences.shouldSendViewportWidth(), m_preloadRequest->preferences().shouldSendViewportWidth());
} }
void preloadRequestVerification(Resource::Type type, const char* url, const char* baseURL, int width, ReferrerPolicy referrerPolicy)
{
preloadRequestVerification(type, url, baseURL, width, ClientHintsPreferences());
EXPECT_EQ(referrerPolicy, m_preloadRequest->referrerPolicy());
}
void preconnectRequestVerification(const String& host, CrossOriginAttributeValue crossOrigin) void preconnectRequestVerification(const String& host, CrossOriginAttributeValue crossOrigin)
{ {
if (!host.isNull()) { if (!host.isNull()) {
...@@ -142,6 +158,16 @@ protected: ...@@ -142,6 +158,16 @@ protected:
preloader.preconnectRequestVerification(testCase.preconnectedHost, testCase.crossOrigin); preloader.preconnectRequestVerification(testCase.preconnectedHost, testCase.crossOrigin);
} }
void test(ReferrerPolicyTestCase testCase)
{
MockHTMLResourcePreloader preloader;
KURL baseURL(ParsedURLString, testCase.baseURL);
m_scanner->appendToEnd(String(testCase.inputHTML));
m_scanner->scan(&preloader, baseURL);
preloader.preloadRequestVerification(testCase.type, testCase.preloadedURL, testCase.outputBaseURL, testCase.resourceWidth, testCase.referrerPolicy);
}
private: private:
OwnPtr<DummyPageHolder> m_dummyPageHolder; OwnPtr<DummyPageHolder> m_dummyPageHolder;
OwnPtr<HTMLPreloadScanner> m_scanner; OwnPtr<HTMLPreloadScanner> m_scanner;
...@@ -297,4 +323,22 @@ TEST_F(HTMLPreloadScannerTest, testPicture) ...@@ -297,4 +323,22 @@ TEST_F(HTMLPreloadScannerTest, testPicture)
test(testCase); test(testCase);
} }
TEST_F(HTMLPreloadScannerTest, testReferrerPolicy)
{
ReferrerPolicyTestCase testCases[] = {
{ "http://example.test", "<img src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyDefault },
{ "http://example.test", "<img referrerpolicy='origin' src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyOrigin },
{ "http://example.test", "<meta name='referrer' content='not-a-valid-policy'><img src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyDefault },
{ "http://example.test", "<img referrerpolicy='origin' referrerpolicy='origin-when-crossorigin' src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyOrigin },
{ "http://example.test", "<img referrerpolicy='not-a-valid-policy' src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyDefault },
{ "http://example.test", "<meta name='referrer' content='no-referrer'><img referrerpolicy='origin' src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyOrigin },
// The scanner's state is not reset between test cases, so all subsequent test cases have a document referrer policy of no-referrer.
{ "http://example.test", "<img referrerpolicy='not-a-valid-policy' src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyNever },
{ "http://example.test", "<img src='bla.gif'/>", "bla.gif", "http://example.test/", Resource::Image, 0, ReferrerPolicyNever }
};
for (const auto& testCase : testCases)
test(testCase);
}
} // namespace blink } // namespace blink
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
bool isCORS() const { return m_isCORSEnabled; } bool isCORS() const { return m_isCORSEnabled; }
bool isAllowCredentials() const { return m_allowCredentials == AllowStoredCredentials; } bool isAllowCredentials() const { return m_allowCredentials == AllowStoredCredentials; }
const ClientHintsPreferences& preferences() const { return m_clientHintsPreferences; } const ClientHintsPreferences& preferences() const { return m_clientHintsPreferences; }
ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; }
private: private:
PreloadRequest(const String& initiatorName, PreloadRequest(const String& initiatorName,
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "core/svg/graphics/SVGImage.h" #include "core/svg/graphics/SVGImage.h"
#include "platform/Logging.h" #include "platform/Logging.h"
#include "platform/weborigin/SecurityOrigin.h" #include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityPolicy.h"
#include "public/platform/WebURLRequest.h" #include "public/platform/WebURLRequest.h"
namespace blink { namespace blink {
...@@ -78,16 +79,17 @@ static ImageLoader::BypassMainWorldBehavior shouldBypassMainWorldCSP(ImageLoader ...@@ -78,16 +79,17 @@ static ImageLoader::BypassMainWorldBehavior shouldBypassMainWorldCSP(ImageLoader
class ImageLoader::Task : public WebThread::Task { class ImageLoader::Task : public WebThread::Task {
public: public:
static PassOwnPtr<Task> create(ImageLoader* loader, UpdateFromElementBehavior updateBehavior) static PassOwnPtr<Task> create(ImageLoader* loader, UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
{ {
return adoptPtr(new Task(loader, updateBehavior)); return adoptPtr(new Task(loader, updateBehavior, referrerPolicy));
} }
Task(ImageLoader* loader, UpdateFromElementBehavior updateBehavior) Task(ImageLoader* loader, UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
: m_loader(loader) : m_loader(loader)
, m_shouldBypassMainWorldCSP(shouldBypassMainWorldCSP(loader)) , m_shouldBypassMainWorldCSP(shouldBypassMainWorldCSP(loader))
, m_updateBehavior(updateBehavior) , m_updateBehavior(updateBehavior)
, m_weakFactory(this) , m_weakFactory(this)
, m_referrerPolicy(referrerPolicy)
{ {
v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate(); v8::Isolate* isolate = V8PerIsolateData::mainThreadIsolate();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
...@@ -109,9 +111,9 @@ public: ...@@ -109,9 +111,9 @@ public:
return; return;
if (m_scriptState->contextIsValid()) { if (m_scriptState->contextIsValid()) {
ScriptState::Scope scope(m_scriptState.get()); ScriptState::Scope scope(m_scriptState.get());
m_loader->doUpdateFromElement(m_shouldBypassMainWorldCSP, m_updateBehavior); m_loader->doUpdateFromElement(m_shouldBypassMainWorldCSP, m_updateBehavior, m_referrerPolicy);
} else { } else {
m_loader->doUpdateFromElement(m_shouldBypassMainWorldCSP, m_updateBehavior); m_loader->doUpdateFromElement(m_shouldBypassMainWorldCSP, m_updateBehavior, m_referrerPolicy);
} }
} }
...@@ -132,6 +134,7 @@ private: ...@@ -132,6 +134,7 @@ private:
UpdateFromElementBehavior m_updateBehavior; UpdateFromElementBehavior m_updateBehavior;
RefPtr<ScriptState> m_scriptState; RefPtr<ScriptState> m_scriptState;
WeakPtrFactory<Task> m_weakFactory; WeakPtrFactory<Task> m_weakFactory;
ReferrerPolicy m_referrerPolicy;
}; };
ImageLoader::ImageLoader(Element* element) ImageLoader::ImageLoader(Element* element)
...@@ -273,15 +276,15 @@ inline void ImageLoader::clearFailedLoadURL() ...@@ -273,15 +276,15 @@ inline void ImageLoader::clearFailedLoadURL()
m_failedLoadURL = AtomicString(); m_failedLoadURL = AtomicString();
} }
inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior) inline void ImageLoader::enqueueImageLoadingMicroTask(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
{ {
OwnPtr<Task> task = Task::create(this, updateBehavior); OwnPtr<Task> task = Task::create(this, updateBehavior, referrerPolicy);
m_pendingTask = task->createWeakPtr(); m_pendingTask = task->createWeakPtr();
Microtask::enqueueMicrotask(task.release()); Microtask::enqueueMicrotask(task.release());
m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->document()); m_loadDelayCounter = IncrementLoadEventDelayCount::create(m_element->document());
} }
void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, UpdateFromElementBehavior updateBehavior) void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
{ {
// FIXME: According to // FIXME: According to
// http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#the-img-element:the-img-element-55 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#the-img-element:the-img-element-55
...@@ -314,6 +317,10 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up ...@@ -314,6 +317,10 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up
// ImageLoader defers the load of images when in an ImageDocument. Don't defer this load on a forced reload. // ImageLoader defers the load of images when in an ImageDocument. Don't defer this load on a forced reload.
m_loadingImageDocument = false; m_loadingImageDocument = false;
} }
if (referrerPolicy != ReferrerPolicyDefault)
resourceRequest.setHTTPReferrer(SecurityPolicy::generateReferrer(referrerPolicy, url, document.outgoingReferrer()));
if (isHTMLPictureElement(element()->parentNode()) || !element()->fastGetAttribute(HTMLNames::srcsetAttr).isNull()) if (isHTMLPictureElement(element()->parentNode()) || !element()->fastGetAttribute(HTMLNames::srcsetAttr).isNull())
resourceRequest.setRequestContext(WebURLRequest::RequestContextImageSet); resourceRequest.setRequestContext(WebURLRequest::RequestContextImageSet);
FetchRequest request(resourceRequest, element()->localName(), resourceLoaderOptions); FetchRequest request(resourceRequest, element()->localName(), resourceLoaderOptions);
...@@ -389,7 +396,7 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up ...@@ -389,7 +396,7 @@ void ImageLoader::doUpdateFromElement(BypassMainWorldBehavior bypassBehavior, Up
updatedHasPendingEvent(); updatedHasPendingEvent();
} }
void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior) void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior, ReferrerPolicy referrerPolicy)
{ {
AtomicString imageSourceURL = m_element->imageSourceURL(); AtomicString imageSourceURL = m_element->imageSourceURL();
m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged); m_suppressErrorEvents = (updateBehavior == UpdateSizeChanged);
...@@ -409,7 +416,7 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior) ...@@ -409,7 +416,7 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior)
KURL url = imageSourceToKURL(imageSourceURL); KURL url = imageSourceToKURL(imageSourceURL);
if (shouldLoadImmediately(url)) { if (shouldLoadImmediately(url)) {
doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior); doUpdateFromElement(DoNotBypassMainWorldCSP, updateBehavior, referrerPolicy);
return; return;
} }
// Allow the idiom "img.src=''; img.src='.." to clear down the image before // Allow the idiom "img.src=''; img.src='.." to clear down the image before
...@@ -425,7 +432,7 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior) ...@@ -425,7 +432,7 @@ void ImageLoader::updateFromElement(UpdateFromElementBehavior updateBehavior)
// raw HTML parsing case by loading images we don't intend to display. // raw HTML parsing case by loading images we don't intend to display.
Document& document = m_element->document(); Document& document = m_element->document();
if (document.isActive()) if (document.isActive())
enqueueImageLoadingMicroTask(updateBehavior); enqueueImageLoadingMicroTask(updateBehavior, referrerPolicy);
} }
KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const KURL ImageLoader::imageSourceToKURL(AtomicString imageSourceURL) const
......
...@@ -85,7 +85,7 @@ public: ...@@ -85,7 +85,7 @@ public:
DoNotBypassMainWorldCSP DoNotBypassMainWorldCSP
}; };
void updateFromElement(UpdateFromElementBehavior = UpdateNormal); void updateFromElement(UpdateFromElementBehavior = UpdateNormal, ReferrerPolicy = ReferrerPolicyDefault);
void elementDidMoveToNewDocument(); void elementDidMoveToNewDocument();
...@@ -121,7 +121,7 @@ private: ...@@ -121,7 +121,7 @@ private:
class Task; class Task;
// Called from the task or from updateFromElement to initiate the load. // Called from the task or from updateFromElement to initiate the load.
void doUpdateFromElement(BypassMainWorldBehavior, UpdateFromElementBehavior); void doUpdateFromElement(BypassMainWorldBehavior, UpdateFromElementBehavior, ReferrerPolicy = ReferrerPolicyDefault);
virtual void dispatchLoadEvent() = 0; virtual void dispatchLoadEvent() = 0;
virtual void noImageResourceToLoad() { } virtual void noImageResourceToLoad() { }
...@@ -139,7 +139,7 @@ private: ...@@ -139,7 +139,7 @@ private:
void clearFailedLoadURL(); void clearFailedLoadURL();
void dispatchErrorEvent(); void dispatchErrorEvent();
void crossSiteOrCSPViolationOccurred(AtomicString); void crossSiteOrCSPViolationOccurred(AtomicString);
void enqueueImageLoadingMicroTask(UpdateFromElementBehavior); void enqueueImageLoadingMicroTask(UpdateFromElementBehavior, ReferrerPolicy);
void timerFired(Timer<ImageLoader>*); void timerFired(Timer<ImageLoader>*);
......
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