[Flask] Cannot get custom header value from request.headers

Tom Vaughan thomas.david.vaughan at gmail.com
Thu Jul 27 15:54:17 EDT 2017


Thanks Scott! I really appreciate that you've taken some time to look into this!

The problem seems to be with nginx/uwsgi/werkzeug. This is my current
work around: https://gitlab.com/tvaughan/docker-nginx-proxy-uwsgi/commit/646a22f279e665a3114baa581b3ba2c7ebfc1ad1.
This simply sends the custom headers in the format expected by
werkzeug when it looks up the keys in self.environment.

This issue https://github.com/pallets/werkzeug/issues/940 appears to
be related. My problem isn't with the same header being provided more
than once, but rather this issue does say there is some condition
which causes werkzeug to not coerce header names. I still don't know
what that condition is. Note that in my workaround Host is OK as-is.
Perhaps the condition is simply the X- prefix? Still diggin'...

Thanks,
-Tom



On Thu, Jul 27, 2017 at 3:14 PM, Scott Werner <scott.werner.vt at gmail.com> wrote:
> Tom,
>
> Request headers key names are case-insensitive, so X-Real-Ip and X-REAL-IP
> would both work. I could not repeat your issue using Python 3.6:
>
> from flask import Flask, jsonify, request
>
> app = Flask(__name__)
>
> @app.route('/')
> def hello_world():
>     print(request.headers)
>     print(request.headers.get('Accept', 'No Accept'))
>     print(request.headers.get('X-Real-Ip', 'No X-Real-Ip'))
>     print(request.headers.get('X-REAL-IP', 'No X-Real-Ip'))
>     return jsonify(dict(request.headers))
>
> app.run()
>
>
> $ curl --header "X-Real-Ip: 8.8.8.8" http://127.0.0.1:5000/
> {
>   "Accept": "*/*",
>   "Host": "127.0.0.1:5000",
>   "User-Agent": "curl/7.54.1",
>   "X-Real-Ip": "8.8.8.8"
> }
>
>
> 127.0.0.1 - - [27/Jul/2017 15:12:18] "GET / HTTP/1.1" 200 -
> Host: 127.0.0.1:5000
> User-Agent: curl/7.54.1
> Accept: */*
> X-Real-Ip: 8.8.8.8
>
>
> */*
> 8.8.8.8
> 8.8.8.8
>
>
>
> On Thu, Jul 27, 2017 at 11:53 AM, Tom Vaughan
> <thomas.david.vaughan at gmail.com> wrote:
>>
>> On Thu, Jul 27, 2017 at 12:51 AM, Tom Vaughan
>> <thomas.david.vaughan at gmail.com> wrote:
>> > Hi,
>> >
>> > Why would this:
>> >
>> >     print(request.headers)
>> >     print(request.headers.get('Accept', 'No Accept'))
>> >     print(request.headers.get('X-Real-Ip', 'No X-Real-Ip'))
>> >
>> > cause this output:
>> >
>> >     Accept:
>> > text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
>> >     Connection: keep-alive
>> >     X-Real-Ip: 172.17.0.1
>> >     [...]
>> >
>> >     text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
>> >     No X-Real-Ip
>> >
>> > ?
>>
>> So the problem is:
>>
>>     File
>> "/usr/local/lib/python3.5/dist-packages/werkzeug/datastructures.py",
>> line 1349, in __getitem__
>>
>>         key = key.upper().replace('-', '_')
>>         if key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
>>             return _unicodify_header_value(self.environ[key])
>>         return _unicodify_header_value(self.environ['HTTP_' + key])
>>
>> The problem is that the custom header values (those that start with
>> X-) are not capitalized in self.environ, everything else is. For
>> example in self.environ, Accept exists as HTTP_ACCEPT, but X-Real-Ip
>> exists as HTTP_X_Real_IP. But why?
>> _______________________________________________
>> Flask mailing list
>> Flask at python.org
>> https://mail.python.org/mailman/listinfo/flask
>
>
>
>
> --
> Scott Werner
> scott.werner.vt at gmail.com


More information about the Flask mailing list