-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Port not provided in URLs produced with url_for
#1380
Comments
Thinking on this more last night, I can see the use case for things like Cloud Foundry deploys where the internal port being served would be obfuscated by the cloud instance, so the application should report Perhaps a flag then to enable port inclusion? |
Port 80 is the default port for HTTP and 443 is default for https, if the external URL is serving something like 'http://www.example.com/blah' then there's no real reason for port inclusion - however in every other case where the port is non-standard, I agree with your assessment that it should be included in the url. Possibly just inclusion of the port for the external uri should be enough. I'm sure one of the better devs will weigh in on it. |
Sorry, when I said "should report |
@eric-spitler I think I am understanding now ... You are asking for a setting for a "base URL" that would be used to create an absolute URL that is different than what is being exposed. For example, I have a sanic instance running as |
Consider the default use case, a simple app serving an endpoint that returns the result of from sanic.app import Sanic
from sanic.response import text
app = Sanic()
app.config.SERVER_NAME = 'localhost'
@app.route('/test', name='test', methods=['GET'])
def make_url(request):
return text(request.app.url_for('test', _external=True))
app.run() The application starts up on > curl http://127.0.0.1:8000/test
http://localhost/test Butting hitting the URL returned by > curl http://127.0.0.1/test
curl: (7) Failed connect to 127.0.0.1:80; Connection refused My point in this issue is that the URL generated by app.SERVER_NAME = 'localhost:8000' The more complex use case is where the application is running behind another interface, such as Cloud Foundry or AWS load balancers, in which case the developer must set As it stands, the developer must always set the following, but the documentation does not make that immediately apparent. app.SERVER_NAME = '{}:{}'.format(hostname, port)
app.run(host=hostname, port=port) I propose 2 possible updates:
The second bullet will support both the simple and complex use cases I spoke of. Default the value to Hopefully that makes more sense? Sorry if I was unclear before. |
Thanks for the explanation @eric-spitler. I certainly feel a documentation update is in order here. That makes sense. As for the flag, I am not opposed to having an |
I suggest not use |
@lixxu I don't understand your argument; _var indicates semiprivate which sanic honors - for more info. |
@lixxu I think the point @eric-spitler was making is that it should be configurable, and transparent. |
|
In that case, I think that having a One problem I see is that >>> from urllib.parse import urlunparse
>>> urlunparse(("https", "localhost", "/hello/world", "", "", ""))
'https://localhost/hello/world'
>>> urlunparse(("https", "localhost:443", "/hello/world", "", "", ""))
'https://localhost:443/hello/world'
>>> urlunparse(("http", "localhost:80", "/hello/world", "", "", ""))
'http://localhost:80/hello/world'
>>> urlunparse(("http", "localhost", "/hello/world", "", "", ""))
'http://localhost/hello/world' So, the thing is ...
[1] I don't think that any URL builder would strip the port value if one is given. |
I created a PR (#1406) for it. |
This is sorted out by #1638, which gets hostname and port always from the same location (proxy headers or if not found, Host header), and thus proper URLs may be generated via request.url_for which, contrary to app.url_for, has access to this data. No fallback to host/port specified at run, or SSL server name identifier / socket port, is needed because Host header is available in all normal circumstances, and it contains this information. app.url_for, which might be used at layout generation time or otherwise while the app is not yet running, can only rely on config.SERVER_NAME, which should contain the full URL to application root including any non-standard port number. @eric-spitler Do you believe that the current approach is sufficient? One shortcoming of this is that in order to use app.url_for, one must manually set Since app.url_for is likely used before app.run is called, any host/port passed to run is not available to it, and I cannot readily see any easy solution to this. |
That PR resolves this case for situations where the URL is being assembled from with a request context. However, it does not resolve it in other cases, such as another thread that is processing ongoing tasks unrelated to incoming requests. The latter use case is likely uncommon so this PR resolves a large percentage of these situations. So long as the I personally am okay with ensuring that the |
Describe the bug
The default port for a Sanic app is 8000, which by HTTP standards is a custom port. This port can also be set during calls to
app.run()
.When using
app.url_for('handler.name', _external=True)
, the resultant URL does not contain the port without manual intervention.This line is the final step before the application returns the URL. The URL is build using
urlunparse
which takes atuple
of values as would be producted by urlparse. The snippet below shows that only the first 6 arguments are provided, which does not include the port (unless included as part ofnetloc
).https://github.com/huge-success/sanic/blob/905c51bef03818c629173938a1183b38dd0ebc65/sanic/app.py#L695
In order to get port, the value of
app.confg.SERVER_NAME
must be set to the hostname and portThus, the default behavior for creating the URL is incorrect as it requires manual attribute setting for every single application.
Expected behavior
Calls to
app.url_for()
with the_external
flag should build the correct URL, including the port number, such ashttp://hostname:8000
without forcing every application to specify theSERVER_NAME
config attribute.Environment (please complete the following information):
The text was updated successfully, but these errors were encountered: