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

environ["SERVER_PORT"] could be "None" #8

Closed
CoolSpring8 opened this issue Feb 15, 2021 · 8 comments
Closed

environ["SERVER_PORT"] could be "None" #8

CoolSpring8 opened this issue Feb 15, 2021 · 8 comments

Comments

@CoolSpring8
Copy link

The benchmark appears to be broken in my test, which reports an ValueError caused by trying to convert "None" to int.
(Also reproduced in a cleanly installed Docker container. )

The error message:

=================================== 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) ====================

After some investigation, I found out that the port property in httpx.URL changed its behavior in encode/httpx@c089480#diff-c9a78eb3b5f5c4fac4e5552165fbdd5320c7e3fadf9eedabcb5461393466c090L107-R110.

So a simple fix might be adding conditional statements for SERVER_PORT and url_scheme.

@CoolSpring8
Copy link
Author

Just noticed tests were changed in e2a7bfd... So should the line in benchmark.py also add :80, or to change asgi.py like in the present PR?

@abersheeran
Copy link
Owner

https://www.python.org/dev/peps/pep-3333/#environ-variables In the WSGI standard, SERVER_PORT is a required value.

This is a problem with the old version of httpx you are using, not a2wsgi. Please upgrade the httpx version to the latest 0.16 and run the script again.

@CoolSpring8
Copy link
Author

https://www.python.org/dev/peps/pep-3333/#environ-variables In the WSGI standard, SERVER_PORT is a required value.

This is a problem with the old version of httpx you are using, not a2wsgi. Please upgrade the httpx version to the latest 0.16 and run the script again.

Sorry, it is indeed not a bug on a2wsgi side.

But I was actually using httpx 0.16.1:

$ pip3 show httpx | grep Version
Version: 0.16.1

And I could not find in which commit httpx fixed the problem you mentioned. Could you please kindly point it out?

@abersheeran
Copy link
Owner

You can see this line https://github.com/encode/httpx/blob/0.16.1/httpx/_models.py#L121. The port should be automatically completed by another library. If httpx 0.16 does not work properly in your environment, please check the version of rfc3986.

@abersheeran
Copy link
Owner

By the way, you can try the library version specified in poetry.lock. It should be able to pass all test cases.

@abersheeran
Copy link
Owner

I'm sorry, I just tried running this script. But found the same error as you. Maybe it's that after upgrading httpx some time in the past, I never tried to run it again. This is a problem with httpx. I will submit a PR for httpx to fix this error. Thanks for your feedback.

@abersheeran
Copy link
Owner

encode/httpx#1469 Done.

@CoolSpring8
Copy link
Author

Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants