def test_create_invalid_tdef(): """ Test whether creating invalid TorrentDef objects result in ValueErrors """ invalid_metainfo = {} with pytest.raises(ValueError): TorrentDef.load_from_memory(bencode(invalid_metainfo)) invalid_metainfo = {b'info': {}} with pytest.raises(ValueError): TorrentDef.load_from_memory(bencode(invalid_metainfo))
async def test_get_torrentinfo(mock_dlmgr, tmp_path, rest_api, endpoint): """ Testing whether the API returns a correct dictionary with torrent info. """ endpoint.download_manager = mock_dlmgr shutil.copyfile(TORRENT_UBUNTU_FILE, tmp_path / 'ubuntu.torrent') def verify_valid_dict(json_data): metainfo_dict = json.loads(unhexlify(json_data['metainfo'])) # FIXME: This check is commented out because json.dump garbles pieces binary data during transfer. # To fix it, we must switch to some encoding scheme that is able to encode and decode raw binary # fields in the dicts. # However, for this works fine at the moment because we never use pieces data in the GUI. # assert TorrentDef.load_from_dict(metainfo_dict) assert 'info' in metainfo_dict def path_to_url(path): return urllib.request.pathname2url(str(path)) mock_dlmgr.downloads = {} mock_dlmgr.metainfo_requests = {} mock_dlmgr.get_channel_downloads = lambda: [] mock_dlmgr.shutdown = lambda: succeed(None) mock_dlmgr.notifier = Mock() await do_request(rest_api, 'torrentinfo', expected_code=400) await do_request(rest_api, 'torrentinfo?uri=def', expected_code=400) path = "file:" + path_to_url(TESTS_DATA_DIR / "bak_single.torrent") verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200)) # Corrupt file path = "file:" + path_to_url(TESTS_DATA_DIR / "test_rss.xml") await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500) path = "http://localhost:1234/ubuntu.torrent" async def mock_http_query(*_): with open(tmp_path / "ubuntu.torrent", 'rb') as f: return f.read() with patch( "tribler_core.components.libtorrent.restapi.torrentinfo_endpoint.query_http_uri", new=mock_http_query): verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={quote_plus(path)}', expected_code=200)) path = quote_plus(f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}' f'&dn=test torrent&tr=http://ubuntu.org/ann') hops_list = [] with open(TESTS_DATA_DIR / "ubuntu-15.04-desktop-amd64.iso.torrent", mode='rb') as torrent_file: torrent_data = torrent_file.read() tdef = TorrentDef.load_from_memory(torrent_data) metainfo_dict = tdef_to_metadata_dict( TorrentDef.load_from_memory(torrent_data)) def get_metainfo(infohash, timeout=20, hops=None, url=None): if hops is not None: hops_list.append(hops) assert url assert url == unquote_plus(path) return succeed(tdef.get_metainfo()) mock_dlmgr.get_metainfo = get_metainfo verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200)) path = 'magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1' # No infohash await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=400) path = quote_plus(f"magnet:?xt=urn:btih:{'a' * 40}&dn=test torrent") mock_dlmgr.get_metainfo = lambda *_, **__: succeed(None) await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500) # Ensure that correct torrent metadata was sent through notifier (to MetadataStore) mock_dlmgr.notifier.notify.assert_called_with( NTFY.TORRENT_METADATA_ADDED.value, metainfo_dict) mock_dlmgr.get_metainfo = get_metainfo verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200)) await do_request(rest_api, f'torrentinfo?uri={path}&hops=0', expected_code=200) assert [0] == hops_list await do_request(rest_api, f'torrentinfo?uri={path}&hops=foo', expected_code=400) path = 'http://fdsafksdlafdslkdksdlfjs9fsafasdf7lkdzz32.n38/324.torrent' await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500) mock_download = Mock() path = quote_plus( f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}&dn=test torrent') mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download} result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert result["download_exists"] # Check that we do not return "downloads_exists" if the download is metainfo only download mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download} mock_dlmgr.metainfo_requests = {UBUNTU_1504_INFOHASH: [mock_download]} result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert not result["download_exists"] # Check that we return "downloads_exists" if there is a metainfo download for the infohash, # but there is also a regular download for the same infohash mock_dlmgr.downloads = {UBUNTU_1504_INFOHASH: mock_download} mock_dlmgr.metainfo_requests = {UBUNTU_1504_INFOHASH: [Mock()]} result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert result["download_exists"]
async def add_torrent_to_channel(self, request): channel_pk, channel_id = self.get_channel_from_request(request) with db_session: channel = self.mds.CollectionNode.get(public_key=channel_pk, id_=channel_id) if not channel: return RESTResponse({"error": "Unknown channel"}, status=HTTP_NOT_FOUND) parameters = await request.json() extra_info = {} if parameters.get('description', None): extra_info = {'description': parameters['description']} # First, check whether we did upload a magnet link or URL if parameters.get('uri', None): uri = parameters['uri'] if uri.startswith("http:") or uri.startswith("https:"): data = await _fetch_uri(uri) tdef = TorrentDef.load_from_memory(data) elif uri.startswith("magnet:"): _, xt, _ = parse_magnetlink(uri) if ( xt and is_infohash(codecs.encode(xt, 'hex')) and (self.mds.torrent_exists_in_personal_channel(xt) or channel.copy_torrent_from_infohash(xt)) ): return RESTResponse({"added": 1}) meta_info = await self.download_manager.get_metainfo(xt, timeout=30, url=uri) if not meta_info: raise RuntimeError("Metainfo timeout") tdef = TorrentDef.load_from_dict(meta_info) else: return RESTResponse({"error": "unknown uri type"}, status=HTTP_BAD_REQUEST) added = 0 if tdef: channel.add_torrent_to_channel(tdef, extra_info) added = 1 return RESTResponse({"added": added}) torrents_dir = None if parameters.get('torrents_dir', None): torrents_dir = parameters['torrents_dir'] if not Path(torrents_dir).is_absolute(): return RESTResponse({"error": "the torrents_dir should point to a directory"}, status=HTTP_BAD_REQUEST) recursive = False if parameters.get('recursive'): recursive = parameters['recursive'] if not torrents_dir: return RESTResponse( {"error": "the torrents_dir parameter should be provided when the recursive parameter is set"}, status=HTTP_BAD_REQUEST, ) if torrents_dir: torrents_list, errors_list = channel.add_torrents_from_dir(torrents_dir, recursive) return RESTResponse({"added": len(torrents_list), "errors": errors_list}) if not parameters.get('torrent', None): return RESTResponse({"error": "torrent parameter missing"}, status=HTTP_BAD_REQUEST) # Try to parse the torrent data # Any errors will be handled by the error_middleware torrent = base64.b64decode(parameters['torrent']) torrent_def = TorrentDef.load_from_memory(torrent) channel.add_torrent_to_channel(torrent_def, extra_info) return RESTResponse({"added": 1})
async def test_get_torrentinfo(tmp_path, rest_api, endpoint: TorrentInfoEndpoint): """ Testing whether the API returns a correct dictionary with torrent info. """ def _path(file): return path_to_uri(TESTS_DATA_DIR / file) shutil.copyfile(TORRENT_UBUNTU_FILE, tmp_path / 'ubuntu.torrent') def verify_valid_dict(json_data): metainfo_dict = json.loads(unhexlify(json_data['metainfo'])) assert 'info' in metainfo_dict url = 'torrentinfo' await do_request(rest_api, url, expected_code=400) await do_request(rest_api, url, params={'uri': 'def'}, expected_code=400) response = await do_request(rest_api, url, params={'uri': _path('bak_single.torrent')}, expected_code=200) verify_valid_dict(response) # Corrupt file await do_request(rest_api, url, params={'uri': _path('test_rss.xml')}, expected_code=500) path = "http://localhost:1234/ubuntu.torrent" async def mock_http_query(*_): with open(tmp_path / "ubuntu.torrent", 'rb') as f: return f.read() with patch( "tribler_core.components.libtorrent.restapi.torrentinfo_endpoint.query_http_uri", new=mock_http_query): verify_valid_dict(await do_request(rest_api, url, params={'uri': path}, expected_code=200)) path = quote_plus(f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}' f'&dn=test torrent&tr=http://ubuntu.org/ann') hops_list = [] with open(TESTS_DATA_DIR / "ubuntu-15.04-desktop-amd64.iso.torrent", mode='rb') as torrent_file: torrent_data = torrent_file.read() tdef = TorrentDef.load_from_memory(torrent_data) metainfo_dict = tdef_to_metadata_dict( TorrentDef.load_from_memory(torrent_data)) def get_metainfo(infohash, timeout=20, hops=None, url=None): if hops is not None: hops_list.append(hops) assert url assert url == unquote_plus(path) return succeed(tdef.get_metainfo()) endpoint.download_manager.get_metainfo = get_metainfo verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200)) path = 'magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1' # No infohash await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=400) path = quote_plus(f"magnet:?xt=urn:btih:{'a' * 40}&dn=test torrent") endpoint.download_manager.get_metainfo = lambda *_, **__: succeed(None) await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500) # Ensure that correct torrent metadata was sent through notifier (to MetadataStore) endpoint.download_manager.notifier[ notifications.torrent_metadata_added].assert_called_with(metainfo_dict) endpoint.download_manager.get_metainfo = get_metainfo verify_valid_dict(await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200)) await do_request(rest_api, f'torrentinfo?uri={path}&hops=0', expected_code=200) assert [0] == hops_list await do_request(rest_api, f'torrentinfo?uri={path}&hops=foo', expected_code=400) path = 'http://fdsafksdlafdslkdksdlfjs9fsafasdf7lkdzz32.n38/324.torrent' await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=500) mock_download = MagicMock() path = quote_plus( f'magnet:?xt=urn:btih:{hexlify(UBUNTU_1504_INFOHASH)}&dn=test torrent') endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download} result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert result["download_exists"] # Check that we do not return "downloads_exists" if the download is metainfo only download endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download} endpoint.download_manager.metainfo_requests = { UBUNTU_1504_INFOHASH: [mock_download] } result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert not result["download_exists"] # Check that we return "downloads_exists" if there is a metainfo download for the infohash, # but there is also a regular download for the same infohash endpoint.download_manager.downloads = {UBUNTU_1504_INFOHASH: mock_download} endpoint.download_manager.metainfo_requests = { UBUNTU_1504_INFOHASH: [MagicMock()] } result = await do_request(rest_api, f'torrentinfo?uri={path}', expected_code=200) assert result["download_exists"]