Skip to content

Commit

Permalink
Avoid compiling rules every time the extension is loaded if the rules…
Browse files Browse the repository at this point in the history
… haven't changed

https://bugs.webkit.org/show_bug.cgi?id=265473
rdar://118839289

Reviewed by Timothy Hatcher.

* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionContextCocoa.mm:
(WebKit::WebExtensionContext::declarativeNetRequestRuleStore):
(WebKit::computeStringHashForContentBlockerRules): Compute the hash for these content blocker rules, making sure to
append the current version of the rule translator, so when it is updated, rules will be re-compiled.
(WebKit::WebExtensionContext::compileDeclarativeNetRequestRules): Before compiling the rule, perform a lookup and check
the hash.
* Source/WebKit/UIProcess/Extensions/Cocoa/_WKWebExtensionDeclarativeNetRequestRule.mm:
* Source/WebKit/UIProcess/Extensions/WebExtensionContext.h:

Canonical link: https://commits.webkit.org/271248@main
  • Loading branch information
b-weinstein committed Nov 29, 2023
1 parent 4622c40 commit 10ce6ab
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,14 @@
static NSString * const backgroundContentEventListenersVersionKey = @"BackgroundContentEventListenersVersion";
static NSString * const lastSeenBaseURLStateKey = @"LastSeenBaseURL";
static NSString * const lastSeenVersionStateKey = @"LastSeenVersion";
static NSString * const lastLoadedDNRHashStateKey = @"LastLoadedDNRHash";

// Update this value when any changes are made to the WebExtensionEventListenerType enum.
static constexpr NSInteger currentBackgroundContentListenerStateVersion = 2;

// Update this value when any changes are made to the rule translation logic in _WKWebExtensionDeclarativeNetRequestRule.
static constexpr NSInteger currentDeclarativeNetRequestRuleTranslatorVersion = 1;

@interface _WKWebExtensionContextDelegate : NSObject <WKNavigationDelegate, WKUIDelegate> {
WeakPtr<WebKit::WebExtensionContext> _webExtensionContext;
}
Expand Down Expand Up @@ -2649,14 +2653,14 @@ static _WKWebExtensionContextError toAPI(WebExtensionContext::Error error)
WKContentRuleListStore *WebExtensionContext::declarativeNetRequestRuleStore()
{
if (m_declarativeNetRequestRuleStore)
return m_declarativeNetRequestRuleStore;
return m_declarativeNetRequestRuleStore.get();

String contentBlockerStorePath = m_extensionController->configuration().declarativeNetRequestStoreDirectory();
if (contentBlockerStorePath.isEmpty())
return nil;

m_declarativeNetRequestRuleStore = [WKContentRuleListStore storeWithURL:[NSURL fileURLWithPath:contentBlockerStorePath]];
return m_declarativeNetRequestRuleStore;
return m_declarativeNetRequestRuleStore.get();
}

void WebExtensionContext::removeDeclarativeNetRequestRules()
Expand All @@ -2683,10 +2687,21 @@ static _WKWebExtensionContextError toAPI(WebExtensionContext::Error error)
}];
}

void WebExtensionContext::compileDeclarativeNetRequestRules(NSArray *rulesData)
static NSString *computeStringHashForContentBlockerRules(NSString *rules)
{
// FIXME: rdar://118839289 - Avoid converting/compiling the rules data every time if the rules haven't changed.
SHA1 sha1;
sha1.addBytes(String(rules).span8());

SHA1::Digest digest;
sha1.computeHash(digest);

auto hashAsCString = SHA1::hexDigest(digest);
auto hashAsString = String::fromUTF8(hashAsCString);
return [hashAsString stringByAppendingString:[NSString stringWithFormat:@"-%zu", currentDeclarativeNetRequestRuleTranslatorVersion]];
}

void WebExtensionContext::compileDeclarativeNetRequestRules(NSArray *rulesData)
{
NSArray<NSString *> *jsonDeserializationErrorStrings;
auto *allJSONObjects = [_WKWebExtensionDeclarativeNetRequestTranslator jsonObjectsFromData:rulesData errorStrings:&jsonDeserializationErrorStrings];

Expand All @@ -2697,15 +2712,33 @@ static _WKWebExtensionContextError toAPI(WebExtensionContext::Error error)
if (!webKitRules)
return;

[declarativeNetRequestRuleStore() compileContentRuleListForIdentifier:uniqueIdentifier() encodedContentRuleList:webKitRules completionHandler:^(WKContentRuleList *ruleList, NSError *error) {
if (error) {
RELEASE_LOG_ERROR(Extensions, "Error compiling declarativeNetRequest rules: %{public}@", privacyPreservingDescription(error));
return;
auto *previouslyLoadedHash = objectForKey<NSString>(m_state, lastLoadedDNRHashStateKey);
auto *hashOfWebKitRules = computeStringHashForContentBlockerRules(webKitRules);

[declarativeNetRequestRuleStore() lookUpContentRuleListForIdentifier:uniqueIdentifier() completionHandler:^(WKContentRuleList *foundRuleList, NSError *) {
if (foundRuleList) {
if ([previouslyLoadedHash isEqualToString:hashOfWebKitRules]) {
auto userContentControllers = hasAccessInPrivateBrowsing() ? extensionController()->allUserContentControllers() : extensionController()->allNonPrivateUserContentControllers();
for (auto& userContentController : userContentControllers)
userContentController.addContentRuleList(*foundRuleList->_contentRuleList, m_baseURL);

return;
}
}

auto userContentControllers = hasAccessInPrivateBrowsing() ? extensionController()->allUserContentControllers() : extensionController()->allNonPrivateUserContentControllers();
for (auto& userContentController : userContentControllers)
userContentController.addContentRuleList(*ruleList->_contentRuleList, m_baseURL);
[declarativeNetRequestRuleStore() compileContentRuleListForIdentifier:uniqueIdentifier() encodedContentRuleList:webKitRules completionHandler:^(WKContentRuleList *ruleList, NSError *error) {
if (error) {
RELEASE_LOG_ERROR(Extensions, "Error compiling declarativeNetRequest rules: %{public}@", privacyPreservingDescription(error));
return;
}

[m_state setObject:hashOfWebKitRules forKey:lastLoadedDNRHashStateKey];
writeStateToStorage();

auto userContentControllers = hasAccessInPrivateBrowsing() ? extensionController()->allUserContentControllers() : extensionController()->allNonPrivateUserContentControllers();
for (auto& userContentController : userContentControllers)
userContentController.addContentRuleList(*ruleList->_contentRuleList, m_baseURL);
}];
}];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#import "WKContentRuleListInternal.h"
#import "WebExtensionUtilities.h"

// If any changes are made to the rule translation logic here, make sure to increment currentDeclarativeNetRequestRuleTranslatorVersion in WebExtensionContextCocoa.

// Keys in the top level rule dictionary.
static NSString * const declarativeNetRequestRuleIDKey = @"id";
static NSString * const declarativeNetRequestRulePriorityKey = @"priority";
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKit/UIProcess/Extensions/WebExtensionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
CommandsVector m_commands;
bool m_populatedCommands { false };

WKContentRuleListStore *m_declarativeNetRequestRuleStore;
RetainPtr<WKContentRuleListStore> m_declarativeNetRequestRuleStore;
};

template<typename T>
Expand Down

0 comments on commit 10ce6ab

Please sign in to comment.