Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace obsolete JS media type #2111

Merged
merged 9 commits into from
Jun 4, 2023
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),
vytas7 marked this conversation as resolved.
Show resolved Hide resolved
('.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'
Loading