Skip to content

Commit

Permalink
Merge pull request #1377 from brave/adblock_200ok
Browse files Browse the repository at this point in the history
Issue 2554: Replace data urls with HTTP 200 OK in adblocker.
  • Loading branch information
iefremov authored Jan 28, 2019
2 parents b57fc20 + 55cc6ef commit 461df53
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 27 deletions.
34 changes: 8 additions & 26 deletions browser/net/brave_ad_block_tp_network_delegate_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,6 @@

using content::ResourceType;

namespace {

bool IsImageResourceType(ResourceType resource_type) {
return resource_type == content::RESOURCE_TYPE_FAVICON ||
resource_type == content::RESOURCE_TYPE_IMAGE;
}
GURL GetBlankDataURLForResourceType(ResourceType resource_type) {
return GURL(IsImageResourceType(resource_type) ?
kEmptyImageDataURI : kEmptyDataURI);
}

} // namespace

namespace brave {

std::string GetGoogleTagManagerPolyfillJS() {
Expand Down Expand Up @@ -101,14 +88,12 @@ void OnBeforeURLRequestAdBlockTPOnTaskRunner(std::shared_ptr<BraveRequestInfo> c
std::string tab_host = ctx->tab_origin.host();
if (!g_brave_browser_process->tracking_protection_service()->
ShouldStartRequest(ctx->request_url, ctx->resource_type, tab_host)) {
ctx->new_url_spec = GetBlankDataURLForResourceType(ctx->resource_type).spec();
ctx->blocked_by = kTrackerBlocked;
} else if (!g_brave_browser_process->ad_block_service()->ShouldStartRequest(
ctx->request_url, ctx->resource_type, tab_host) ||
!g_brave_browser_process->ad_block_regional_service()
->ShouldStartRequest(ctx->request_url, ctx->resource_type,
tab_host)) {
ctx->new_url_spec = GetBlankDataURLForResourceType(ctx->resource_type).spec();
ctx->blocked_by = kAdBlocked;
}
}
Expand All @@ -117,17 +102,14 @@ void OnBeforeURLRequestDispatchOnIOThread(
const ResponseCallback& next_callback,
std::shared_ptr<BraveRequestInfo> ctx) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!ctx->new_url_spec.empty() &&
ctx->new_url_spec != ctx->request_url.spec()) {
if (ctx->blocked_by == kAdBlocked) {
brave_shields::DispatchBlockedEventFromIO(ctx->request_url,
ctx->render_frame_id, ctx->render_process_id, ctx->frame_tree_node_id,
brave_shields::kAds);
} else if (ctx->blocked_by == kTrackerBlocked) {
brave_shields::DispatchBlockedEventFromIO(ctx->request_url,
ctx->render_frame_id, ctx->render_process_id, ctx->frame_tree_node_id,
brave_shields::kTrackers);
}
if (ctx->blocked_by == kAdBlocked) {
brave_shields::DispatchBlockedEventFromIO(ctx->request_url,
ctx->render_frame_id, ctx->render_process_id, ctx->frame_tree_node_id,
brave_shields::kAds);
} else if (ctx->blocked_by == kTrackerBlocked) {
brave_shields::DispatchBlockedEventFromIO(ctx->request_url,
ctx->render_frame_id, ctx->render_process_id, ctx->frame_tree_node_id,
brave_shields::kTrackers);
}

next_callback.Run();
Expand Down
9 changes: 8 additions & 1 deletion browser/net/brave_network_delegate_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,15 @@ void BraveNetworkDelegateBase::RunNextCallback(
IsRequestIdentifierValid(ctx->request_identifier)) {
*ctx->new_url = GURL(ctx->new_url_spec);
}
if (ctx->blocked_by == brave::kAdBlocked ||
ctx->blocked_by == brave::kTrackerBlocked) {
// We are going to intercept this request and block it later in the
// network stack.
request->SetExtraRequestHeaderByName("X-Brave-Block", "", true);
}
rv = ChromeNetworkDelegate::OnBeforeURLRequest(request,
std::move(wrapped_callback), ctx->new_url);
std::move(wrapped_callback),
ctx->new_url);
} else if (ctx->event_type == brave::kOnBeforeStartTransaction) {
rv = ChromeNetworkDelegate::OnBeforeStartTransaction(request,
std::move(wrapped_callback), ctx->headers);
Expand Down
2 changes: 2 additions & 0 deletions components/brave_shields/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ source_set("brave_shields") {
"ad_block_regional_service.h",
"ad_block_service.cc",
"ad_block_service.h",
"adblock_interceptor.cc",
"adblock_interceptor.h",
"base_brave_shields_service.cc",
"base_brave_shields_service.h",
"base_local_data_files_observer.cc",
Expand Down
205 changes: 205 additions & 0 deletions components/brave_shields/browser/adblock_interceptor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/components/brave_shields/browser/adblock_interceptor.h"

#include <algorithm>
#include <string>
#include <vector>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_split.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request_job.h"

namespace brave_shields {
namespace {

// Everything but jpeg is a transparent pixel.
const unsigned char kWebp1x1[] = {
0x52, 0x49, 0x46, 0x46, 0x1a, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
0x56, 0x50, 0x38, 0x4c, 0x0d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
0x10, 0x07, 0x10, 0x11, 0x11, 0x88, 0x88, 0xfe, 0x07, 0x00};
const unsigned char kPng1x1[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x08, 0x04, 0x00, 0x00, 0x00, 0xb5, 0x1c, 0x0c, 0x02, 0x00, 0x00, 0x00,
0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0xfa, 0xcf, 0x00, 0x00,
0x02, 0x07, 0x01, 0x02, 0x9a, 0x1c, 0x31, 0x71, 0x00, 0x00, 0x00, 0x00,
0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
const unsigned char kGif1x1[] = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80,
0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x21, 0xf9, 0x04,
0x01, 0x0a, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, 0x01, 0x00, 0x3b};
const unsigned char kJpeg1x1[] = {
0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x11, 0x00,
0xff, 0xc4, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc4,
0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x08,
0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0x37, 0xff, 0xd9};

// Basically, for now all Chromium image resource requests use hardcoded
// 'Accept' header that starts with "image/webp". However, it is possible to
// craft a custom 'Accept', for example, using XHR, so we provide stubs for
// other popular mime types.
std::vector<unsigned char> GetContentForMimeType(const std::string& mime_type) {
static const base::NoDestructor<
base::flat_map<std::string, std::vector<unsigned char>>>
content({
{"image/webp", {kWebp1x1, std::end(kWebp1x1)}},
{"image/*", {kPng1x1, std::end(kPng1x1)}},
{"image/apng", {kPng1x1, std::end(kPng1x1)}},
{"image/png", {kPng1x1, std::end(kPng1x1)}},
{"image/x-png", {kPng1x1, std::end(kPng1x1)}},
{"image/gif", {kGif1x1, std::end(kGif1x1)}},
{"image/jpeg", {kJpeg1x1, std::end(kJpeg1x1)}},
});
auto it = content->find(mime_type);
if (it == content->end()) {
return {};
}
return it->second;
}

class Http200OkJob : public net::URLRequestJob {
public:
Http200OkJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate);

// URLRequestJob:
void Start() override;
void Kill() override;
bool GetMimeType(std::string* mime_type) const override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int ReadRawData(net::IOBuffer* buf, int buf_size) override;

private:
~Http200OkJob() override;
void StartAsync();
void InitMimeAndResponse(net::URLRequest* request);

// Intercepted from 'Accept:' (or default if the header is empty).
std::string mime_type_ = "text/html";
std::vector<unsigned char> response_body_;

base::WeakPtrFactory<Http200OkJob> weak_factory_;
};

Http200OkJob::Http200OkJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate)
: net::URLRequestJob(request, network_delegate), weak_factory_(this) {
InitMimeAndResponse(request);
}

void Http200OkJob::Start() {
// Start reading asynchronously so that all error reporting and data
// callbacks happen as they would for network requests.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&Http200OkJob::StartAsync, weak_factory_.GetWeakPtr()));
}

void Http200OkJob::Kill() {
weak_factory_.InvalidateWeakPtrs();
URLRequestJob::Kill();
}

bool Http200OkJob::GetMimeType(std::string* mime_type) const {
*mime_type = mime_type_;
return true;
}

void Http200OkJob::GetResponseInfo(net::HttpResponseInfo* info) {
net::HttpResponseInfo new_info;
// TODO(iefremov): Allowing any origins still breaks some CORS requests.
// Maybe we can provide something smarter here.
// TODO(iefremov): Some URLRequests users extract Content-Type from headers,
// not from |GetMimeType()|. Probably we could add a Content-Type here.
std::string raw_headers =
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: " + mime_type_ + "\r\n";
new_info.headers =
new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
raw_headers.c_str(), raw_headers.size()));
*info = new_info;
}

