summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCalum Lind <calumlind+deluge@gmail.com>2019-11-09 10:42:33 +0000
committerCalum Lind <calumlind+deluge@gmail.com>2019-11-12 15:21:56 +0000
commit23b3f144fce3424ae874d54a659cb7b8dd624ade (patch)
treec294e7a3dbbddc72e5c208907397bbcf7c1ac297
parent89d62eb509d498becd83d8854d56e5d6581a7cbf (diff)
downloaddeluge-23b3f144fce3424ae874d54a659cb7b8dd624ade.zip
deluge-23b3f144fce3424ae874d54a659cb7b8dd624ade.tar.gz
deluge-23b3f144fce3424ae874d54a659cb7b8dd624ade.tar.bz2
[#3298|Core] Fix pickle loading non-ascii state error
When trying to load a torrents.state from version 1.3 users were encountering the following error: UnicodeDecodeError: 'ascii' codec can't decode byte This was due to the way that Python 2 was pickling state with torrent filenames that contained non-ascii characters and Python 3 was unpickling the state using ascii encoding and failing. The fix is to specify utf-8 encoding when loading torrents.state.
-rw-r--r--deluge/core/torrentmanager.py7
-rw-r--r--deluge/tests/data/utf8_filename_torrents.state85
-rw-r--r--deluge/tests/test_torrentmanager.py13
3 files changed, 102 insertions, 3 deletions
diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py
index 752f93d..b948687 100644
--- a/deluge/core/torrentmanager.py
+++ b/deluge/core/torrentmanager.py
@@ -25,7 +25,7 @@ from twisted.internet.task import LoopingCall
import deluge.component as component
from deluge._libtorrent import lt
-from deluge.common import archive_files, decode_bytes, get_magnet_info, is_magnet
+from deluge.common import PY2, archive_files, decode_bytes, get_magnet_info, is_magnet
from deluge.configmanager import ConfigManager, get_config_dir
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath
@@ -809,7 +809,10 @@ class TorrentManager(component.Component):
try:
with open(filepath, 'rb') as _file:
- state = pickle.load(_file)
+ if PY2:
+ state = pickle.load(_file)
+ else:
+ state = pickle.load(_file, encoding='utf8')
except (IOError, EOFError, pickle.UnpicklingError) as ex:
message = 'Unable to load {}: {}'.format(filepath, ex)
log.error(message)
diff --git a/deluge/tests/data/utf8_filename_torrents.state b/deluge/tests/data/utf8_filename_torrents.state
new file mode 100644
index 0000000..0e9c33d
--- /dev/null
+++ b/deluge/tests/data/utf8_filename_torrents.state
@@ -0,0 +1,85 @@
+(ideluge.core.torrentmanager
+TorrentManagerState
+p1
+(dp2
+S'torrents'
+p3
+(lp4
+(ideluge.core.torrentmanager
+TorrentState
+p5
+(dp6
+S'max_download_speed'
+p7
+I-1
+sS'move_completed_path'
+p8
+S'/home/calum/Downloads'
+p9
+sS'paused'
+p10
+I00
+sS'max_upload_slots'
+p11
+I-1
+sS'prioritize_first_last'
+p12
+I00
+sS'max_connections'
+p13
+I-1
+sS'compact'
+p14
+I00
+sS'queue'
+p15
+I0
+sS'file_priorities'
+p16
+(lp17
+I4
+asS'filename'
+p18
+S'\xc2\xa2.torrent'
+p19
+sS'max_upload_speed'
+p20
+I-1
+sS'save_path'
+p21
+S'/home/calum/Downloads'
+p22
+sS'time_added'
+p23
+F1573563097.749759
+sS'total_uploaded'
+p24
+I0
+sS'torrent_id'
+p25
+S'80d81d55ef3b85f3c1b634c362e014b35594dc71'
+p26
+sS'auto_managed'
+p27
+I01
+sS'stop_at_ratio'
+p28
+I00
+sS'move_completed'
+p29
+I00
+sS'trackers'
+p30
+(lp31
+sS'magnet'
+p32
+NsS'remove_at_ratio'
+p33
+I00
+sS'stop_ratio'
+p34
+F2
+sS'is_finished'
+p35
+I00
+sbasb.
diff --git a/deluge/tests/test_torrentmanager.py b/deluge/tests/test_torrentmanager.py
index bf84f45..74d37bd 100644
--- a/deluge/tests/test_torrentmanager.py
+++ b/deluge/tests/test_torrentmanager.py
@@ -7,6 +7,8 @@
from __future__ import unicode_literals
+import os
+import shutil
import warnings
from base64 import b64encode
@@ -28,7 +30,7 @@ warnings.resetwarnings()
class TorrentmanagerTestCase(BaseTestCase):
def set_up(self):
- common.set_tmp_config_dir()
+ self.config_dir = common.set_tmp_config_dir()
self.rpcserver = RPCServer(listen=False)
self.core = Core()
self.core.config.config['lsd'] = False
@@ -118,3 +120,12 @@ class TorrentmanagerTestCase(BaseTestCase):
self.assertRaises(
InvalidTorrentError, self.tm.remove, 'torrentidthatdoesntexist'
)
+
+ def test_open_state_from_python2(self):
+ """Open a Python2 state with a UTF-8 encoded torrent filename."""
+ shutil.copy(
+ common.get_test_data_file('utf8_filename_torrents.state'),
+ os.path.join(self.config_dir, 'state', 'torrents.state'),
+ )
+ state = self.tm.open_state()
+ self.assertEqual(len(state.torrents), 1)