Skip to content

Commit

Permalink
Redirect with a 308 rather than 301
Browse files Browse the repository at this point in the history
With strict slashes enabled and the route defined with a trailing
slash e.g. `/a/` a request to `/a` currently results in a 301 response
to redirect to `/a/`. This is good for GET and HEAD requests, but
problematic for other verbs as clients will typically treat a 301
response as meaning redirect as a GET verb as noted in RFC 2616
section-10.3.2 (RFC 2616 stated this was erroneous, and then RFC 7231
allowed this behaviour). RFC 7538 later introduced a 308 code to work
as 301 was originally intended. As 308 is now widely supported, 301
can be changed to 308.
  • Loading branch information
pgjones authored and davidism committed Nov 22, 2018
1 parent 4d30c23 commit fd6eb30
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Unreleased
``_empty_stream`` instance. This improves test isolation by preventing
cases where closing the stream in one request would affect other usages.
(`#1340`_)
- Change ``RequestRedirect`` code from 301 to 308, preserving the verb
and request body (form data) during redirect. (`#1342`_)
- The version of jQuery used by the debugger is updated to 3.3.1.
(`#1390`_)
- The debugger correctly renders long ``markupsafe.Markup`` instances.
Expand Down Expand Up @@ -153,6 +155,7 @@ Unreleased
.. _`#1325`: https://github.com/pallets/werkzeug/pull/1325
.. _`#1338`: https://github.com/pallets/werkzeug/pull/1338
.. _`#1340`: https://github.com/pallets/werkzeug/pull/1340
.. _`#1342`: https://github.com/pallets/werkzeug/pull/1342
.. _`#1346`: https://github.com/pallets/werkzeug/pull/1346
.. _`#1358`: https://github.com/pallets/werkzeug/pull/1358
.. _`#1375`: https://github.com/pallets/werkzeug/pull/1375
Expand Down
6 changes: 5 additions & 1 deletion tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def test_strict_slashes_redirect():
map = r.Map([
r.Rule('/bar/', endpoint='get', methods=["GET"]),
r.Rule('/bar', endpoint='post', methods=["POST"]),
r.Rule('/foo/', endpoint='foo', methods=["POST"]),
])
adapter = map.bind('example.org', '/')

Expand All @@ -74,6 +75,9 @@ def test_strict_slashes_redirect():
# Check if exceptions are correct
pytest.raises(r.RequestRedirect, adapter.match, '/bar', method='GET')
pytest.raises(r.MethodNotAllowed, adapter.match, '/bar/', method='POST')
with pytest.raises(r.RequestRedirect) as error_info:
adapter.match('/foo', method='POST')
assert error_info.value.code == 308

# Check differently defined order
map = r.Map([
Expand Down Expand Up @@ -277,7 +281,7 @@ def view_func(endpoint, values):
)

assert dispatch('/').data == b"('root', {})"
assert dispatch('/foo').status_code == 301
assert dispatch('/foo').status_code == 308
raise_this = r.NotFound()
pytest.raises(r.NotFound, lambda: dispatch('/bar'))
assert dispatch('/bar', True).status_code == 404
Expand Down
2 changes: 1 addition & 1 deletion werkzeug/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class RequestRedirect(HTTPException, RoutingException):
The attribute `new_url` contains the absolute destination url.
"""
code = 301
code = 308

def __init__(self, new_url):
RoutingException.__init__(self, new_url)
Expand Down
8 changes: 4 additions & 4 deletions werkzeug/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,10 @@ def handle_match(m):

def redirect(location, code=302, Response=None):
"""Returns a response object (a WSGI application) that, if called,
redirects the client to the target location. Supported codes are 301,
302, 303, 305, and 307. 300 is not supported because it's not a real
redirect and 304 because it's the answer for a request with a request
with defined If-Modified-Since headers.
redirects the client to the target location. Supported codes are
301, 302, 303, 305, 307, and 308. 300 is not supported because
it's not a real redirect and 304 because it's the answer for a
request with a request with defined If-Modified-Since headers.
.. versionadded:: 0.6
The location can now be a unicode string that is encoded using
Expand Down

0 comments on commit fd6eb30

Please sign in to comment.