[UI] Replace deprecated cgi module with email

As PEP 594 says, cgi module is marked as deprecated
in python 3.11, and will be removed in 3.13
(actually removed at least in 3.13 rc1).

As suggested on PEP 594, replace cgi.parse_header
with email.message.EmailMessage introduced in python 3.6.

Updated test modify test_download_with_rename_sanitised
- With RFC2045 specification, Content-Disposition filenames
parameter containing slash (directory separator) must be
quoted, so changing as such.

Ref: https://peps.python.org/pep-0594/#deprecated-modules
Ref: https://peps.python.org/pep-0594/#cgi

Closes: https://github.com/deluge-torrent/deluge/pull/462
This commit is contained in:
Mamoru TASAKA 2024-08-29 15:31:25 +09:00 committed by Calum Lind
parent 3bceb4bfc1
commit 5d96cfc72f
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
3 changed files with 15 additions and 9 deletions

View File

@ -6,7 +6,7 @@
# See LICENSE for more details. # See LICENSE for more details.
# #
import cgi import email.message
import logging import logging
import os.path import os.path
import zlib import zlib
@ -133,9 +133,10 @@ class HTTPDownloaderAgent:
content_disp = headers.getRawHeaders(b'content-disposition')[0].decode( content_disp = headers.getRawHeaders(b'content-disposition')[0].decode(
'utf-8' 'utf-8'
) )
content_disp_params = cgi.parse_header(content_disp)[1] message = email.message.EmailMessage()
if 'filename' in content_disp_params: message['content-disposition'] = content_disp
new_file_name = content_disp_params['filename'] new_file_name = message.get_filename()
if new_file_name:
new_file_name = sanitise_filename(new_file_name) new_file_name = sanitise_filename(new_file_name)
new_file_name = os.path.join( new_file_name = os.path.join(
os.path.split(self.filename)[0], new_file_name os.path.split(self.filename)[0], new_file_name
@ -152,7 +153,10 @@ class HTTPDownloaderAgent:
self.filename = new_file_name self.filename = new_file_name
cont_type_header = headers.getRawHeaders(b'content-type')[0].decode() cont_type_header = headers.getRawHeaders(b'content-type')[0].decode()
cont_type, params = cgi.parse_header(cont_type_header) message = email.message.EmailMessage()
message['content-type'] = cont_type_header
cont_type = message.get_content_type()
params = message['content-type'].params
# Only re-ecode text content types. # Only re-ecode text content types.
encoding = None encoding = None
if cont_type.startswith('text/'): if cont_type.startswith('text/'):

View File

@ -206,10 +206,10 @@ class TestDownloadFile:
self.assert_contains(filename, 'This file should be called renamed') self.assert_contains(filename, 'This file should be called renamed')
async def test_download_with_rename_sanitised(self): async def test_download_with_rename_sanitised(self):
url = self.get_url('rename?filename=/etc/passwd') url = self.get_url('rename?filename="/etc/passwd"')
filename = await download_file(url, fname('original')) filename = await download_file(url, fname('original'))
assert filename == fname('passwd') assert filename == fname('passwd')
self.assert_contains(filename, 'This file should be called /etc/passwd') self.assert_contains(filename, 'This file should be called "/etc/passwd"')
async def test_download_with_attachment_no_filename(self): async def test_download_with_attachment_no_filename(self):
url = self.get_url('attachment') url = self.get_url('attachment')

View File

@ -6,7 +6,7 @@
# See LICENSE for more details. # See LICENSE for more details.
# #
import cgi import email.message
import json import json
import logging import logging
import os import os
@ -191,7 +191,9 @@ class JSON(resource.Resource, component.Component):
Handler to take the json data as a string and pass it on to the Handler to take the json data as a string and pass it on to the
_handle_request method for further processing. _handle_request method for further processing.
""" """
content_type, _ = cgi.parse_header(request.getHeader(b'content-type').decode()) message = email.message.EmailMessage()
message['content-type'] = request.getHeader(b'content-type').decode()
content_type = message.get_content_type()
if content_type != 'application/json': if content_type != 'application/json':
message = 'Invalid JSON request content-type: %s' % content_type message = 'Invalid JSON request content-type: %s' % content_type
raise JSONException(message) raise JSONException(message)