Title: [291200] trunk
Revision
291200
Author
commit-qu...@webkit.org
Date
2022-03-11 16:32:18 -0800 (Fri, 11 Mar 2022)

Log Message

Finish implementing modify-headers actions for WKContentRuleList SPI
https://bugs.webkit.org/show_bug.cgi?id=237784
Source/WebCore:

<rdar://72433048>

Patch by Alex Christensen <achristen...@webkit.org> on 2022-03-11
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):

Source/WebKit:

<rdar://72433048>

Patch by Alex Christensen <achristen...@webkit.org> on 2022-03-11
Reviewed by Tim Hatcher.

* UIProcess/API/APIContentRuleListStore.h:

Tools:

Patch by Alex Christensen <achristen...@webkit.org> on 2022-03-11
Reviewed by Tim Hatcher.

* TestWebKitAPI/Tests/WebCore/ContentExtensions.cpp:
(TestWebKitAPI::TEST_F):

Modified Paths

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, &regexFilterValue, 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, &regexp, 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++)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to