Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add .torrent support #405

Merged
merged 11 commits into from
Sep 11, 2018
Merged
2 changes: 2 additions & 0 deletions browser/brave_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ void BraveContentBrowserClient::BrowserURLHandlerCreated(
// before anything else can.
handler->AddHandlerPair(&webtorrent::HandleMagnetURLRewrite,
content::BrowserURLHandler::null_handler());
handler->AddHandlerPair(&webtorrent::HandleTorrentURLRewrite,
&webtorrent::HandleTorrentURLReverseRewrite);
handler->AddHandlerPair(&HandleURLRewrite,
&HandleURLReverseRewrite);
ChromeContentBrowserClient::BrowserURLHandlerCreated(handler);
Expand Down
26 changes: 22 additions & 4 deletions browser/brave_content_browser_client_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,30 @@ class BraveContentBrowserClientTest : public InProcessBrowserTest {

ASSERT_TRUE(embedded_test_server()->Start());

url_ = embedded_test_server()->GetURL("a.com", "/magnet.html");
magnet_html_url_ = embedded_test_server()->GetURL("a.com", "/magnet.html");
magnet_url_ = GURL("magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c&dn=Big+Buck+Bunny&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fbig-buck-bunny.torrent");
extension_url_ = GURL("chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/brave_webtorrent.html?magnet%3A%3Fxt%3Durn%3Abtih%3Add8255ecdc7ca55fb0bbf81323d87062db1f6d1c%26dn%3DBig%2BBuck%2BBunny%26tr%3Dudp%253A%252F%252Fexplodie.org%253A6969%26tr%3Dudp%253A%252F%252Ftracker.coppersurfer.tk%253A6969%26tr%3Dudp%253A%252F%252Ftracker.empire-js.us%253A1337%26tr%3Dudp%253A%252F%252Ftracker.leechers-paradise.org%253A6969%26tr%3Dudp%253A%252F%252Ftracker.opentrackr.org%253A1337%26tr%3Dwss%253A%252F%252Ftracker.btorrent.xyz%26tr%3Dwss%253A%252F%252Ftracker.fastcast.nz%26tr%3Dwss%253A%252F%252Ftracker.openwebtorrent.com%26ws%3Dhttps%253A%252F%252Fwebtorrent.io%252Ftorrents%252F%26xs%3Dhttps%253A%252F%252Fwebtorrent.io%252Ftorrents%252Fbig-buck-bunny.torrent");
torrent_url_ = GURL("https://webtorrent.io/torrents/sintel.torrent#ix=5");
torrent_extension_url_ = GURL("chrome-extension://lgjmpdmojkpocjcopdikifhejkkjglho/extension/brave_webtorrent.html?https://webtorrent.io/torrents/sintel.torrent#ix=5");
}

void TearDown() override {
browser_content_client_.reset();
content_client_.reset();
}

const GURL& url() { return url_; }
const GURL& magnet_html_url() { return magnet_html_url_; }
const GURL& magnet_url() { return magnet_url_; }
const GURL& extension_url() { return extension_url_; }
const GURL& torrent_url() { return torrent_url_; }
const GURL& torrent_extension_url() { return torrent_extension_url_; }

private:
GURL url_;
GURL magnet_html_url_;
GURL magnet_url_;
GURL extension_url_;
GURL torrent_url_;
GURL torrent_extension_url_;
ContentSettingsPattern top_level_page_pattern_;
ContentSettingsPattern empty_pattern_;
std::unique_ptr<ChromeContentClient> content_client_;
Expand Down Expand Up @@ -104,7 +110,7 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteMagnetURLURLBar) {

IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteMagnetURLLink) {
content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
ui_test_utils::NavigateToURL(browser(), url());
ui_test_utils::NavigateToURL(browser(), magnet_html_url());
ASSERT_TRUE(WaitForLoadStop(contents));
bool value;
EXPECT_TRUE(ExecuteScriptAndExtractBool(contents, "clickMagnetLink();",
Expand All @@ -118,3 +124,15 @@ IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, RewriteMagnetURLLink) {
EXPECT_STREQ(entry->GetURL().spec().c_str(),
extension_url().spec().c_str()) << "Real URL should be extension URL";
}

IN_PROC_BROWSER_TEST_F(BraveContentBrowserClientTest, ReverseRewriteTorrentURL) {
content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
ui_test_utils::NavigateToURL(browser(), torrent_extension_url());
ASSERT_TRUE(WaitForLoadStop(contents));

EXPECT_STREQ(contents->GetLastCommittedURL().spec().c_str(),
torrent_url().spec().c_str()) << "URL visible to users should stay as the torrent URL";
content::NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
EXPECT_STREQ(entry->GetURL().spec().c_str(),
torrent_extension_url().spec().c_str()) << "Real URL should be extension URL";
}
3 changes: 2 additions & 1 deletion browser/net/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ source_set("net") {
"brave_system_network_delegate.cc",
"brave_system_network_delegate.h",
"url_context.cc",
"url_context.h"
"url_context.h",
]
deps = [
"//brave/browser/safebrowsing",
"//brave/components/brave_webtorrent/browser/net",
"//chrome/browser",
"//content/public/browser",
"//net",
Expand Down
51 changes: 51 additions & 0 deletions browser/net/brave_network_delegate_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,36 @@ int BraveNetworkDelegateBase::OnBeforeStartTransaction(net::URLRequest* request,
return net::ERR_IO_PENDING;
}

int BraveNetworkDelegateBase::OnHeadersReceived(net::URLRequest* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) {
if (headers_received_callbacks_.empty() || !request) {
return ChromeNetworkDelegate::OnHeadersReceived(request,
std::move(callback), original_response_headers,
override_response_headers, allowed_unsafe_redirect_url);
}

std::shared_ptr<brave::BraveRequestInfo> ctx(
new brave::BraveRequestInfo());
callbacks_[request->identifier()] = std::move(callback);
ctx->request_identifier = request->identifier();
ctx->event_type = brave::kOnHeadersReceived;
ctx->original_response_headers = original_response_headers;
ctx->override_response_headers = override_response_headers;
ctx->allowed_unsafe_redirect_url = allowed_unsafe_redirect_url;

// Return ERR_IO_PENDING and run callbacks later by posting a task.
// URLRequestHttpJob::awaiting_callback_ will be set to true after we
// return net::ERR_IO_PENDING here, callbacks need to be run later than this
// to set awaiting_callback_ back to false.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&BraveNetworkDelegateBase::RunNextCallback,
base::Unretained(this), request, nullptr, ctx));
return net::ERR_IO_PENDING;
}

void BraveNetworkDelegateBase::RunCallbackForRequestIdentifier(uint64_t request_identifier, int rv) {
std::map<uint64_t, net::CompletionOnceCallback>::iterator it =
callbacks_.find(request_identifier);
Expand Down Expand Up @@ -106,6 +136,23 @@ void BraveNetworkDelegateBase::RunNextCallback(
break;
}
}
} else if (ctx->event_type == brave::kOnHeadersReceived) {
while(headers_received_callbacks_.size() != ctx->next_url_request_index) {
brave::OnHeadersReceivedCallback callback =
headers_received_callbacks_[ctx->next_url_request_index++];
brave::ResponseCallback next_callback =
base::Bind(&BraveNetworkDelegateBase::RunNextCallback,
base::Unretained(this), request, new_url, ctx);
rv = callback.Run(request, ctx->original_response_headers,
ctx->override_response_headers, ctx->allowed_unsafe_redirect_url,
next_callback, ctx);
if (rv == net::ERR_IO_PENDING) {
return;
}
if (rv == net::ERR_ABORTED) {
break;
}
}
}

