Skip to content

Commit

Permalink
feat: replace obsolete JS media type (#2111)
Browse files Browse the repository at this point in the history
* Replace obsolete JS media type

* feat(response): prefer `falcon.MEDIA_*` constants to stdlib's `mimetypes`

* feat(static): add static media type mapping for `.mjs`

---------

Co-authored-by: Vytautas Liuolia <vytautas.liuolia@gmail.com>
  • Loading branch information
euj1n0ng and vytas7 committed Jun 4, 2023
1 parent c7c790f commit 7dff4ff
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
6 changes: 6 additions & 0 deletions docs/_newsfragments/2110.newandimproved.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Following the recommendation from
`RFC 9239 <https://www.rfc-editor.org/rfc/rfc9239>`__, the
:ref:`MEDIA_JS <media_type_constants>` constant has been updated to
``text/javascript``. Furthermore, this and other media type constants are now
preferred to the stdlib's :mod:`mimetypes` for the initialization of
:attr:`~falcon.ResponseOptions.static_media_types`.
36 changes: 28 additions & 8 deletions falcon/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,10 @@
# contrary to the RFCs.
MEDIA_XML = 'application/xml'

# NOTE(kgriffs): RFC 4329 recommends application/* over text/.
# furthermore, parsers are required to respect the Unicode
# encoding signature, if present in the document, and to default
# to UTF-8 when not present. Note, however, that implementations
# are not required to support anything besides UTF-8, so it is
# unclear how much utility an encoding signature (or the charset
# parameter for that matter) has in practice.
MEDIA_JS = 'application/javascript'
# NOTE(euj1n0ng): According to RFC 9239, Changed the intended usage of the
# media type "text/javascript" from OBSOLETE to COMMON. Changed
# the intended usage for all other script media types to obsolete.
MEDIA_JS = 'text/javascript'

# NOTE(kgriffs): According to RFC 6838, most text media types should
# include the charset parameter.
Expand Down Expand Up @@ -141,6 +137,30 @@
]
)

# NOTE(vytas): We strip the preferred charsets from the default static file
# type mapping as it is hard to make any assumptions without knowing which
# files are going to be served. Moreover, the popular web servers (like
# Nginx) do not try to guess either.
_DEFAULT_STATIC_MEDIA_TYPES = tuple(
(ext, media_type.split(';', 1)[0])
for ext, media_type in (
('.bmp', MEDIA_BMP),
('.gif', MEDIA_GIF),
('.htm', MEDIA_HTML),
('.html', MEDIA_HTML),
('.jpeg', MEDIA_JPEG),
('.jpg', MEDIA_JPEG),
('.js', MEDIA_JS),
('.json', MEDIA_JSON),
('.mjs', MEDIA_JS),
('.png', MEDIA_PNG),
('.txt', MEDIA_TEXT),
('.xml', MEDIA_XML),
('.yaml', MEDIA_YAML),
('.yml', MEDIA_YAML),
)
)

# NOTE(kgriffs): Special singleton to be used internally whenever using
# None would be ambiguous.
_UNSET = object()
Expand Down
4 changes: 3 additions & 1 deletion falcon/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import functools
import mimetypes

from falcon.constants import _DEFAULT_STATIC_MEDIA_TYPES
from falcon.constants import _UNSET
from falcon.constants import DEFAULT_MEDIA_TYPE
from falcon.errors import HeaderNotSupported
Expand Down Expand Up @@ -1246,4 +1247,5 @@ def __init__(self):

if not mimetypes.inited:
mimetypes.init()
self.static_media_types = mimetypes.types_map
self.static_media_types = mimetypes.types_map.copy()
self.static_media_types.update(_DEFAULT_STATIC_MEDIA_TYPES)
11 changes: 9 additions & 2 deletions tests/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,20 @@ def test_response_removed_stream_len(resp):
def test_response_option_mimetype_init(monkeypatch):
mock = MagicMock()
mock.inited = False
mock.types_map = {'.js': 'application/javascript'}
monkeypatch.setattr('falcon.response.mimetypes', mock)

ro = ResponseOptions()

assert ro.static_media_types is mock.types_map
assert ro.static_media_types['.js'] == 'text/javascript'
assert ro.static_media_types['.json'] == 'application/json'
assert ro.static_media_types['.mjs'] == 'text/javascript'

mock.reset_mock()
mock.inited = True
ro = ResponseOptions()
assert ro.static_media_types is mock.types_map
mock.init.assert_not_called()

assert ro.static_media_types['.js'] == 'text/javascript'
assert ro.static_media_types['.json'] == 'application/json'
assert ro.static_media_types['.mjs'] == 'text/javascript'

0 comments on commit 7dff4ff

Please sign in to comment.