Bug 1076583 - Fix CSP tests regression from the previous patches. r=smaug

Add a way to override the JS calling location temporarily, and use it to
propagate it to the image load task.

Differential Revision: https://phabricator.services.mozilla.com/D218416
This commit is contained in:
Emilio Cobos Álvarez 2024-08-05 12:23:45 +00:00
parent 64ca3f2d61
commit cce3bd162f
9 changed files with 54 additions and 24 deletions

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/SourceLocation.h"
#include "mozilla/ThreadLocal.h"
#include "nsContentUtils.h"
#include "jsapi.h"
@ -21,12 +22,30 @@ SourceLocation::SourceLocation(nsCOMPtr<nsIURI>&& aResource, uint32_t aLine,
uint32_t aCol)
: mResource(std::move(aResource)), mLine(aLine), mColumn(aCol) {}
static MOZ_THREAD_LOCAL(const JSCallingLocation*) tlsFallback;
const JSCallingLocation* JSCallingLocation::GetFallback() {
if (!tlsFallback.initialized()) {
return nullptr;
}
return tlsFallback.get();
}
void JSCallingLocation::SetFallback(const JSCallingLocation* aFallback) {
if (!tlsFallback.init()) {
return;
}
tlsFallback.set(aFallback);
}
JSCallingLocation JSCallingLocation::Get() {
return Get(nsContentUtils::GetCurrentJSContext());
}
JSCallingLocation JSCallingLocation::Get(JSContext* aCx) {
JSCallingLocation result;
if (const JSCallingLocation* loc = GetFallback()) {
result = *loc;
}
if (!aCx) {
return result;
}

View File

@ -40,6 +40,22 @@ struct JSCallingLocation : SourceLocation {
static JSCallingLocation Get();
static JSCallingLocation Get(JSContext*);
class MOZ_STACK_CLASS AutoFallback {
public:
explicit AutoFallback(const JSCallingLocation* aFallback)
: mOldFallback(GetFallback()) {
SetFallback(aFallback);
}
~AutoFallback() { SetFallback(mOldFallback); }
private:
const JSCallingLocation* mOldFallback;
};
private:
static const JSCallingLocation* GetFallback();
static void SetFallback(const JSCallingLocation*);
};
} // namespace mozilla

View File

@ -83,14 +83,15 @@ class ImageLoadTask final : public MicroTaskRunnable {
ImageLoadTask(HTMLImageElement* aElement, bool aAlwaysLoad,
bool aUseUrgentStartForChannel)
: mElement(aElement),
mDocument(aElement->OwnerDoc()),
mAlwaysLoad(aAlwaysLoad),
mUseUrgentStartForChannel(aUseUrgentStartForChannel) {
mDocument = aElement->OwnerDoc();
mDocument->BlockOnload();
}
void Run(AutoSlowOperation& aAso) override {
if (mElement->mPendingImageLoadTask == this) {
JSCallingLocation::AutoFallback fallback(&mCallingLocation);
mElement->mPendingImageLoadTask = nullptr;
mElement->mUseUrgentStartForChannel = mUseUrgentStartForChannel;
mElement->LoadSelectedImage(mAlwaysLoad);
@ -107,13 +108,13 @@ class ImageLoadTask final : public MicroTaskRunnable {
private:
~ImageLoadTask() = default;
RefPtr<HTMLImageElement> mElement;
nsCOMPtr<Document> mDocument;
bool mAlwaysLoad;
// True if we want to set nsIClassOfService::UrgentStart to the channel to
// get the response ASAP for better user responsiveness.
bool mUseUrgentStartForChannel;
const RefPtr<HTMLImageElement> mElement;
const RefPtr<Document> mDocument;
const JSCallingLocation mCallingLocation{JSCallingLocation::Get()};
const bool mAlwaysLoad;
// True if we want to set nsIClassOfService::UrgentStart to the channel to get
// the response ASAP for better user responsiveness.
const bool mUseUrgentStartForChannel;
};
HTMLImageElement::HTMLImageElement(

View File

@ -1,3 +0,0 @@
[securitypolicyviolation-block-cross-origin-image-from-script.sub.html]
[Non-redirected cross-origin URLs are not stripped.]
expected: FAIL

View File

@ -1,3 +0,0 @@
[securitypolicyviolation-block-cross-origin-image.sub.html]
[Non-redirected cross-origin URLs are not stripped.]
expected: FAIL

View File

@ -1,3 +0,0 @@
[securitypolicyviolation-block-image-from-script.sub.html]
[Non-redirected cross-origin URLs are not stripped.]
expected: FAIL

View File

@ -1,3 +0,0 @@
[securitypolicyviolation-block-image.sub.html]
[Non-redirected same-origin URLs are not stripped.]
expected: FAIL

View File

@ -16,8 +16,11 @@
assert_equals(e.originalPolicy, "img-src \'none\'");
assert_equals(e.disposition, "enforce");
assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
assert_equals(e.lineNumber, 2);
assert_equals(e.columnNumber, 1);
// Per https://html.spec.whatwg.org/#relevant-mutations:
// The img or source HTML element insertion steps or HTML element removing steps count the mutation as a relevant mutation.
// So when the src load is async, line 3 (appendChild, and thus the insertion steps) is what triggers the relevant load, not the src setter.
assert_equals(e.lineNumber, 3);
assert_equals(e.columnNumber, 15);
assert_equals(e.statusCode, 200);
}));

View File

@ -16,8 +16,11 @@
assert_equals(e.originalPolicy, "img-src \'none\'");
assert_equals(e.disposition, "enforce");
assert_equals(new URL(e.sourceFile).pathname, "/content-security-policy/support/inject-image.sub.js");
assert_equals(e.lineNumber, 2);
assert_equals(e.columnNumber, 1);
// Per https://html.spec.whatwg.org/#relevant-mutations:
// The img or source HTML element insertion steps or HTML element removing steps count the mutation as a relevant mutation.
// So when the src load is async, line 3 (appendChild, and thus the insertion steps) is what triggers the relevant load, not the src setter.
assert_equals(e.lineNumber, 3);
assert_equals(e.columnNumber, 15);
assert_equals(e.statusCode, 200);
}));