Opened 5 years ago

Closed 23 months ago

#12747 closed New feature (fixed)

Custom HTTP status reason phrases are not supported

Reported by: Gustavo Owned by: gisle
Component: HTTP handling Version: master
Severity: Normal Keywords: http status, http status reason, http status reason phrase
Cc: akvadrako Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

At present, Django hard-codes the HTTP status reason phrases based on an integer that represents the HTTP status code, forcing the recommended phrases by the HTTP specification.

Note they are just the recommended/default phrases and developers should be allowed to override these phrases. For example, I may want to return the following and Django should allow me to do so:

403 Get out

Or,

200 Everything is fine

See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1

In order to support this, Django could have the following code in django.http:HttpResponse.__init__:

        if isinstance(status, basestring):
            # The status is given as a real HTTP status header, so we should
            # tell the code and the reason apart for Django:
            (status_code, status_reason) = status.split(" ", 1)
            status_code = int(status_code)
            self.status_reason = status_reason or None
        else:
            # The status has been given the old way supported by Django, simply
            # the status code as an integer:
            status_code = status
            self.status_reason = None

And the following on django.core.handlers.wsgi:WSGIHandler.__call__():

        if response.status_reason:
            status_text = "%s %s" % (response.status_code, response.status_reason)
        else:
            try:
                status_text = STATUS_CODE_TEXT[response.status_code]
            except KeyError:
                status_text = 'UNKNOWN STATUS CODE'

If any Django user wants to use this functionality before it gets implemented, they may use twod.wsgi: http://bitbucket.org/2degrees/twod.wsgi/

Attachments (3)

0001-Ticket-12747-Set-custom-status_text-message.patch (4.7 KB) - added by gisle 5 years ago.
0002-Test-that-the-custom-response-shows-up-on-the-WSGI-l.patch (3.0 KB) - added by gisle 5 years ago.
Test that the custom response shows up on the WSGI level as well
12747-3.diff (4.9 KB) - added by claudep 2 years ago.
Updated patch, tuple instead of string

Download all attachments as: .zip

Change History (23)

comment:1 Changed 5 years ago by Alex

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

comment:2 Changed 5 years ago by gisle

  • Owner changed from nobody to gisle

comment:3 Changed 5 years ago by gisle

  • Needs tests set

Changed 5 years ago by gisle

Test that the custom response shows up on the WSGI level as well

comment:4 Changed 5 years ago by gisle

  • Needs tests unset

comment:5 follow-up: Changed 5 years ago by ubernostrum

  • milestone 1.2 deleted

1.2 is feature-frozen, moving this feature request off the milestone.

comment:6 in reply to: ↑ 5 Changed 5 years ago by Gustavo

Replying to ubernostrum:

1.2 is feature-frozen, moving this feature request off the milestone.

This can hardly be a feature. It's a fix for partially broken HTTP support.

comment:7 Changed 5 years ago by russellm

@Gustavo:

Is there any condition under which the existing implementation will raise an error or cause data loss in the absence of a custom status message?

Is there any standard that is violated by not allowing a custom status message?

The answer to both of these questions is No. Therefore, this isn't a bug fix. It's a feature request.

It may be an extremely useful new feature, but that doesn't change the fact that it is still a feature, and Django 1.2 is feature frozen.

comment:8 Changed 4 years ago by akvadrako

  • Cc akvadrako added

comment:9 Changed 4 years ago by mattmcc

  • Severity set to Normal
  • Type set to New feature

comment:10 Changed 4 years ago by patchhammer

  • Easy pickings unset
  • Patch needs improvement set

0002-Test-that-the-custom-response-shows-up-on-the-WSGI-l.patch fails to apply cleanly on to trunk

comment:11 Changed 3 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

Changed 2 years ago by claudep

Updated patch, tuple instead of string

comment:12 Changed 2 years ago by claudep

  • Patch needs improvement unset
  • Version changed from 1.1 to master

Just attached an updated patch. I choose to pass a tuple as the status argument, instead of a string that has to be parsed, which is always fragile.

comment:13 Changed 2 years ago by aaugustin

I couldn't care less about this feature request, but the approach shown in the patch looks all right.

I don't have an opinion on using a string or a tuple or a new keyword argument to pass the status text.

The patch is out of date; otherwise, in the interest of crossing one ticket off the list, this is RFC.

comment:14 follow-up: Changed 2 years ago by aaugustin

Actually, since this isn't a particularly useful feature, and I don't expect anyone to ever need it, it'd be nice if it didn't have any overhead.

comment:15 in reply to: ↑ 14 Changed 2 years ago by Gustavo

Hi, aaugustin.

Replying to aaugustin:

Actually, since this isn't a particularly useful feature, and I don't expect anyone to ever need it, it'd be nice if it didn't have any overhead.

What do you mean by "overhead"? I think a new keyword argument would be cleaner, but I'm happy to update update the patch in either direction. Which is the approach you prefer?

Thanks.

comment:16 Changed 2 years ago by Paul McNett <p@…>

This is hackish, quickly written, and tested for only 10 minutes or so but I implemented custom status codes by monkeypatching the django.core.handlers.wsgi.STATUS_CODE_TEXT dict like:

import django.core.handlers.wsgi as wsgi

class NextDict(dict):
    def __init__(self, *args, **kwargs):
        self._nextdict = {}
        super(NextDict, self).__init__(*args, **kwargs)

    def set_next(self, key, value):
        """
        The next time this key is queried, return the passed value.
        After that, use the default.
        """
        self._nextdict[key] = value

    def __getitem__(self, key):
        if key in self._nextdict:
            v = self._nextdict[key]
            del(self._nextdict[key])
            return v
        return super(NextDict, self).__getitem__(key)

wsgi.STATUS_CODE_TEXT = NextDict(wsgi.STATUS_CODE_TEXT)

And then when I want my response to have a custom message for it's status code:

    class MyView(request):
        wsgi.STATUS_CODE_TEXT.set_next(200, "hello")
        return HttpResponse("hello again")

I googled for similar ideas and didn't find anyone doing this, so I thought it may give someone some ideas to develop this into a plugin or something. It wouldn't add overhead to the default (and reasonable) implementation, but would help some of us satisfy our requirements easily and without adding too much extra overhead...

comment:17 Changed 2 years ago by aaugustin

#20328 is a duplicate.

comment:18 Changed 2 years ago by ikame

For the API of my company we use this feature in a lot of places.
One of the use cases is:
We have a courses resource, if the teacher tries to DELETE a course with enrolled users, we return a 400 Cannot delete course with students response.

comment:19 Changed 23 months ago by aaugustin

I'd like to stop seeing pull requests about this.

If you want to do it, this is how: https://github.com/django/django/pull/1154

comment:20 Changed 23 months ago by Aymeric Augustin <aymeric.augustin@…>

  • Resolution set to fixed
  • Status changed from new to closed

In cb86f707a04e5635817d5f37a1443f9bf7d6af21:

Fixed #12747 -- Made reason phrases customizable.

Note: See TracTickets for help on using tickets.
Back to Top