Skip to content
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

Fix server not running with explicit hostname #827

Merged
merged 3 commits into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ def install_signal_handlers(self):
thread.join()


def test_run_hostname():
class App:
def __init__(self, scope):
if scope["type"] != "http":
raise Exception()

async def __call__(self, receive, send):
await send({"type": "http.response.start", "status": 204, "headers": []})
await send({"type": "http.response.body", "body": b"", "more_body": False})

class CustomServer(Server):
def install_signal_handlers(self):
pass

config = Config(app=App, host="localhost", loop="asyncio", limit_max_requests=1)
server = CustomServer(config=config)
thread = threading.Thread(target=server.run)
thread.start()
while not server.started:
time.sleep(0.01)
response = requests.get("http://localhost:8000")
assert response.status_code == 204
thread.join()


def test_run_multiprocess():
class App:
def __init__(self, scope):
Expand Down
16 changes: 4 additions & 12 deletions uvicorn/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import socket
import ssl
import sys
from enum import Enum
from typing import List, Tuple

import click
Expand Down Expand Up @@ -116,15 +115,8 @@ def create_ssl_context(
return ctx


class _IPKind(Enum):
IPv4 = "IPv4"
IPv6 = "IPv6"


def _get_server_start_message(
host_ip_version: _IPKind = _IPKind.IPv4,
) -> Tuple[str, str]:
if host_ip_version is _IPKind.IPv6:
def _get_server_start_message(is_ipv6_message: bool = False) -> Tuple[str, str]:
if is_ipv6_message:
ip_repr = "%s://[%s]:%d"
else:
ip_repr = "%s://%s:%d"
Expand Down Expand Up @@ -376,9 +368,9 @@ def bind_socket(self):
sock.set_inheritable(True)

if family == socket.AddressFamily.AF_INET6:
message, color_message = _get_server_start_message(_IPKind.IPv6)
message, color_message = _get_server_start_message(is_ipv6_message=True)
else:
message, color_message = _get_server_start_message(_IPKind.IPv4)
message, color_message = _get_server_start_message()
protocol_name = "https" if self.is_ssl else "http"
logger.info(
message,
Expand Down
17 changes: 11 additions & 6 deletions uvicorn/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import time
import typing
from email.utils import formatdate
from ipaddress import IPv6Address, ip_address
from ipaddress import IPv4Address, IPv6Address, ip_address

import click

Expand All @@ -26,7 +26,6 @@
WS_PROTOCOLS,
Config,
_get_server_start_message,
_IPKind,
)
from uvicorn.supervisors import ChangeReload, Multiprocess

Expand Down Expand Up @@ -523,10 +522,16 @@ def _share_socket(sock: socket) -> socket:
if port == 0:
port = server.sockets[0].getsockname()[1]
protocol_name = "https" if config.ssl else "http"
if isinstance(ip_address(config.host), IPv6Address):
message, color_message = _get_server_start_message(_IPKind.IPv6)
else:
message, color_message = _get_server_start_message(_IPKind.IPv4)
try:
addr = ip_address(config.host)
Copy link
Member

@cdeler cdeler Oct 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you cannot omit this try-except block (or to replace it by regex)

Another approach to check if it's an ip or hostname is to:

socket.getaddrinfo(config.host, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST)

But it's also should be wrapped by try-except statement

if isinstance(addr, IPv6Address):
message, color_message = _get_server_start_message(
is_ipv6_message=True
)
elif isinstance(addr, IPv4Address):
message, color_message = _get_server_start_message()
except ValueError:
message, color_message = _get_server_start_message()

logger.info(
message,
Expand Down