| Index: lib/requestBlocker.js | 
| =================================================================== | 
| --- a/lib/requestBlocker.js | 
| +++ b/lib/requestBlocker.js | 
| @@ -65,17 +65,17 @@ | 
|  | 
| for (let type in browser.webRequest.ResourceType) | 
| yield resourceTypes.get(browser.webRequest.ResourceType[type]) || "OTHER"; | 
|  | 
| // WEBRTC gets addressed through a workaround, even if the webRequest API is | 
| // lacking support to block this kind of a request. | 
| yield "WEBRTC"; | 
|  | 
| -  // POPUP, CSP and ELEMHIDE filters aren't mapped to resource types. | 
| +  // These filter types aren't mapped to resource types. | 
| yield "POPUP"; | 
| yield "ELEMHIDE"; | 
| yield "CSP"; | 
| }()); | 
|  | 
| function getDocumentInfo(page, frame, originUrl) | 
| { | 
| return [ | 
| @@ -118,25 +118,25 @@ | 
| // an origin (proto + host). | 
| else | 
| return Promise.resolve([]); | 
|  | 
| return browser.tabs.query({url}).then(tabs => tabs.map(tab => tab.id)); | 
| } | 
|  | 
| function logRequest(tabIds, url, type, docDomain, thirdParty, | 
| -                    sitekey, specificOnly, filter) | 
| +                    sitekey, specificOnly, filter, rewrittenTo) | 
| { | 
| if (filter) | 
| FilterNotifier.emit("filter.hitCount", filter, 0, 0, tabIds); | 
|  | 
| devtools.logRequest( | 
| tabIds, url, type, docDomain, | 
| thirdParty, sitekey, | 
| -    specificOnly, filter | 
| +    specificOnly, filter, rewrittenTo | 
| ); | 
| } | 
|  | 
| browser.webRequest.onBeforeRequest.addListener(details => | 
| { | 
| // Never block top-level documents. | 
| if (details.type == "main_frame") | 
| return; | 
| @@ -189,24 +189,42 @@ | 
| return; | 
|  | 
| let type = resourceTypes.get(details.type) || "OTHER"; | 
| let [docDomain, sitekey, specificOnly] = getDocumentInfo(page, frame, | 
| originUrl); | 
| let [filter, urlString, thirdParty] = matchRequest(url, type, docDomain, | 
| sitekey, specificOnly); | 
|  | 
| +  let result; | 
| +  let rewrittenTo; | 
| + | 
| +  if (filter instanceof BlockingFilter) | 
| +  { | 
| +    if (filter.rewrite) | 
| +    { | 
| +      let rewritten = filter.rewriteUrl(urlString); | 
| +      if (rewritten == urlString) | 
| +        // we couldn't do the rewrite, so just let it through. | 
| +        return; | 
| + | 
| +      rewrittenTo = rewritten; | 
| +      result = {redirectUrl: rewritten}; | 
| +    } | 
| +    else | 
| +      result = {cancel: true}; | 
| +  } | 
| + | 
| getRelatedTabIds(details).then(tabIds => | 
| { | 
| logRequest(tabIds, urlString, type, docDomain, | 
| -               thirdParty, sitekey, specificOnly, filter); | 
| +               thirdParty, sitekey, specificOnly, filter, rewrittenTo); | 
| }); | 
|  | 
| -  if (filter instanceof BlockingFilter) | 
| -    return {cancel: true}; | 
| +  return result; | 
| }, {urls: ["<all_urls>"]}, ["blocking"]); | 
|  | 
| port.on("filters.collapse", (message, sender) => | 
| { | 
| let {page, frame} = sender; | 
|  | 
| if (checkWhitelisted(page, frame)) | 
| return false; | 
|  |