mirror of https://github.com/pypa/pip
Move parse_content_disposition to network.download
This commit is contained in:
parent
32b0fc23ab
commit
762e4a0817
|
@ -1,5 +1,6 @@
|
|||
"""Download files with progress indicators.
|
||||
"""
|
||||
import cgi
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
@ -80,3 +81,18 @@ def sanitize_content_filename(filename):
|
|||
Sanitize the "filename" value from a Content-Disposition header.
|
||||
"""
|
||||
return os.path.basename(filename)
|
||||
|
||||
|
||||
def parse_content_disposition(content_disposition, default_filename):
|
||||
# type: (str, str) -> str
|
||||
"""
|
||||
Parse the "filename" value from a Content-Disposition header, and
|
||||
return the default filename if the result is empty.
|
||||
"""
|
||||
_type, params = cgi.parse_header(content_disposition)
|
||||
filename = params.get('filename')
|
||||
if filename:
|
||||
# We need to sanitize the filename to prevent directory traversal
|
||||
# in case the filename contains ".." path parts.
|
||||
filename = sanitize_content_filename(filename)
|
||||
return filename or default_filename
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
# mypy: strict-optional=False
|
||||
# mypy: disallow-untyped-defs=False
|
||||
|
||||
import cgi
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
|
@ -30,7 +29,7 @@ from pip._internal.exceptions import (
|
|||
)
|
||||
from pip._internal.network.download import (
|
||||
_prepare_download,
|
||||
sanitize_content_filename,
|
||||
parse_content_disposition,
|
||||
)
|
||||
from pip._internal.network.session import PipSession
|
||||
from pip._internal.utils.compat import expanduser
|
||||
|
@ -308,21 +307,6 @@ def unpack_url(
|
|||
)
|
||||
|
||||
|
||||
def parse_content_disposition(content_disposition, default_filename):
|
||||
# type: (str, str) -> str
|
||||
"""
|
||||
Parse the "filename" value from a Content-Disposition header, and
|
||||
return the default filename if the result is empty.
|
||||
"""
|
||||
_type, params = cgi.parse_header(content_disposition)
|
||||
filename = params.get('filename')
|
||||
if filename:
|
||||
# We need to sanitize the filename to prevent directory traversal
|
||||
# in case the filename contains ".." path parts.
|
||||
filename = sanitize_content_filename(filename)
|
||||
return filename or default_filename
|
||||
|
||||
|
||||
def _get_http_response_filename(resp, link):
|
||||
# type: (Response, Link) -> str
|
||||
"""Get an ideal filename from the given HTTP response, falling back to
|
||||
|
|
|
@ -6,6 +6,7 @@ import pytest
|
|||
from pip._internal.models.link import Link
|
||||
from pip._internal.network.download import (
|
||||
_prepare_download,
|
||||
parse_content_disposition,
|
||||
sanitize_content_filename,
|
||||
)
|
||||
from tests.lib.requests_mocks import MockResponse
|
||||
|
@ -77,3 +78,15 @@ def test_sanitize_content_filename__platform_dependent(
|
|||
else:
|
||||
expected = non_win_expected
|
||||
assert sanitize_content_filename(filename) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("content_disposition, default_filename, expected", [
|
||||
('attachment;filename="../file"', 'df', 'file'),
|
||||
])
|
||||
def test_parse_content_disposition(
|
||||
content_disposition,
|
||||
default_filename,
|
||||
expected
|
||||
):
|
||||
actual = parse_content_disposition(content_disposition, default_filename)
|
||||
assert actual == expected
|
||||
|
|
|
@ -14,7 +14,6 @@ from pip._internal.operations.prepare import (
|
|||
Downloader,
|
||||
_copy_source_tree,
|
||||
_download_http_url,
|
||||
parse_content_disposition,
|
||||
unpack_file_url,
|
||||
unpack_http_url,
|
||||
)
|
||||
|
@ -106,18 +105,6 @@ def test_unpack_http_url_bad_downloaded_checksum(mock_unpack_file):
|
|||
rmtree(download_dir)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("content_disposition, default_filename, expected", [
|
||||
('attachment;filename="../file"', 'df', 'file'),
|
||||
])
|
||||
def test_parse_content_disposition(
|
||||
content_disposition,
|
||||
default_filename,
|
||||
expected
|
||||
):
|
||||
actual = parse_content_disposition(content_disposition, default_filename)
|
||||
assert actual == expected
|
||||
|
||||
|
||||
def test_download_http_url__no_directory_traversal(tmpdir):
|
||||
"""
|
||||
Test that directory traversal doesn't happen on download when the
|
||||
|
|
Loading…
Reference in New Issue