diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 321e2aef6..cc920fa3a 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -30,7 +30,7 @@ import qutebrowser.utils.message as message from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.usertypes import PromptMode, Question, Timer from qutebrowser.utils.misc import (interpolate_color, format_seconds, - format_size) + format_size, get_http_header) class DownloadItem(QObject): @@ -321,18 +321,10 @@ class DownloadManager(QObject): Args: reply: The QNetworkReply to get a filename for. """ - filename = None # First check if the Content-Disposition header has a filename # attribute. - if reply.hasRawHeader('Content-Disposition'): - header = reply.rawHeader('Content-Disposition') - data = header.split(':', maxsplit=1)[1].strip() - for pair in data.split(';'): - if '=' in pair: - key, value = pair.split('=') - if key == 'filename': - filename = value.strip('"') - break + from qutebrowser.utils.debug import set_trace; set_trace() + filename = get_http_header(reply, 'Content-Disposition', 'filename') # Then try to get filename from url if not filename: filename = reply.url().path() diff --git a/qutebrowser/utils/misc.py b/qutebrowser/utils/misc.py index 00dad0b37..b98ccfcaa 100644 --- a/qutebrowser/utils/misc.py +++ b/qutebrowser/utils/misc.py @@ -26,6 +26,8 @@ import os import re import sys import shlex +import email +import email.policy import os.path import operator import urllib.request @@ -393,6 +395,33 @@ def check_print_compat(): return not (os.name == 'nt' and qt_version_check('5.3.0', operator.lt)) +def get_http_header(reply, headername, param=None): + """Get a parameter from a HTTP header. + + Note we use the email value to get a HTTP header, because they're both MIME + headers and email supports that. + + Args: + reply: The QNetworkReply to get the header from. + headername: The name of the header. + param: The name of the param to get, or None to get the whole contents. + + Return: + The data as a string, or None if the data wasn't found. + + FIXME add tests + """ + if not reply.hasRawHeader(headername): + return None + header = (headername.encode('ascii') + b': ' + + bytes(reply.rawHeader(headername))) + msg = email.message_from_bytes(header, policy=email.policy.HTTP) + if param is not None: + return msg.get_param(param, header=headername) + else: + return msg.get(headername, None) + + class EventLoop(QEventLoop): """A thin wrapper around QEventLoop.