Diff
Modified: trunk/Source/WebCore/ChangeLog (291199 => 291200)
--- trunk/Source/WebCore/ChangeLog 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebCore/ChangeLog 2022-03-12 00:32:18 UTC (rev 291200)
@@ -1,3 +1,28 @@
+2022-03-11 Alex Christensen <achristen...@webkit.org>
+
+ Finish implementing modify-headers actions for WKContentRuleList SPI
+ https://bugs.webkit.org/show_bug.cgi?id=237784
+ <rdar://72433048>
+
+ Reviewed by Tim Hatcher.
+
+ I hadn't implemented regex substitution yet.
+
+ * contentextensions/ContentExtensionActions.cpp:
+ (WebCore::ContentExtensions::RedirectAction::parse):
+ (WebCore::ContentExtensions::RedirectAction::serialize const):
+ (WebCore::ContentExtensions::RedirectAction::deserialize):
+ (WebCore::ContentExtensions::RedirectAction::applyToRequest):
+ (WebCore::ContentExtensions::RedirectAction::RegexSubstitutionAction::serialize const):
+ (WebCore::ContentExtensions::RedirectAction::RegexSubstitutionAction::deserialize):
+ (WebCore::ContentExtensions::makeJSString):
+ (WebCore::ContentExtensions::RedirectAction::RegexSubstitutionAction::applyToURL const):
+ * contentextensions/ContentExtensionActions.h:
+ (WebCore::ContentExtensions::add):
+ * contentextensions/ContentExtensionParser.cpp:
+ (WebCore::ContentExtensions::loadAction):
+ (WebCore::ContentExtensions::loadRule):
+
2022-03-11 Nikolaos Mouchtaris <nmouchta...@apple.com>
[iOS] Fix ovserscroll-behavior for main document
Modified: trunk/Source/WebCore/contentextensions/ContentExtensionActions.cpp (291199 => 291200)
--- trunk/Source/WebCore/contentextensions/ContentExtensionActions.cpp 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionActions.cpp 2022-03-12 00:32:18 UTC (rev 291200)
@@ -30,6 +30,8 @@
#include "ContentExtensionError.h"
#include "ResourceRequest.h"
+#include <_javascript_Core/JSRetainPtr.h>
+#include <_javascript_Core/_javascript_.h>
#include <wtf/CrossThreadCopier.h>
#include <wtf/URL.h>
#include <wtf/URLParser.h>
@@ -285,7 +287,7 @@
return deserializeLength(span, 0);
}
-Expected<RedirectAction, std::error_code> RedirectAction::parse(const JSON::Object& redirectObject)
+Expected<RedirectAction, std::error_code> RedirectAction::parse(const JSON::Object& redirectObject, const String& urlFilter)
{
auto redirect = redirectObject.getObject("redirect");
if (!redirect)
@@ -298,7 +300,7 @@
}
if (auto regexSubstitution = redirect->getString("regex-substitution"); !!regexSubstitution)
- return RedirectAction { RegexSubstitutionAction { WTFMove(regexSubstitution) } };
+ return RedirectAction { RegexSubstitutionAction { WTFMove(regexSubstitution), urlFilter } };
if (auto transform = redirect->getObject("transform")) {
auto parsedTransform = URLTransformAction::parse(*transform);
@@ -343,7 +345,7 @@
std::visit(WTF::makeVisitor([&](const ExtensionPathAction& action) {
append(vector, action.extensionPath.utf8());
}, [&](const RegexSubstitutionAction& action) {
- append(vector, action.regexSubstitution.utf8());
+ action.serialize(vector);
}, [&](const URLTransformAction& action) {
action.serialize(vector);
}, [&](const URLAction& action) {
@@ -362,7 +364,7 @@
case WTF::alternativeIndexV<ExtensionPathAction, ActionVariant>:
return ExtensionPathAction { deserializeUTF8String(span, headerSize, stringLength) };
case WTF::alternativeIndexV<RegexSubstitutionAction, ActionVariant>:
- return RegexSubstitutionAction { deserializeUTF8String(span, headerSize, stringLength) };
+ return RegexSubstitutionAction::deserialize(span.subspan(headerSize));
case WTF::alternativeIndexV<URLTransformAction, ActionVariant>:
return URLTransformAction::deserialize(span.subspan(headerSize));
case WTF::alternativeIndexV<URLAction, ActionVariant>:
@@ -383,8 +385,10 @@
auto url = ""
url.setPath(action.extensionPath);
request.setURL(WTFMove(url));
- }, [&] (const RegexSubstitutionAction&) {
- // FIXME: Implement, ideally in a way that doesn't require making a new VM and global object for each redirect operation.
+ }, [&] (const RegexSubstitutionAction& action) {
+ auto url = ""
+ action.applyToURL(url);
+ request.setURL(WTFMove(url));
}, [&] (const URLTransformAction& action) {
auto url = ""
action.applyToURL(url);
@@ -394,6 +398,88 @@
}), action);
}
+void RedirectAction::RegexSubstitutionAction::serialize(Vector<uint8_t>& vector) const
+{
+ auto regexSubstitutionUTF8 = regexSubstitution.utf8();
+ auto regexFilterUTF8 = regexFilter.utf8();
+ vector.reserveCapacity(vector.size()
+ + sizeof(uint32_t)
+ + sizeof(uint32_t)
+ + regexSubstitutionUTF8.length()
+ + regexFilterUTF8.length());
+ uncheckedAppend(vector, regexSubstitutionUTF8.length());
+ uncheckedAppend(vector, regexFilterUTF8.length());
+ uncheckedAppend(vector, regexSubstitutionUTF8);
+ uncheckedAppend(vector, regexFilterUTF8);
+}
+
+auto RedirectAction::RegexSubstitutionAction::deserialize(Span<const uint8_t> span) -> RegexSubstitutionAction
+{
+ auto regexSubstitutionLength = deserializeLength(span, 0);
+ auto regexFilterLength = deserializeLength(span, sizeof(uint32_t));
+ constexpr auto headerSize = sizeof(uint32_t) + sizeof(uint32_t);
+ auto regexSubstitution = deserializeUTF8String(span, headerSize, regexSubstitutionLength);
+ auto regexFilter = deserializeUTF8String(span, headerSize + regexSubstitutionLength, regexFilterLength);
+ return { WTFMove(regexSubstitution), WTFMove(regexFilter) };
+}
+
+static JSRetainPtr<JSStringRef> makeJSString(const char* utf8)
+{
+ return adopt(JSStringCreateWithUTF8CString(utf8));
+}
+
+static JSRetainPtr<JSStringRef> makeJSString(const String& string)
+{
+ return makeJSString(string.utf8().data());
+}
+
+void RedirectAction::RegexSubstitutionAction::applyToURL(URL& url) const
+{
+ static JSContextGroupRef contextGroup = nullptr;
+ static JSGlobalContextRef context = nullptr;
+ if (!contextGroup || !context) {
+ contextGroup = JSContextGroupCreate();
+ context = JSGlobalContextCreateInGroup(contextGroup, nullptr);
+ }
+
+ auto toObject = [&] (JSValueRef value) {
+ return JSValueToObject(context, value, nullptr);
+ };
+ auto getProperty = [&] (JSValueRef value, const char* name) {
+ return JSObjectGetProperty(context, toObject(value), makeJSString(name).get(), nullptr);
+ };
+ auto getArrayValue = [&] (JSValueRef value, size_t index) {
+ return JSObjectGetPropertyAtIndex(context, toObject(value), index, nullptr);
+ };
+ auto valueToWTFString = [&] (JSValueRef value) {
+ auto string = adopt(JSValueToStringCopy(context, value, nullptr));
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string.get());
+ Vector<char> buffer(bufferSize);
+ JSStringGetUTF8CString(string.get(), buffer.data(), buffer.size());
+ return String::fromUTF8(buffer.data());
+ };
+
+ // Effectively execute this _javascript_:
+ // const regexp = new RegExp(regexFilter);
+ // const result = url.match(regexp);
+ JSValueRef regexFilterValue = JSValueMakeString(context, makeJSString(regexFilter).get());
+ JSObjectRef regexp = JSObjectMakeRegExp(context, 1, ®exFilterValue, nullptr);
+ JSValueRef urlValue = JSValueMakeString(context, makeJSString(url.string()).get());
+ JSObjectRef matchFunction = JSValueToObject(context, getProperty(urlValue, "match"), nullptr);
+ JSValueRef result = JSObjectCallAsFunction(context, matchFunction, toObject(urlValue), 1, ®exp, nullptr);
+ if (!JSValueIsArray(context, result))
+ return;
+
+ String substitution = regexSubstitution;
+ size_t resultLength = JSValueToNumber(context, getProperty(result, "length"), nullptr);
+ for (size_t i = 0; i < std::min<size_t>(10, resultLength); i++)
+ substitution.replace(makeString('\\', i), valueToWTFString(getArrayValue(result, i)));
+
+ URL replacementURL(substitution);
+ if (replacementURL.isValid())
+ url = ""
+}
+
auto RedirectAction::URLTransformAction::parse(const JSON::Object& transform) -> Expected<URLTransformAction, std::error_code>
{
URLTransformAction action;
Modified: trunk/Source/WebCore/contentextensions/ContentExtensionActions.h (291199 => 291200)
--- trunk/Source/WebCore/contentextensions/ContentExtensionActions.h 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionActions.h 2022-03-12 00:32:18 UTC (rev 291200)
@@ -139,10 +139,14 @@
};
struct RegexSubstitutionAction {
String regexSubstitution;
+ String regexFilter;
- RegexSubstitutionAction isolatedCopy() const & { return { regexSubstitution.isolatedCopy() }; }
- RegexSubstitutionAction isolatedCopy() && { return { WTFMove(regexSubstitution).isolatedCopy() }; }
- bool operator==(const RegexSubstitutionAction& other) const { return other.regexSubstitution == this->regexSubstitution; }
+ RegexSubstitutionAction isolatedCopy() const & { return { regexSubstitution.isolatedCopy(), regexFilter.isolatedCopy() }; }
+ RegexSubstitutionAction isolatedCopy() && { return { WTFMove(regexSubstitution).isolatedCopy(), WTFMove(regexFilter).isolatedCopy() }; }
+ void serialize(Vector<uint8_t>&) const;
+ static RegexSubstitutionAction deserialize(Span<const uint8_t>);
+ bool operator==(const RegexSubstitutionAction& other) const { return other.regexSubstitution == this->regexSubstitution && other.regexFilter == this->regexFilter; }
+ WEBCORE_EXPORT void applyToURL(URL&) const;
};
struct URLTransformAction {
struct QueryTransform {
@@ -214,7 +218,7 @@
RedirectAction(DeletedValueTag) : hashTableType(HashTableType::Deleted) { }
bool isDeletedValue() const { return hashTableType == HashTableType::Deleted; }
- static Expected<RedirectAction, std::error_code> parse(const JSON::Object&);
+ static Expected<RedirectAction, std::error_code> parse(const JSON::Object&, const String& urlFilter);
RedirectAction isolatedCopy() const &;
RedirectAction isolatedCopy() &&;
bool operator==(const RedirectAction&) const;
@@ -262,7 +266,7 @@
inline void add(Hasher& hasher, const RedirectAction::RegexSubstitutionAction& action)
{
- add(hasher, action.regexSubstitution);
+ add(hasher, action.regexSubstitution, action.regexFilter);
}
inline void add(Hasher& hasher, const RedirectAction::URLTransformAction::QueryTransform::QueryKeyValue& queryKeyValue)
Modified: trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp (291199 => 291200)
--- trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebCore/contentextensions/ContentExtensionParser.cpp 2022-03-12 00:32:18 UTC (rev 291200)
@@ -210,7 +210,7 @@
return !!parser.parseSelector(selector);
}
-static std::optional<Expected<Action, std::error_code>> loadAction(const JSON::Object& ruleObject)
+static std::optional<Expected<Action, std::error_code>> loadAction(const JSON::Object& ruleObject, const String& urlFilter)
{
auto actionObject = ruleObject.getObject("action");
if (!actionObject)
@@ -241,7 +241,7 @@
return Action { NotifyAction { { WTFMove(notification) } } };
}
if (actionType == "redirect") {
- auto action = ""
+ auto action = "" urlFilter);
if (!action)
return makeUnexpected(action.error());
return Action { RedirectAction { WTFMove(*action) } };
@@ -261,7 +261,7 @@
if (!trigger.has_value())
return makeUnexpected(trigger.error());
- auto action = ""
+ auto action = "" trigger->urlFilter);
if (!action)
return std::nullopt;
if (!action->has_value())
Modified: trunk/Source/WebKit/ChangeLog (291199 => 291200)
--- trunk/Source/WebKit/ChangeLog 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebKit/ChangeLog 2022-03-12 00:32:18 UTC (rev 291200)
@@ -1,3 +1,13 @@
+2022-03-11 Alex Christensen <achristen...@webkit.org>
+
+ Finish implementing modify-headers actions for WKContentRuleList SPI
+ https://bugs.webkit.org/show_bug.cgi?id=237784
+ <rdar://72433048>
+
+ Reviewed by Tim Hatcher.
+
+ * UIProcess/API/APIContentRuleListStore.h:
+
2022-03-11 Nikolaos Mouchtaris <nmouchta...@apple.com>
[iOS] Fix ovserscroll-behavior for main document
Modified: trunk/Source/WebKit/UIProcess/API/APIContentRuleListStore.h (291199 => 291200)
--- trunk/Source/WebKit/UIProcess/API/APIContentRuleListStore.h 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Source/WebKit/UIProcess/API/APIContentRuleListStore.h 2022-03-12 00:32:18 UTC (rev 291200)
@@ -54,7 +54,7 @@
#if ENABLE(CONTENT_EXTENSIONS)
// This should be incremented every time a functional change is made to the bytecode, file format, etc.
// to prevent crashing while loading old data.
- static constexpr uint32_t CurrentContentRuleListFileVersion = 14;
+ static constexpr uint32_t CurrentContentRuleListFileVersion = 15;
static ContentRuleListStore& defaultStore();
static Ref<ContentRuleListStore> storeWithPath(const WTF::String& storePath);
Modified: trunk/Tools/ChangeLog (291199 => 291200)
--- trunk/Tools/ChangeLog 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Tools/ChangeLog 2022-03-12 00:32:18 UTC (rev 291200)
@@ -1,3 +1,13 @@
+2022-03-11 Alex Christensen <achristen...@webkit.org>
+
+ Finish implementing modify-headers actions for WKContentRuleList SPI
+ https://bugs.webkit.org/show_bug.cgi?id=237784
+
+ Reviewed by Tim Hatcher.
+
+ * TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
+ (TestWebKitAPI::TEST_F):
+
2022-03-11 Adrian Perez de Castro <ape...@igalia.com>
[GLib] Expose ArrayBuffer in the public API
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp (291199 => 291200)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp 2022-03-12 00:32:18 UTC (rev 291200)
@@ -3039,7 +3039,7 @@
EXPECT_EQ(deserialized, action);
};
checkRedirectActionSerialization({ { RedirectAction::ExtensionPathAction { "extensionPath" } } }, 18);
- checkRedirectActionSerialization({ { RedirectAction::RegexSubstitutionAction { "regexSubstitution" } } }, 22);
+ checkRedirectActionSerialization({ { RedirectAction::RegexSubstitutionAction { "regexSubstitution", "regexFilter" } } }, 41);
checkRedirectActionSerialization({ { RedirectAction::URLAction { "url" } } }, 8);
checkRedirectActionSerialization({ { RedirectAction::URLTransformAction {
"frägment",
@@ -3097,6 +3097,22 @@
testRequest(matchingEverything, requestInTopAndFrameURLs("http://example.com/", "https://webkit.org/", "https://webkit.org/"), { });
}
+TEST_F(ContentExtensionTest, RegexSubstitution)
+{
+ auto transformURL = [] (String&& regexSubstitution, String&& regexFilter, String&& originalURL, const char* expectedTransformedURL) {
+ WebCore::ContentExtensions::RedirectAction::RegexSubstitutionAction action { WTFMove(regexSubstitution), WTFMove(regexFilter) };
+ URL url(WTFMove(originalURL));
+ action.applyToURL(url);
+ EXPECT_STREQ(url.string().utf8().data(), expectedTransformedURL);
+ };
+ transformURL("https://\\1.xyz.com/", "^https://www\\.(abc?)\\.xyz\\.com/", "https://www.abc.xyz.com", "https://abc.xyz.com/");
+ transformURL("https://\\1.\\1.xyz.com/", "^https://www\\.(abc?)\\.xyz\\.com/", "https://www.ab.xyz.com", "https://ab.ab.xyz.com/");
+ transformURL("https://\\1.\\1.xyz.com/", "^https://www\\.(abc?)\\.xyz\\.com/", "https://ab.xyz.com", "https://ab.xyz.com/");
+ transformURL("https://example.com/\\0\\1", "^https://www\\.(abc?)\\.xyz\\.com/", "https://www.ab.xyz.com", "https://example.com/https://www.ab.xyz.com/ab");
+ transformURL("https://example.com/\\1\\2\\3\\4\\5\\6\\7\\8\\9\\10\\11\\12\\13\\14", "^https://(e)(x)(a)(m)(p)(l)(e)(w)(e)(b)(s)(i)(t)(e)/", "https://examplewebsite/", "https://example.com/examplewee0e1e2e3e4");
+ transformURL("https://!@#$%^&*invalidURL\\1/", "^https://www\\.(abc?)\\.xyz\\.com/", "https://www.abc.xyz.com", "https://www.abc.xyz.com/");
+}
+
} // namespace TestWebKitAPI
#endif // ENABLE(CONTENT_EXTENSIONS)
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKContentExtensionStore.mm (291199 => 291200)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKContentExtensionStore.mm 2022-03-12 00:00:08 UTC (rev 291199)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKContentExtensionStore.mm 2022-03-12 00:32:18 UTC (rev 291200)
@@ -650,6 +650,9 @@
}
} } },
"trigger": { "url-filter": "8.txt" }
+ }, {
+ "action": { "type": "redirect", "redirect": { "regex-substitution": "testscheme://replaced-by-regex/\\1.txt" } },
+ "trigger": { "url-filter": "(9).txt" }
} ]
)JSON");
@@ -674,12 +677,13 @@
try { await fetch('6.txt#fragment-should-be-removed') } catch(e) { };
try { await fetch('7.txt') } catch(e) { };
try { await fetch('8.txt?key-to-replace-_only_=pre-replacement-value') } catch(e) { };
+ try { await fetch('9.txt') } catch(e) { };
}
fetchSubresources();
</script>
)HTML");
}
- if ([path isEqualToString:@"/8.txt"])
+ if ([path isEqualToString:@"/9.txt"])
receivedAllRequests = true;
respond(task, "");
};
@@ -713,6 +717,7 @@
"testscheme://:testpassword@testhost/6.txt",
"testscheme://testhost/7.txt?#",
"testscheme://testhost/8.txt?key-to-replace-_only_=value-to-replace-only&key-to-add=value-to-add",
+ "testscheme://replaced-by-regex/9.txt",
};
EXPECT_EQ(expectedRequestedURLs.size(), [urls count]);
for (size_t i = 0; i < expectedRequestedURLs.size(); i++)