141

I need to get all the Django request headers. From what I've read, Django simply dumps everything into the request.META variable along with a lot of other data. What would be the best way to get all the headers that the client sent to my Django application?

I'm going use these to build a httplib request.

smitop
  • 4,770
  • 2
  • 20
  • 53
Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382

10 Answers10

171

According to the documentation request.META is a "standard Python dictionary containing all available HTTP headers". If you want to get all the headers you can simply iterate through the dictionary.

Which part of your code to do this depends on your exact requirement. Anyplace that has access to request should do.

Update

I need to access it in a Middleware class but when i iterate over it, I get a lot of values apart from HTTP headers.

From the documentation:

With the exception of CONTENT_LENGTH and CONTENT_TYPE, as given above, any HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name.

(Emphasis added)

To get the HTTP headers alone, just filter by keys prefixed with HTTP_.

Update 2

could you show me how I could build a dictionary of headers by filtering out all the keys from the request.META variable which begin with a HTTP_ and strip out the leading HTTP_ part.

Sure. Here is one way to do it.

import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value) 
       in request.META.items() if header.startswith('HTTP_'))
Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
  • I need to access it in a Middleware class but when i iterate over it, I get a lot of values apart from HTTP headers. – Mridang Agarwalla Oct 08 '10 at 11:03
  • Thanks Manoj. Just out of curiosity - could you show me how I could build a dictionary of headers by filtering out all the keys from the `request.META` variable which begin with a `HTTP_` and strip out the leading `HTTP_` part. Is this possible through lambda functions? (I think they're called lambda functions) I'm asking this because I would probably go on do it the long way by first iterating over them, then checking to see if it begins with a `HTTP_` and then adding it to the new dictionary. Thanks again. – Mridang Agarwalla Oct 08 '10 at 11:21
  • Thanks again Manoj. I modified it slightly to use `lstrip('HTTP_')` instead of the regex. :) – Mridang Agarwalla Oct 08 '10 at 13:17
  • @Mridang: `lstrip`. Of course. My substitute fu is weak today evening. – Manoj Govindan Oct 08 '10 at 13:23
  • This does not seem to work with agents like CURL. It appears CURL is not setting the META dictionary while typical browsers do. –  Nov 29 '11 at 18:49
  • 3
    @Mridang Agarwalla: `lstrip` won't actually do what you're asking it to do. `lstrip` will strip out all leading characters that match any characters in the string you give it, so if you have a header `"HTTP_TOKEN_ID"` it will give back `"OKEN_ID"`, because the `"T"` at the beginning of `"TOKEN"` matches a character in the string passed to lstrip. The way to do it is `prefix = 'HTTP_'; header = header[len(prefix):]`. – jcdyer Apr 15 '14 at 16:23
  • I'll be using the headers for a new request, treating Django as a proxy and I was worried about the headers being all upper-case. Turns out HTTP headers are case-insensitive, so this isn't an issue. – freb Jan 26 '15 at 17:42
  • 2
    Django 2.2 has supported `HttpRequest.headers`. – 周左左 Apr 01 '19 at 15:14
63

Starting from Django 2.2, you can use request.headers to access the HTTP headers. From the documentation on HttpRequest.headers:

A case insensitive, dict-like object that provides access to all HTTP-prefixed headers (plus Content-Length and Content-Type) from the request.

The name of each header is stylized with title-casing (e.g. User-Agent) when it’s displayed. You can access headers case-insensitively:

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

To get all headers, you can use request.headers.keys() or request.headers.items().

Community
  • 1
  • 1
Daniel Hepper
  • 28,981
  • 10
  • 72
  • 75
19

Simply you can use HttpRequest.headers from Django 2.2 onward. Following example is directly taken from the official Django Documentation under Request and response objects section.

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
Kushan Gunasekera
  • 7,268
  • 6
  • 44
  • 58
19

This is another way to do it, very similar to Manoj Govindan's answer above:

import re
regex_http_          = re.compile(r'^HTTP_.+$')
regex_content_type   = re.compile(r'^CONTENT_TYPE$')
regex_content_length = re.compile(r'^CONTENT_LENGTH$')

request_headers = {}
for header in request.META:
    if regex_http_.match(header) or regex_content_type.match(header) or regex_content_length.match(header):
        request_headers[header] = request.META[header]

That will also grab the CONTENT_TYPE and CONTENT_LENGTH request headers, along with the HTTP_ ones. request_headers['some_key] == request.META['some_key'].

Modify accordingly if you need to include/omit certain headers. Django lists a bunch, but not all, of them here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Django's algorithm for request headers:

  1. Replace hyphen - with underscore _
  2. Convert to UPPERCASE.
  3. Prepend HTTP_ to all headers in original request, except for CONTENT_TYPE and CONTENT_LENGTH.

The values of each header should be unmodified.

Dave
  • 12,408
  • 12
  • 64
  • 67
  • 6
    That can all be combined into a single regexp, `re.compile(r'^(HTTP_.+|CONTENT_TYPE|CONTENT_LENGTH)$')` – Rebs Dec 04 '15 at 03:41
7

request.META.get('HTTP_AUTHORIZATION') /python3.6/site-packages/rest_framework/authentication.py

you can get that from this file though...

3

I don't think there is any easy way to get only HTTP headers. You have to iterate through request.META dict to get what all you need.

django-debug-toolbar takes the same approach to show header information. Have a look at this file responsible for retrieving header information.

Srikanth Chundi
  • 897
  • 9
  • 8
1

For what it's worth, it appears your intent is to use the incoming HTTP request to form another HTTP request. Sort of like a gateway. There is an excellent module django-revproxy that accomplishes exactly this.

The source is a pretty good reference on how to accomplish what you are trying to do.

Stuart Axon
  • 1,844
  • 1
  • 26
  • 44
abhayAndPoorvisDad
  • 3,477
  • 2
  • 15
  • 17
1

If you want to get client key from request header, u can try following:

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from apps.authentication.models import CerebroAuth

class CerebroAuthentication(BaseAuthentication):
def authenticate(self, request):
    client_id = request.META.get('HTTP_AUTHORIZATION')
    if not client_id:
        raise exceptions.AuthenticationFailed('Client key not provided')
    client_id = client_id.split()
    if len(client_id) == 1 or len(client_id) > 2:
        msg = ('Invalid secrer key header. No credentials provided.')
        raise exceptions.AuthenticationFailed(msg)
    try:
        client = CerebroAuth.objects.get(client_id=client_id[1])
    except CerebroAuth.DoesNotExist:
        raise exceptions.AuthenticationFailed('No such client')
    return (client, None)
Nazik
  • 8,696
  • 27
  • 77
  • 123
Tony Aziz
  • 899
  • 6
  • 4
0
<b>request.META</b><br>
{% for k_meta, v_meta in request.META.items %}
  <code>{{ k_meta }}</code> : {{ v_meta }} <br>
{% endfor %}
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
S. Nick
  • 12,879
  • 8
  • 25
  • 33
0

Just be aware to use "-" instead of "_" in header Key

Because if you use "Current_User" in header, you can not get it by

request.headers.get('Current_User')   <-- None

user "xxx-xxx" as the key

C.K.
  • 4,348
  • 29
  • 43