diff --git a/docs/topics/browser-enhancements.md b/docs/topics/browser-enhancements.md index 6a11f0fac..8b1914231 100644 --- a/docs/topics/browser-enhancements.md +++ b/docs/topics/browser-enhancements.md @@ -19,6 +19,23 @@ For example, given the following form: `request.method` would return `"DELETE"`. +## HTTP header based method overriding + +REST framework also supports method overriding via the `X-HTTP-Method-Override` +header. This is useful if you are working with non-form content such as +JSON and are working with an older web server and/or hosting provider +(e.g. [Amazon Web Services ELB][aws_elb]) that doesn't recognise particular +HTTP methods such as `PATCH`. + +For example, making a `PATCH` request via `POST` in jQuery: + + $.ajax({ + url: '/myresource/', + method: 'POST', + headers: {'X-HTTP-Method-Override': 'PATCH'}, + ... + }); + ## Browser based submission of non-form content Browser-based submission of content types other than form are supported by @@ -62,3 +79,4 @@ as well as how to support content types other than form-encoded data. [rails]: http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-put-or-delete-methods-work [html5]: http://www.w3.org/TR/html5-diff/#changes-2010-06-24 [put_delete]: http://amundsen.com/examples/put-delete-forms/ +[aws_elb]: https://forums.aws.amazon.com/thread.jspa?messageID=400724 diff --git a/rest_framework/request.py b/rest_framework/request.py index 3e2fbd88e..f26d934d7 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -231,10 +231,13 @@ class Request(object): """ self._content_type = self.META.get('HTTP_CONTENT_TYPE', self.META.get('CONTENT_TYPE', '')) + self._perform_form_overloading() - # if the HTTP method was not overloaded, we take the raw HTTP method if not _hasattr(self, '_method'): - self._method = self._request.method + # Method wasn't overloaded by hidden form element, so look for + # method override in header. If not present default to raw HTTP method + self._method = self.META.get('HTTP_X_HTTP_METHOD_OVERRIDE', + self._request.method) def _load_stream(self): """ diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index 4892f7a63..97e5af207 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -58,6 +58,14 @@ class TestMethodOverloading(TestCase): request = Request(factory.post('/', {api_settings.FORM_METHOD_OVERRIDE: 'DELETE'})) self.assertEqual(request.method, 'DELETE') + def test_x_http_method_override_header(self): + """ + POST requests can also be overloaded to another method by setting + the X-HTTP-Method-Override header. + """ + request = Request(factory.post('/', {'foo': 'bar'}, HTTP_X_HTTP_METHOD_OVERRIDE='DELETE')) + self.assertEqual(request.method, 'DELETE') + class TestContentParsing(TestCase): def test_standard_behaviour_determines_no_content_GET(self):