pallets / flask

The Python micro framework for building web applications.
https://flask.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
67.55k stars 16.15k forks source link

Revisit SERVER_NAME's impact on routing and external URL generation #5553

Open rsyring opened 4 weeks ago

rsyring commented 4 weeks ago

998 was a discussion regarding the impact the SERVER_NAME setting has on an application. IMO, there was consensus in that issue, including by @mitsuhiko, that SERVER_NAME being used both in routing and in URL generation was problematic.

That issue was closed by https://github.com/pallets/flask/pull/2635, which made a change regarding subdomain matching. However, IMO, it did not address the fundamental problem of SERVER_NAME impacting two disparate mechanisms in Flask.

I found two additional issues since #998 that have attempted to point out the problem with SERVER_NAME: #2813, #3465

In #2813, a minimal, complete, and verifiable example was requested and I have therefore prepared an example gist that demonstrates the problem.

The gist's third "currently impossible" test demonstrates that it's currently impossible to:

My particular use case currently is that I need SERVER_NAME set so external URLs will be created accurately in distributed tasks where no web request is present. Additionally, I need the app to respond to multiple host names 1) the canonical URL the public uses; and 2) the IP address based URL our load balancer uses for health checks.

IMO, SERVER_NAME should be deprecated and two new settings should be created. One which affects external URL generation and a second that affects routing resolution.

The setting for the URL generation could be CANONICAL_URL and, because its a URL, it could eliminate the need for url_for()'s _scheme arg.

Thanks for your consideration.

davidism commented 4 weeks ago

We should expose Werkzeug's trusted host checking, with a new ALLOWED_HOSTS = [] config to match Django's. This is similar to what we recently did for the dev server debugger.

I don't think we need to deprecate SERVER_NAME. If it's set, it's added to ALLOWED_HOSTS, otherwise behavior stays the same.

it could eliminate the need for url_for()'s _scheme arg.

This is already covered by PREFERRED_URL_SCHEME. If we were to deprecate SERVER_NAME, I'd rename it to PREFERRED_URL_HOST or something, but I think it's fine to leave it.

rsyring commented 4 weeks ago

David, thanks for chiming in.

I think SERVER_NAME still remains problematic:

  1. SERVER_NAME still affects two disparate parts of the system. If all I want to do is configure the external URL used by url_for(), I can't do that without affecting routing or host checking. I should be able to set them separately. This becomes a practical problem in the case of...
  2. What if I don't know all of the hosts that I want to allow? Maybe I'm serving up marketing content on multiple domains and non-technical people are creating names for SSO reasons. Maybe, as is my case, the load balancer is going to use different IPs every time I deploy the app (aws copilot/cloud formation). Or, if I have multiple processes/containers running, there will be multiple IPs that need to be valid but I don't know what they are.

Django doesn't seem to handle the unkown IP case natively: SO discussion and https://pypi.org/project/django-allow-cidr/

I don't know much about how Flask handles subodmains but noting it here in case it should impact the discussion.

Thanks.