std::map<uint64_t, net::CompletionOnceCallback>::iterator it =
Expand All @@ -124,6 +171,10 @@ void BraveNetworkDelegateBase::RunNextCallback(
} else if (ctx->event_type == brave::kOnBeforeStartTransaction) {
rv = ChromeNetworkDelegate::OnBeforeStartTransaction(request,
std::move(wrapped_callback), ctx->headers);
} else if (ctx->event_type == brave::kOnHeadersReceived) {
rv = ChromeNetworkDelegate::OnHeadersReceived(request,
std::move(wrapped_callback), ctx->original_response_headers,
ctx->override_response_headers, ctx->allowed_unsafe_redirect_url);
}

// ChromeNetworkDelegate returns net::ERR_IO_PENDING if an extension is
Expand Down
9 changes: 9 additions & 0 deletions browser/net/brave_network_delegate_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ class BraveNetworkDelegateBase : public ChromeNetworkDelegate {
int OnBeforeStartTransaction(net::URLRequest* request,
net::CompletionOnceCallback callback,
net::HttpRequestHeaders* headers) override;
int OnHeadersReceived(
net::URLRequest* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) override;

void OnURLRequestDestroyed(net::URLRequest* request) override;
void RunCallbackForRequestIdentifier(uint64_t request_identifier, int rv);

Expand All @@ -48,6 +55,8 @@ class BraveNetworkDelegateBase : public ChromeNetworkDelegate {
before_url_request_callbacks_;
std::vector<brave::OnBeforeStartTransactionCallback>
before_start_transaction_callbacks_;
std::vector<brave::OnHeadersReceivedCallback>
headers_received_callbacks_;

private:
std::map<uint64_t, net::CompletionOnceCallback> callbacks_;
Expand Down
6 changes: 6 additions & 0 deletions browser/net/brave_profile_network_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "brave/browser/net/brave_httpse_network_delegate_helper.h"
#include "brave/browser/net/brave_site_hacks_network_delegate_helper.h"
#include "brave/components/brave_rewards/browser/buildflags/buildflags.h"
#include "brave/components/brave_webtorrent/browser/net/brave_torrent_redirect_network_delegate_helper.h"

#if BUILDFLAG(BRAVE_REWARDS_ENABLED)
#include "brave/components/brave_rewards/browser/net/network_delegate_helper.h"
Expand Down Expand Up @@ -37,6 +38,11 @@ BraveProfileNetworkDelegate::BraveProfileNetworkDelegate(
brave::OnBeforeStartTransactionCallback start_transactions_callback =
base::Bind(brave::OnBeforeStartTransaction_SiteHacksWork);
before_start_transaction_callbacks_.push_back(start_transactions_callback);

brave::OnHeadersReceivedCallback headers_received_callback =
base::Bind(
webtorrent::OnHeadersReceived_TorrentRedirectWork);
headers_received_callbacks_.push_back(headers_received_callback);
}

BraveProfileNetworkDelegate::~BraveProfileNetworkDelegate() {
Expand Down
12 changes: 12 additions & 0 deletions browser/net/url_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace brave {
enum BraveNetworkDelegateEventType {
kOnBeforeRequest,
kOnBeforeStartTransaction,
kOnHeadersReceived,
kUnknownEventType
};

Expand All @@ -27,6 +28,9 @@ struct BraveRequestInfo {
uint64_t request_identifier = 0;
size_t next_url_request_index = 0;
net::HttpRequestHeaders* headers = nullptr;
const net::HttpResponseHeaders* original_response_headers = nullptr;
scoped_refptr<net::HttpResponseHeaders>* override_response_headers = nullptr;
GURL* allowed_unsafe_redirect_url = nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed for now, but just noting it might be cleaner to make a subclass with these extra members instead and cast as needed in the headers received code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'll create a small follow-up issue to do this if that's fine with you.

Copy link
Member

@bbondy bbondy Sep 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an issue in the backlog is fine for now.

BraveNetworkDelegateEventType event_type = kUnknownEventType;
DISALLOW_COPY_AND_ASSIGN(BraveRequestInfo);
};
Expand All @@ -44,6 +48,14 @@ using OnBeforeStartTransactionCallback =
net::HttpRequestHeaders* headers,
const ResponseCallback& next_callback,
std::shared_ptr<BraveRequestInfo> ctx)>;
using OnHeadersReceivedCallback =
base::Callback<int(net::URLRequest* request,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url,
const ResponseCallback& next_callback,
std::shared_ptr<BraveRequestInfo> ctx)>;

} // namespace brave


Expand Down
3 changes: 3 additions & 0 deletions common/network_constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ const char kCookieHeader[] = "Cookie";
// Intentional misspelling on referrer to match HTTP spec
const char kRefererHeader[] = "Referer";
const char kUserAgentHeader[] = "User-Agent";

const char kBittorrentMimeType[] = "application/x-bittorrent";
const char kOctetStreamMimeType[] = "application/octet-stream";
2 changes: 2 additions & 0 deletions common/network_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ extern const char kCookieHeader[];
extern const char kRefererHeader[];
extern const char kUserAgentHeader[];

extern const char kBittorrentMimeType[];
extern const char kOctetStreamMimeType[];
#endif // BRAVE_COMMON_NETWORK_CONSTANTS_H_

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,44 @@ static GURL TranslateMagnetURL(const GURL& url) {
return GURL(translatedSpec);
}

static GURL TranslateTorrentUIURLReversed(const GURL& url) {
GURL translatedURL(net::UnescapeURLComponent(
url.query(), net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
net::UnescapeRule::PATH_SEPARATORS));
GURL::Replacements replacements;
replacements.SetRefStr(url.ref_piece());
return translatedURL.ReplaceComponents(replacements);
}

static bool HandleTorrentURLReverseRewrite(GURL* url,
content::BrowserContext* browser_context) {
if (url->SchemeIs(extensions::kExtensionScheme) &&
url->host() == brave_webtorrent_extension_id &&
url->ExtractFileName() == "brave_webtorrent.html") {
*url = TranslateTorrentUIURLReversed(*url);
return true;
}

return false;
}

static bool HandleTorrentURLRewrite(GURL* url,
content::BrowserContext* browser_context) {
// The HTTP/HTTPS URL could be modified later by the network delegate if the
// mime type matches or .torrent is in the path.
// Handle http and https here for making reverse_on_redirect to be true in
// BrowserURLHandlerImpl::RewriteURLIfNecessary to trigger ReverseURLRewrite
// for updating the virtual URL.
if (url->SchemeIsHTTPOrHTTPS() ||
(url->SchemeIs(extensions::kExtensionScheme) &&
url->host() == brave_webtorrent_extension_id &&
url->ExtractFileName() == "brave_webtorrent.html")) {
return true;
}

return false;
}

static bool IsWebtorrentInstalled(content::BrowserContext* browser_context) {
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser_context);
Expand Down
12 changes: 12 additions & 0 deletions components/brave_webtorrent/browser/net/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
source_set("net") {
sources = [
"brave_torrent_redirect_network_delegate_helper.cc",
"brave_torrent_redirect_network_delegate_helper.h",
]

deps = [
"//base",
"//brave/common",
"//net",
]
}
Loading