Repository: sanic-org/sanic

Issue:
url_for() doesn't return a working URI for a blueprint route with host
**Describe the bug**
When i use blueprints with `host` argument and try to get url with `url_for` i get an incorrect url - blueprint's host is used as a path, and not as a hostname

**Code snippet**

```python
from sanic import Sanic, Blueprint
from sanic.response import text

bp = Blueprint('bp_app', host='bp.example.com')


@bp.route('/', name='index')
async def bp_index(request):
    url = request.app.url_for('bp_app.index')
    return text(url)


@bp.route('/internal', name='internal')
async def bp_index(request):
    url = request.app.url_for('bp_app.internal')
    return text(url)


@bp.route('/external', name='external')
async def bp_index(request):
    url = request.app.url_for('bp_app.external', _external=True)
    return text(url)


app = Sanic('app_name')
app.blueprint(bp)


if __name__ == '__main__':
    app.run(port=8000)
```

Output

```console
# 1
$ curl -H "Host:bp.example.com" http://127.0.0.1:8000/
bp.example.com

# 2
$ curl -H "Host:bp.example.com" http://127.0.0.1:8000/internal
bp.example.com/internal

# 3
$ curl -H "Host:bp.example.com" http://127.0.0.1:8000/external
http:///bp.example.com/external
```

`1` example returns hostname by like a path
`2` example returns hostname and path but it's like a path
`3` example return full url, but with no hostname (3 slashes)

**Expected behavior**
I'm expecting correct urls.
For internal urls - only path returned as stated in route.
For external urls - fully qualified domain name with full path

`1` example - `/`
`2` example - `/internal`
`3` example - `http://bp.example.com/external`

**Environment (please complete the following information):**
 - OS: macOS
 - Version: 19.12.2

**Additional context**
Can't get correct place, but found some places, where it can be
[app.py#L829-L832](https://github.com/huge-success/sanic/blob/v19.12.2/sanic/app.py#L829-L832),
[app.py#L848](https://github.com/huge-success/sanic/blob/v19.12.2/sanic/app.py#L848) (perhaps, blueprint's host should be used, and config's server name as default)



Discussion:

Resolving patch:
diff --git a/sanic/app.py b/sanic/app.py
--- a/sanic/app.py
+++ b/sanic/app.py
@@ -830,6 +830,14 @@ def url_for(self, view_name: str, **kwargs):
                 "Endpoint with name `{}` was not found".format(view_name)
             )
 
+        # If the route has host defined, split that off
+        # TODO: Retain netloc and path separately in Route objects
+        host = uri.find("/")
+        if host > 0:
+            host, uri = uri[:host], uri[host:]
+        else:
+            host = None
+
         if view_name == "static" or view_name.endswith(".static"):
             filename = kwargs.pop("filename", None)
             # it's static folder
@@ -862,7 +870,7 @@ def url_for(self, view_name: str, **kwargs):
 
         netloc = kwargs.pop("_server", None)
         if netloc is None and external:
-            netloc = self.config.get("SERVER_NAME", "")
+            netloc = host or self.config.get("SERVER_NAME", "")
 
         if external:
             if not scheme:


Test patch:
diff --git a/tests/test_url_for.py b/tests/test_url_for.py
new file mode 100644
--- /dev/null
+++ b/tests/test_url_for.py
@@ -0,0 +1,12 @@
+def test_routes_with_host(app):
+    @app.route("/")
+    @app.route("/", name="hostindex", host="example.com")
+    @app.route("/path", name="hostpath", host="path.example.com")
+    def index(request):
+        pass
+
+    assert app.url_for("index") == "/"
+    assert app.url_for("hostindex") == "/"
+    assert app.url_for("hostpath") == "/path"
+    assert app.url_for("hostindex", _external=True) == "http://example.com/"
+    assert app.url_for("hostpath", _external=True) == "http://path.example.com/path"