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

Fixed selected files overflowing the URL #8187

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/tribler/core/libtorrent/restapi/downloads_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from binascii import hexlify, unhexlify
from contextlib import suppress
from pathlib import Path, PurePosixPath
from typing import TYPE_CHECKING, TypedDict, cast
from typing import TYPE_CHECKING, Any, Optional, TypedDict, cast

import libtorrent as lt
from aiohttp import web
Expand Down Expand Up @@ -411,7 +411,12 @@ async def add_download(self, request: Request) -> RESTResponse:
params['anon_hops'] = int(params['anon_hops'])
if 'safe_seeding' in params:
params['safe_seeding'] = params['safe_seeding'] != 'false'
tdef = TorrentDef.load_from_memory(await request.read())
body = await request.read()
metainfo = cast(dict[bytes, Any], lt.bdecode(body))
packed_selected_files = cast(Optional[list[int]], metainfo.pop(b"selected_files", None))
if packed_selected_files is not None:
params["selected_files"] = packed_selected_files
tdef = TorrentDef.load_from_dict(metainfo)
else:
params = await request.json()
uri = params.get("uri")
Expand Down
46 changes: 40 additions & 6 deletions src/tribler/ui/src/services/tribler.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,48 @@ export class TriblerService {
}
}

async _mixSelectedIntoMetainfo(torrent: File, selected_files: number[] | undefined): Promise<Uint8Array> {
// Read the torrent data from file
const raw_bytes = new Uint8Array(await torrent.arrayBuffer());

// Create the new data blocks
const new_key = new Uint8Array([49, 52, 58, 115, 101, 108, 101, 99, 116, 101, 100, 95, 102, 105, 108, 101, 115]) // b"14:selected_files"
if ((selected_files !== undefined) && (selected_files.length > 0)){
const str_selected = selected_files.join('ei');
var new_list = new Uint8Array(4 + str_selected.length); // b"li" + str_selected + b"ee"
new_list[0] = 108; // b"l"
new_list[1] = 105; // b"i"
new_list.set(str_selected.split('').map((c) => { return c.charCodeAt(0); }), 2);
new_list[new_list.length - 2] = 101; // b"e"
new_list[new_list.length - 1] = 101; // b"e"
} else {
var new_list = new Uint8Array([108, 101]); // b"le"
}

// Merge everything into the output buffer
const buf_len = raw_bytes.length + new_list.length + 17; // (raw_bytes.length - 1) + 17 + new_list.length + 1
const modified_data = new Uint8Array(buf_len);
modified_data.set(raw_bytes, 0);
modified_data.set(new_key, raw_bytes.length - 1); // [!] this overwrites the last byte of raw_bytes
modified_data.set(new_list, raw_bytes.length + 16); // (raw_bytes.length - 1) + 17
modified_data[buf_len - 1] = 101; // b"e"

return modified_data;
}

async startDownloadFromFile(torrent: File, params: DownloadConfig = {}): Promise<undefined | ErrorDict | boolean> {
try {
return (await this.http.put('/downloads', torrent, {
params: params,
headers: {
'Content-Type': 'applications/x-bittorrent'
}
})).data.started;
// The way selected files are URL encoded leads to the pattern "&selected_files[]=<<FILE_NUMBER>>",
// roughly 20 characters per file in a torrent. With the max of 8190 bytes for a URL, this will lead to
// HTTP 400 errors for torrents that go over +- 400 files.
return (await this.http.put('/downloads',
await this._mixSelectedIntoMetainfo(torrent, params.selected_files), {
params: {...params, "selected_files": []},
headers: {
'Content-Type': 'applications/x-bittorrent'
}
}
)).data.started;
} catch (error) {
return formatAxiosError(error as Error | AxiosError);
}
Expand Down