int Http200OkJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
if (response_body_.empty()) {
return 0;
}

size_t bytes_to_copy =
std::min(static_cast<size_t>(buf_size), response_body_.size());
if (bytes_to_copy > 0) {
std::memcpy(buf->data(), response_body_.data(), bytes_to_copy);
// We do not optimize here because returned data is typically much shorter
// than the buf_size, so there is only one call.
response_body_.erase(response_body_.begin(),
response_body_.begin() + bytes_to_copy);
}
return bytes_to_copy;
}

Http200OkJob::~Http200OkJob() {}

void Http200OkJob::StartAsync() {
NotifyHeadersComplete();
}

void Http200OkJob::InitMimeAndResponse(net::URLRequest* request) {
// Extract mime type that the request wants so we can provide it while
// preparing the response.
auto headers = request->extra_request_headers();
std::string accept_header;
headers.GetHeader("Accept", &accept_header);
auto mime_types = base::SplitString(
accept_header, ",;", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (!mime_types.empty()) {
DCHECK(!mime_types.front().empty());
// If the entry looks like "*/*", use the default value. Otherwise, use
// the value from 'Accept', even if it looks like "audio/*".
if (mime_types.front()[0] != '*') {
mime_type_ = mime_types.front();
}
response_body_ = GetContentForMimeType(mime_type_);
}
}

} // namespace

