Skip to content

environ["SERVER_PORT"] can't be "None" #1468

Closed

Description

@abersheeran

Checklist

  • The bug is reproducible against the latest release and/or master.
  • There are no similar issues or pull requests to fix it yet.

Describe the bug

abersheeran/a2wsgi#8

=================================== FAILURES ===================================
____________ test_convert_asgi_to_wsgi[app1-a2wsgi-ASGIMiddleware] _____________

app = <a2wsgi.asgi.ASGIMiddleware object at 0x7fced147eb80>
name = 'a2wsgi-ASGIMiddleware'

    @pytest.mark.parametrize(
        "app, name",
        [(wsgi_echo, "pure-WSGI"), (ASGIMiddleware(asgi_echo), "a2wsgi-ASGIMiddleware")],
    )
    def test_convert_asgi_to_wsgi(app, name):
        with httpx.Client(app=app, base_url="http://testserver") as client:
            start_time = time.time_ns()
            for _ in range(100):
>               client.post("/", data=b"hello world")

a2wsgi/benchmark.py:99:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/local/lib/python3.8/site-packages/httpx/_client.py:992: in post
    return self.request(
/usr/local/lib/python3.8/site-packages/httpx/_client.py:733: in request
    return self.send(
/usr/local/lib/python3.8/site-packages/httpx/_client.py:767: in send
    response = self._send_handling_auth(
/usr/local/lib/python3.8/site-packages/httpx/_client.py:805: in _send_handling_auth
    response = self._send_handling_redirects(
/usr/local/lib/python3.8/site-packages/httpx/_client.py:837: in _send_handling_redirects
    response = self._send_single_request(request, timeout)
/usr/local/lib/python3.8/site-packages/httpx/_client.py:861: in _send_single_request
    (status_code, headers, stream, ext) = transport.request(
/usr/local/lib/python3.8/site-packages/httpx/_transports/wsgi.py:113: in request
    result = _skip_leading_empty_chunks(result)
/usr/local/lib/python3.8/site-packages/httpx/_transports/wsgi.py:10: in _skip_leading_empty_chunks
    for chunk in body:
a2wsgi/a2wsgi/asgi.py:160: in __call__
    self.app(build_scope(environ), self.asgi_receive, self.asgi_send)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

environ = {'CONTENT_LENGTH': '11', 'HTTP_ACCEPT': '*/*', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_CONNECTION': 'keep-alive', ...}

    def build_scope(environ: Environ) -> Scope:
        headers = [
            (
                each[5:].lower().replace("_", "-").encode("latin1"),
                environ[each].encode("latin1"),
            )
            for each in environ.keys()
            if each.startswith("HTTP_")
        ]
        if environ.get("CONTENT_TYPE"):
            headers.append((b"content-type", environ["CONTENT_TYPE"].encode("latin1")))
        if environ.get("CONTENT_LENGTH"):
            headers.append((b"content-length", environ["CONTENT_LENGTH"].encode("latin1")))

        if environ.get("REMOTE_ADDR") and environ.get("REMOTE_PORT"):
            client = (environ.get("REMOTE_ADDR"), int(environ.get("REMOTE_PORT")))
        else:
            client = None

        return {
            "type": "http",
            "asgi": {"version": "3.0", "spec_version": "3.0"},
            "http_version": environ.get("SERVER_PROTOCOL", "http/1.0").split("/")[1],
            "method": environ["REQUEST_METHOD"],
            "scheme": environ.get("wsgi.url_scheme", "http"),
            "path": environ["PATH_INFO"].encode("latin1").decode("utf8"),
            "query_string": environ["QUERY_STRING"].encode("ascii"),
            "root_path": environ.get("SCRIPT_NAME", "").encode("latin1").decode("utf8"),
            "client": client,
>           "server": (environ["SERVER_NAME"], int(environ["SERVER_PORT"])),
            "headers": headers,
        }
E       ValueError: invalid literal for int() with base 10: 'None'

a2wsgi/a2wsgi/asgi.py:94: ValueError
=========================== short test summary info ============================
FAILED a2wsgi/benchmark.py::test_convert_asgi_to_wsgi[app1-a2wsgi-ASGIMiddleware]
==================== 1 failed, 5 passed in 95.47s (0:01:35) ====================

Expected behavior

https://www.python.org/dev/peps/pep-3333/#environ-variables

SERVER_PORT must be a valid integer value for URL splicing. In the WSGI application test, it may not have a real value, but we should give a default value, such as 80.

Activity

  1. florimondmanca commented on Feb 16, 2021

    @florimondmanca
    Contributor

    @abersheeran Good catch!

    Indeed, in WSGITransport the url is unpacked as scheme, host, port, full_path, and port is an Optional[int], obtained from here:

    httpx/httpx/_models.py

    Lines 208 to 214 in 8696405

    @property
    def port(self) -> typing.Optional[int]:
    """
    The URL port as an integer.
    """
    port = self._uri_reference.port
    return int(port) if port else None

    So we need to handle the "default port" case in WSGITransport.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions