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

Add .torrent support #405

merged 11 commits into from
Sep 11, 2018

Conversation

yrliou
Copy link
Member

@yrliou yrliou commented Sep 6, 2018

Fix brave/brave-browser#855

Submitter Checklist:

  • Submitted a ticket for my issue if one did not already exist.
  • Used Github auto-closing keywords in the commit message.
  • Added/updated tests for this change (for new code or code which already has tests).
  • Ran git rebase -i to squash commits (if needed).
  • Tagged reviewers and labelled the pull request as needed.
  • Request a security/privacy review as needed.
  • Add appropriate QA labels (QA/Needed or QA/No-QA-Needed) to include the closed issue in milestone

Test Plan:

Manual Test:

  1. Open a new tab and visit https://webtorrent.io/free-torrents, click torrent link of Sintel should leads to a torrent viewer page without start downloading
  2. Click start download, torrent should start to be downloading
  3. Click any link under save file should be able to download that specific file
  4. Click on poster.jpg, should open a tab and show the image directly
  5. Go back to the torrent downloading page and click on sintel.mp4, should open a tab to stream the media
    (Note: It might take a while for the media to be ready to play.)
  6. Close the media streaming tab and go back to the torrent downloading page
  7. Go back to https://webtorrent.io/free-torrents tab and see if it also works by right click the torrent link to open it in a new tab

Automation Test:
npm run test -- brave_browser_tests --filter=BraveContentBrowserClientTest.ReverseRewriteTorrentURL
npm run test -- brave_unit_tests --filter=BraveTorrentRedirectNetworkDelegateHelperTest.*
npm run test-unit

Reviewer Checklist:

  • New files have MPL-2.0 license header.
  • Request a security/privacy review as needed.
  • Adequate test coverage exists to prevent regressions
  • Verify test plan is specified in PR before merging to source

@yrliou yrliou self-assigned this Sep 6, 2018
@yrliou yrliou force-pushed the torrent_support branch 6 times, most recently from 160977d to 4863b33 Compare September 7, 2018 06:07
@yrliou yrliou changed the title [WIP] Add .torrent support Add .torrent support Sep 8, 2018
@yrliou yrliou requested a review from bbondy September 8, 2018 00:24
"url_context.h"
"url_context.h",
"//brave/components/brave_webtorrent/browser/net/brave_torrent_redirect_network_delegate_helper.cc",
"//brave/components/brave_webtorrent/browser/net/brave_torrent_redirect_network_delegate_helper.h",
Copy link
Member Author

Choose a reason for hiding this comment

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

These two files have been moved into a separate source set inside brave_webtorrent component by cf81e8d

@@ -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.

// 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->SchemeIs("http") || url->SchemeIs("https") ||
Copy link
Member

Choose a reason for hiding this comment

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

nit: url->SchemeIsHTTPOrHTTPS()

return false;
}

if (mimeType == "application/x-bittorrent") {
Copy link
Member

Choose a reason for hiding this comment

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

nit: pls add this to common/network_constants.h and use the constant here and in tests

return false;
}

bool URLMatched(net::URLRequest* request) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: this would be easy to add a unittest for

Copy link
Member Author

Choose a reason for hiding this comment

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

These util functions are covered in BraveTorrentRedirectNetworkDelegateHelperTest unit tests.

return false;
}

net::HttpContentDisposition cd_headers(disposition, std::string());
Copy link
Member

Choose a reason for hiding this comment

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

++ on using HttpContentDisposition since the header can be complex like
Content-Disposition: attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";

return true;
}

if (mimeType == "application/octet-stream" &&
Copy link
Member

Choose a reason for hiding this comment

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

nit: I prefer you do a constant for this one too for use here and in tests

return false;
}

bool IsWebtorrentInitiated(net::URLRequest* request) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: unit test as well, you can adjust the signature to pass a const GURL & to make it easier.

request->url().spec()}));
(*override_response_headers)->AddHeader(
"Location: " + url.spec());
*allowed_unsafe_redirect_url = url;
Copy link
Member

Choose a reason for hiding this comment

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

neat 😮


*override_response_headers =
new net::HttpResponseHeaders(original_response_headers->raw_headers());
(*override_response_headers)->ReplaceStatusLine("HTTP/1.1 301 Moved Permanently");
Copy link
Member

