Repository: encode/django-rest-framework

Issue:
rest_framework api view not working when CSRF_HEADER_NAME param is not default
## Checklist
- [X] I have verified that that issue exists against the `master` branch of Django REST framework.
- [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
- [X] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.)
- [X] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.)
- [X] I have reduced the issue to the simplest possible case.
- [X] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)
## Steps to reproduce

Set custom CSRF header name in settings.py eg.
setting.py:

``` python
CSRF_HEADER_NAME = "HTTP_X_XSRF_TOKEN"
```
1. Go to api view 
2. Login to account with permission to modificate any data
3. make request with unsafe method - for example modify data
## Expected behavior

Request should work and data should be modified.
## Actual behavior

Systems gives error CSRF Failed: CSRF token missing or incorrect.
## Patch

**rest_framework/static/rest_framework/js/csrf.js** change line 49 to:

``` javascript
xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken);
```

**rest_framework/templates/rest_framework/base.html** add new line between lines 265-266 from:

``` javascript
window.drf = {
          csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
```

to

``` javascript
window.drf = {
          csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}",
          csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
```

same story in file **rest_framework/templates/rest_framework/admin.html** but modification should be done between lines 234 and 235

``` javascript
window.drf = {
          csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
```

to

``` javascript
window.drf = {
          csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}",
          csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
```

**rest_framework/renderers.py** add new line between 678 and 679 before:

``` javascript
            'csrf_cookie_name': settings.CSRF_COOKIE_NAME,
        }
```

after

``` javascript
            'csrf_cookie_name': settings.CSRF_COOKIE_NAME,
            'csrf_header_name': (settings.CSRF_HEADER_NAME[5:].replace("_","-") if settings.CSRF_HEADER_NAME.startswith('HTTP_') else settings.CSRF_HEADER_NAME.replace("_","-")),
        }
```

and that is all. Last modification have those replaces call because Django documentation say:

```
As with other HTTP headers in request.META, the header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name. For example, if your client sends a 'X-XSRF-TOKEN' header, the setting should be 'HTTP_X_XSRF_TOKEN'.
```

ps. great job guys! Nice module. 



Discussion:
Great, thanks for the comprehensive report!


Resolving patch:
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -645,6 +645,12 @@ def get_context(self, data, accepted_media_type, renderer_context):
         else:
             paginator = None
 
+        csrf_cookie_name = settings.CSRF_COOKIE_NAME
+        csrf_header_name = getattr(settings, 'CSRF_HEADER_NAME', 'HTTP_X_CSRFToken')  # Fallback for Django 1.8
+        if csrf_header_name.startswith('HTTP_'):
+            csrf_header_name = csrf_header_name[5:]
+        csrf_header_name = csrf_header_name.replace('_', '-')
+
         context = {
             'content': self.get_content(renderer, data, accepted_media_type, renderer_context),
             'view': view,
@@ -675,7 +681,8 @@ def get_context(self, data, accepted_media_type, renderer_context):
             'display_edit_forms': bool(response.status_code != 403),
 
             'api_settings': api_settings,
-            'csrf_cookie_name': settings.CSRF_COOKIE_NAME,
+            'csrf_cookie_name': csrf_cookie_name,
+            'csrf_header_name': csrf_header_name
         }
         return context
 


Test patch: