Skip to content

Commit

Permalink
Content-Disposition fast access in ClientResponse
Browse files Browse the repository at this point in the history
Add content_disposition and content_disposition_dict properties

Partially implements #1670
  • Loading branch information
Sergey Skripnick committed Oct 31, 2017
1 parent 20362c5 commit be43246
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
22 changes: 22 additions & 0 deletions aiohttp/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ class HeadersMixin:

_content_type = None
_content_dict = None
_stored_content_disposition = None
_stored_content_type = sentinel

def _parse_content_type(self, raw):
Expand All @@ -714,6 +715,13 @@ def _parse_content_type(self, raw):
else:
self._content_type, self._content_dict = cgi.parse_header(raw)

def _parse_content_disposition(self, _CONTENT_DISPOSITION):
raw = self._headers.get(_CONTENT_DISPOSITION)
if raw is not None:
self._stored_content_disposition = cgi.parse_header(raw)
else:
self._stored_content_disposition = (None, {})

@property
def content_type(self, *, _CONTENT_TYPE=hdrs.CONTENT_TYPE):
"""The value of content part for Content-Type HTTP header."""
Expand All @@ -737,3 +745,17 @@ def content_length(self, *, _CONTENT_LENGTH=hdrs.CONTENT_LENGTH):

if content_length:
return int(content_length)

@property
def content_disposition(self, *, header=hdrs.CONTENT_DISPOSITION):
"""The value of Content-Disposition HTTP header."""
if self._stored_content_disposition is None:
self._parse_content_disposition(header)
return self._stored_content_disposition[0]

@property
def content_disposition_dict(self, *, header=hdrs.CONTENT_DISPOSITION):
"""Parameters of Content-Disposition HTTP header."""
if self._stored_content_disposition is None:
self._parse_content_disposition(header)
return self._stored_content_disposition[1]
19 changes: 19 additions & 0 deletions docs/client_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,25 @@ Response object
Returns :class:`str` like ``'utf-8'`` or ``None`` if no *Content-Type*
header present in HTTP headers or it has no charset information.

.. attribute:: content_disposition

Read-only property that specified the *Content-Disposition* HTTP header.

Returns :class:`str` like ``'attachment'`` or ``None`` if no
*Content-Disposition* header present in HTTP headers.

.. seealso:: :attr:`content_disposition_dict`

.. attribute:: content_disposition_dict

Read-only property that specified the *Content-Disposition* dictionary of parameters.

Returns :class:`dict` like ``{'filename': 'archive.tar.gz'}`` or empty dict if no
*Content-Disposition* header present in HTTP headers.

.. note:: Using ``filename`` parameter directly may be not safe because it may
contain file path components, e.g. ``/home/user/.bashrc``.

.. attribute:: history

A :class:`~collections.abc.Sequence` of :class:`ClientResponse`
Expand Down
25 changes: 25 additions & 0 deletions tests/test_client_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,31 @@ def test_charset_no_charset():
assert response.charset is None


def test_content_disposition_full():
response = ClientResponse('get', URL('http://def-cl-resp.org'))
response.headers = {'Content-Disposition':
'attachment; filename="archive.tar.gz"'}

assert 'attachment' == response.content_disposition
assert 'archive.tar.gz' == response.content_disposition_dict["filename"]


def test_content_disposition_no_dict():
response = ClientResponse('get', URL('http://def-cl-resp.org'))
response.headers = {'Content-Disposition': 'attachment'}

assert 'attachment' == response.content_disposition
assert {} == response.content_disposition_dict


def test_content_disposition_no_header():
response = ClientResponse('get', URL('http://def-cl-resp.org'))
response.headers = {}

assert response.content_disposition is None
assert {} == response.content_disposition_dict


def test_response_request_info():
url = 'http://def-cl-resp.org'
headers = {'Content-Type': 'application/json;charset=cp1251'}
Expand Down

0 comments on commit be43246

Please sign in to comment.