@bbondy bbondy Sep 10, 2018

Choose a reason for hiding this comment

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

Should we use 302 here instead?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe 307 if we ever want to also preserve the HTTP method.

Copy link
Member Author

Choose a reason for hiding this comment

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

Was following browser-laptop for using 301, but 307 Temporary Redirect seems more reasonable to me, so I'll change it to 307.


bool FileNameMatched(const net::HttpResponseHeaders* headers) {
std::string disposition;
if (!headers->GetNormalizedHeader("content-disposition", &disposition)) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: I know header names are case insensitive but prefer "Content-Disposition" since it's more canonical.

@@ -7,7 +7,7 @@
"scripts": ["extension/out/brave_webtorrent_background.bundle.js"],
"persistent": true
},
"permissions": ["tabs", "windows", "http://127.0.0.1:*/*"],
Copy link
Member

Choose a reason for hiding this comment

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

cc @diracdeltas for security review

Copy link
Member

Choose a reason for hiding this comment

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

seems ok since <all_urls> is required in the browser-laptop extension

@@ -20,6 +20,6 @@
"listen": "*:*"
}
},
"content_security_policy": "default-src 'self'; connect-src 'self'; font-src 'self' data:; script-src 'self'; media-src 'self' http://127.0.0.1:*; form-action 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-src 'self' http://127.0.0.1:*;",
Copy link
Member

Choose a reason for hiding this comment

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

cc @diracdeltas for security review

Copy link
Member

Choose a reason for hiding this comment

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

@yrliou could you explain why this change is needed? it isn't in the browser-laptop version of webtorrent so i wonder if we can work around it.

Copy link
Member Author

@yrliou yrliou Sep 10, 2018

Choose a reason for hiding this comment

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

When we click start torrent, the background page of webtorrent component extension will initiate a request to fetch the actual .torrent, for example, from https://webtorrent.io/torrents/big-buck-bunny.torrent
Without this change, I'm getting "Refused to connect to 'https://webtorrent.io/torrents/big-buck-bunny.torrent' because it violates the following Content Security Policy directive: "connect-src 'self'". in the background page.
I think for the browser-laptop case, these things are happened in browser process instead of the extension.

Copy link
Member

Choose a reason for hiding this comment

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

@yrliou thanks for the explanation. Have you tried seeing if this works with an HTTP (not HTTPS) endpoint? I'm afraid Chromium might block that for being mixed content even if it is whitelisted in CSP.

If so we should take another approach like downloading the .torrent file to a tempfile (which would remove the need to whitelist http/https connections in the CSP)

Copy link
Member Author

@yrliou yrliou Sep 10, 2018

Choose a reason for hiding this comment

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

