Code

Ticket #17449: ticket-17449-default-options.patch

File ticket-17449-default-options.patch, 4.8 KB (added by estebistec, 2 years ago)

Patch adjusted to only implement default OPTIONS

  • docs/ref/request-response.txt

     
    748748    The constructor doesn't take any arguments. Use this to designate that a 
    749749    page hasn't been modified since the user's last request (status code 304). 
    750750 
     751.. class:: HttpResponseOptions 
     752 
     753    Like :class:`HttpResponse`, but uses a 200 status code and provides 
     754    an ``Allow`` response header. Takes a single, required argument: a list 
     755    of permitted methods (e.g., ``['GET', 'POST']``) used to populate 
     756    the ``Allow`` header. 
     757 
    751758.. class:: HttpResponseBadRequest 
    752759 
    753760    Acts just like :class:`HttpResponse` but uses a 400 status code. 
  • tests/regressiontests/generic_views/base.py

     
    170170        """ 
    171171        self.assertTrue(DecoratedDispatchView.as_view().is_decorated) 
    172172 
     173    def test_head_no_get(self): 
     174        """ 
     175        Test that a view class with no get responds to a HEAD request with HTTP 
     176        405. 
     177        """ 
     178        request = self.rf.head('/') 
     179        view = PostOnlyView.as_view() 
     180        self.assertEqual(405, view(request).status_code) 
    173181 
     182    def test_options(self): 
     183        """ 
     184        Test that views respond to HTTP OPTIONS requests with an Allow header 
     185        appropriate for the methods implemented by the view class. 
     186        """ 
     187        request = self.rf.options('/') 
     188        view = SimpleView.as_view() 
     189        response = view(request) 
     190        self.assertEqual(200, response.status_code) 
     191        self.assertTrue(response['Allow']) 
     192 
     193    def test_options_for_get_view(self): 
     194        """ 
     195        Test that a view implementing GET allows GET and HEAD. 
     196        """ 
     197        request = self.rf.options('/') 
     198        view = SimpleView.as_view() 
     199        response = view(request) 
     200        self._assert_allows(response, 'GET', 'HEAD') 
     201 
     202    def test_options_for_get_and_post_view(self): 
     203        """ 
     204        Test that a view implementing GET and POST allows GET, HEAD, and POST. 
     205        """ 
     206        request = self.rf.options('/') 
     207        view = SimplePostView.as_view() 
     208        response = view(request) 
     209        self._assert_allows(response, 'GET', 'HEAD', 'POST') 
     210 
     211    def test_options_for_post_view(self): 
     212        """ 
     213        Test that a view implementing POST allows POST. 
     214        """ 
     215        request = self.rf.options('/') 
     216        view = PostOnlyView.as_view() 
     217        response = view(request) 
     218        self._assert_allows(response, 'POST') 
     219 
     220    def _assert_allows(self, response, *expected_methods): 
     221        "Assert allowed HTTP methods reported in the Allow response header" 
     222        response_allows = set(response['Allow'].split(', ')) 
     223        self.assertEqual(set(expected_methods + ('OPTIONS',)), response_allows) 
     224 
     225 
    174226class TemplateViewTest(TestCase): 
    175227    urls = 'regressiontests.generic_views.urls' 
    176228 
  • django/http/__init__.py

     
    726726            raise Exception("This %s instance cannot tell its position" % self.__class__) 
    727727        return sum([len(str(chunk)) for chunk in self._container]) 
    728728 
     729class HttpResponseOptions(HttpResponse): 
     730    status_code = 200 
     731 
     732    def __init__(self, permitted_methods): 
     733        super(HttpResponseOptions, self).__init__() 
     734        self['Allow'] = ', '.join(permitted_methods) 
     735        self['Content-Length'] = '0' 
     736 
    729737class HttpResponseRedirect(HttpResponse): 
    730738    status_code = 302 
    731739 
  • django/views/generic/base.py

     
    6969        return handler(request, *args, **kwargs) 
    7070 
    7171    def http_method_not_allowed(self, request, *args, **kwargs): 
    72         allowed_methods = [m for m in self.http_method_names if hasattr(self, m)] 
    7372        logger.warning('Method Not Allowed (%s): %s', request.method, request.path, 
    7473            extra={ 
    7574                'status_code': 405, 
    7675                'request': self.request 
    7776            } 
    7877        ) 
    79         return http.HttpResponseNotAllowed(allowed_methods) 
     78        return http.HttpResponseNotAllowed(self._allowed_methods()) 
    8079 
     80    def options(self, request, *args, **kwargs): 
     81        return http.HttpResponseOptions(self._allowed_methods()) 
    8182 
     83    def _allowed_methods(self): 
     84        return [m.upper() for m in self.http_method_names if hasattr(self, m)] 
     85 
     86 
    8287class TemplateResponseMixin(object): 
    8388    """ 
    8489    A mixin that can be used to render a template.