Werkzeug: TypeError in BaseRequest.trusted_hosts when a host name starts with a '.'

Created on 11 Dec 2017  ·  1Comment  ·  Source: pallets/werkzeug

Adding a host name starting with . to wrappers.BaseRequest.trusted_hosts results in TypeError: must be str, not bytes (Python 3.6) or TypeError: Can't convert 'bytes' object to str implicitly (Python 3.4), as in werkzeug.wsgi.host_is_trusted, _normalize first calls _encode_idna, which encodes the ref to bytes and then if it start with '.', it is concatenated with the '.', thus mixing str and bytes.

Sample App

from flask import Flask, request

class TrustedHosts:
    """Flask extension setting `werkzeug.wrappers.BaseRequest.trusted_hosts`."""
    def __init__(self, app=None, trusted_hosts=None):
        self.app = app
        self.trusted_hosts = trusted_hosts
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.before_request(self.set_trusted_hosts)

    def set_trusted_hosts(self):
        # As host is a @cached_property this should before its first access.
        request.trusted_hosts = self.trusted_hosts
        print(request.host)

app = Flask(__name__)
TrustedHosts(app, trusted_hosts=['.example.com'])

@app.route('/')
def index():
    return 'OK'

Full Stack Trace

Traceback (most recent call last):
  File "c:\program files\python36\lib\site-packages\flask\app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "c:\program files\python36\lib\site-packages\flask\app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "c:\program files\python36\lib\site-packages\flask\app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "c:\program files\python36\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "c:\program files\python36\lib\site-packages\flask\app.py", line 1610, in full_dispatch_request
    rv = self.preprocess_request()
  File "c:\program files\python36\lib\site-packages\flask\app.py", line 1831, in preprocess_request
    rv = func()
  File "D:\Dropbox\p\kb\python\web\flask\trusted_hosts.py", line 17, in set_trusted_hosts
    print(request.host)
  File "c:\program files\python36\lib\site-packages\werkzeug\local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "c:\program files\python36\lib\site-packages\werkzeug\utils.py", line 73, in __get__
    value = self.func(obj)
  File "c:\program files\python36\lib\site-packages\werkzeug\wrappers.py", line 635, in host
    return get_host(self.environ, trusted_hosts=self.trusted_hosts)
  File "c:\program files\python36\lib\site-packages\werkzeug\wsgi.py", line 160, in get_host
    if not host_is_trusted(rv, trusted_hosts):
  File "c:\program files\python36\lib\site-packages\werkzeug\wsgi.py", line 132, in host_is_trusted
    if suffix_match and hostname.endswith('.' + ref):
TypeError: must be str, not bytes
127.0.0.1 - - [11/Dec/2017 17:11:18] "GET / HTTP/1.1" 500 -

Most helpful comment

A side note, a before_request handler that does this every request is inefficient. Subclass Request, set the attribute, assign the class to the app.

from flask.wrappers import Request

class TrustedRequest(Request):
    trusted_hosts = ['a', 'b', 'c']

app.request_class = TrustedRequest

>All comments

A side note, a before_request handler that does this every request is inefficient. Subclass Request, set the attribute, assign the class to the app.

from flask.wrappers import Request

class TrustedRequest(Request):
    trusted_hosts = ['a', 'b', 'c']

app.request_class = TrustedRequest
Was this page helpful?
0 / 5 - 0 ratings

Related issues

paihu picture paihu  ·  7Comments

masklinn picture masklinn  ·  11Comments

SimonSapin picture SimonSapin  ·  12Comments

Nessphoro picture Nessphoro  ·  6Comments

androiddrew picture androiddrew  ·  14Comments