@diracdeltas I just tried fetching things from HTTP endpoint in the background page using simple-get(https://github.com/feross/simple-get), which is the same as how webtorrent libs make those requests.
Adding http: in CSP's connect-src did allow us to fetch things normally. Without http: specified, same error as above is shown .

Copy link
Member

Choose a reason for hiding this comment

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

sgtm

Copy link
Member Author

@yrliou yrliou Sep 10, 2018

Choose a reason for hiding this comment

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

Tried with http://www.slackware.com/torrents/slackware-14.2-install-d1.torrent, .torrent file was successfully fetched.

package.json Outdated
@@ -126,6 +126,7 @@
},
"dependencies": {
"@types/parse-torrent": "^5.8.2",
"@types/query-string": "^6.1.0",
Copy link
Member

Choose a reason for hiding this comment

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

cc @diracdeltas for security review

package.json Outdated
@@ -135,6 +136,7 @@
"http-node": "^1.2.0",
"prettier-bytes": "^1.0.4",
"qr-image": "^3.2.0",
"query-string": "^6.1.0",
Copy link
Member

Choose a reason for hiding this comment

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

cc @diracdeltas for security review

Copy link
Member

Choose a reason for hiding this comment

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

is it not possible here to use node's builtin querystring module? https://nodejs.org/api/querystring.html

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, my bad, I'll revert 86fb70b and use this one instead.

@@ -14,6 +14,7 @@ transpile_web_ui("brave_webtorrent") {
"background/actions/webtorrentActions.ts",
"background/actions/windowActions.ts",
"background/api/tabs_api.ts",
"background/api/torrent_api.ts",
Copy link
Member

@bbondy bbondy Sep 10, 2018

Choose a reason for hiding this comment

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

@cezaraugusto please take a look at this commit changes for review

@bbondy
Copy link
Member

bbondy commented Sep 10, 2018

  • @diracdeltas to review to take a look from a security perspective as well.

Copy link
Member

@bbondy bbondy left a comment

Choose a reason for hiding this comment

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

Small notes in the various commits. Nice work!

cezaraugusto
cezaraugusto previously approved these changes Sep 10, 2018
Copy link
Contributor

@cezaraugusto cezaraugusto left a comment

Choose a reason for hiding this comment

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

left a nit, please also check https://github.com/brave/brave-core/pull/405/files#r216344528.

Other than that front-end LGTM

try {
const { name, infoHash, ix } = ParseTorrent(torrentId)
newInfoHash = infoHash
newTorrentState = { tabId, torrentId, name, infoHash, ix }
} catch (error) {
newTorrentState = { tabId, torrentId, errorMsg: error.message }
}
} else if (parsedURL.protocol === 'https:' || parsedURL.protocol === 'http:') {
const name = parsedURL.pathname.substr(parsedURL.pathname.lastIndexOf('/') + 1)
let ix: number | undefined = Number(parse(parsedURL.hash).ix)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: please reference in a comment that this is the file index to select a specific file from that torrent so other people not familiar w/ this code can understand faster what this does

package.json Outdated
@@ -134,6 +136,7 @@
"http-node": "^1.2.0",
"prettier-bytes": "^1.0.4",
"qr-image": "^3.2.0",
"query-string": "^6.1.0",
"react-chrome-redux": "^1.5.1",
"throttleit": "^1.0.0",
"webtorrent": "github:brave/webtorrent#600664249258dd7e893789e991d4cc5f481a7bae"
Copy link
Member

Choose a reason for hiding this comment

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

general question, is there a plan for keeping these github forks up to date? we have had some security issues with webtorrent in the past, and i think by forking them in this way, we will no longer get security reports for them with npm audit.

Copy link
Member Author

Choose a reason for hiding this comment

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

brave/brave-browser#856, in the long-term, we want to solve the browser field issue without forking them.
In the short term, I could keep an eye from webtorrent upstream changes and rebase onto their latest releases, I'm not sure if that's sufficient tho.
I wonder if we have guidelines on how to follow upstream changes for projects we're forking, like how frequently should we check or update to the upstream?

Copy link
Member

Choose a reason for hiding this comment

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

rebasing them sgtm for now. we don't really have guidelines right now; probably once per release? if there is a release checklist, this should be added to it.

Copy link
Member Author

@yrliou yrliou Sep 11, 2018

Choose a reason for hiding this comment

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

Per release sounds good to me.
I didn't see one in our wiki tho I might missed it, @bbondy, please correct me if there is.
I could create bugs for our next few releases first and mark with milestone labels, how does that sound, @diracdeltas ?

If callbacks are run before we returning net::ERR_IO_PENDING in BraveNetworkDelegateBase::OnHeadersReceived,
URLRequestHttpJob::awaiting_callback_ might remain true and hit CHECK(!awaiting_callback_) in ~URLRequestHttpJob().
- Add kBittorrentMimeType and kOctetStreamMimeType constants
- Use 307 instead of 301 when redirecting torrent links
- Use querystring instead of query-string
- fixing nit
bbondy
bbondy previously approved these changes Sep 11, 2018
@yrliou
Copy link
Member Author

yrliou commented Sep 11, 2018

Debug builds and tests on all platforms seem fine, this PR is ready to merge.

@bbondy bbondy merged commit dc76204 into master Sep 11, 2018
bbondy added a commit that referenced this pull request Sep 11, 2018
@bbondy
Copy link
Member

bbondy commented Sep 11, 2018

Btw we use 0.55.x label as an indication that it is merged, so best to let the merge add it. Thanks!
0.55.x b71e139

@yrliou yrliou deleted the torrent_support branch September 11, 2018 16:05
@bbondy bbondy added this to the 0.55.x - Release milestone Jan 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebTorrent support of .torrent links
4 participants