AdBlockInterceptor::AdBlockInterceptor() {}
AdBlockInterceptor::~AdBlockInterceptor() {}

net::URLRequestJob* AdBlockInterceptor::MaybeInterceptRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
std::string header;
if (request->extra_request_headers().GetHeader("X-Brave-Block", &header)) {
VLOG(1) << "Intercepting request: " << request->url().spec();
return new Http200OkJob(request, network_delegate);
}
return nullptr;
}

} // namespace brave_shields
30 changes: 30 additions & 0 deletions components/brave_shields/browser/adblock_interceptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef COMPONENTS_BRAVE_SHIELDS_BROWSER_ADBLOCK_INTERCEPTOR_H_
#define COMPONENTS_BRAVE_SHIELDS_BROWSER_ADBLOCK_INTERCEPTOR_H_

#include "net/url_request/url_request_interceptor.h"

namespace brave_shields {

// Intercepts certain requests and blocks them by silently returning 200 OK
// and not allowing them to hit the network.
class AdBlockInterceptor : public net::URLRequestInterceptor {
public:
AdBlockInterceptor();
~AdBlockInterceptor() override;

protected:
// net::URLRequestInterceptor:
net::URLRequestJob* MaybeInterceptRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override;
private:
DISALLOW_COPY_AND_ASSIGN(AdBlockInterceptor);
};

} // namespace brave_shields

#endif // COMPONENTS_BRAVE_SHIELDS_BROWSER_ADBLOCK_INTERCEPTOR_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
diff --git a/chrome/browser/net/chrome_url_request_context_getter.cc b/chrome/browser/net/chrome_url_request_context_getter.cc
index eca8e532e3ec27a97007d9be5f6781c6b2628cf8..315d92e3da48ee1cbf62f88a5c88a8d2db3841da 100644
--- a/chrome/browser/net/chrome_url_request_context_getter.cc
+++ b/chrome/browser/net/chrome_url_request_context_getter.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/chrome_url_request_context_getter.h"

#include <utility>
-
+#include "brave/components/brave_shields/browser/adblock_interceptor.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -49,6 +49,7 @@ class FactoryForMain : public ChromeURLRequestContextFactory {
: profile_io_data_(profile_io_data),
request_interceptors_(std::move(request_interceptors)) {
std::swap(protocol_handlers_, *protocol_handlers);
+ request_interceptors_.emplace_back(new brave_shields::AdBlockInterceptor);
}

net::URLRequestContext* Create() override {
@@ -85,6 +86,7 @@ class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
network_context_request_(std::move(network_context_request)),
network_context_params_(std::move(network_context_params)) {
std::swap(protocol_handlers_, *protocol_handlers);
+ request_interceptors_.emplace_back(new brave_shields::AdBlockInterceptor);
}

net::URLRequestContext* Create() override {

0 comments on commit 461df53

Please sign in to comment.