prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Improper handling of Punycode
  #### Problem Description
  Can't open an address like `https://стопкоронавирус.рф/` through `mitmproxy` or other applications. My upstream proxy receives a CONNECT request to https://СЃС‚РѕРїРєРѕСЂРѕРЅР°РІРёСЂСѓСЃ.СЂС„:443 instead. As the current run of `mitmproxy` was supposed to be just a test, it was configured only to forward all requests as-is to the upstream proxy, so this rules out any and all issues that could arise from my tinkering. Note: the actual URL that the browser opens is `https://xn--80aesfpebagmfblc0a.xn--p1ai` in this case.
  
  Did it fail to properly encode the resulting authority? My upstream proxy normally has no issues with opening Puny-encoded URLs. I can verify that by opening that URL bypassing `mitmproxy`. It looks like it uses the wrong encoding, as it reminds me of the time when Unicode was not widespread and so this is how text in Russian would display when the text encoding wasn't set correctly.
  
  #### Steps to reproduce the behavior:
  1. Configure `mitmproxy` to forward all requests as-is to the upstream proxy that optionally can report what requests it receives. This includes no HTTPS decryption.
  2. Navigate your browser to `https://стопкоронавирус.рф/`.
  3. Check what the authority part of the URL the upstream proxy gets, it should be mangled.
  
  #### System Information
  Paste the output of "mitmproxy --version" here.
  
  ```Mitmproxy: 8.0.0 binary
  Python:    3.10.2
  OpenSSL:   OpenSSL 1.1.1n  15 Mar 2022
  Platform:  Windows-10-10.0.19043-SP0
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `mitmproxy/proxy/layers/http/_upstream_proxy.py`
  Content:
  ```
  1 import time
  2 from typing import Optional
  3 
  4 from h11._receivebuffer import ReceiveBuffer
  5 
  6 from mitmproxy import http, connection
  7 from mitmproxy.net.http import http1
  8 from mitmproxy.proxy import commands, context, layer, tunnel
  9 from mitmproxy.proxy.layers.http._hooks import HttpConnectUpstreamHook
  10 from mitmproxy.proxy.layers import tls
  11 from mitmproxy.utils import human
  12 
  13 
  14 class HttpUpstreamProxy(tunnel.TunnelLayer):
  15     buf: ReceiveBuffer
  16     send_connect: bool
  17     conn: connection.Server
  18     tunnel_connection: connection.Server
  19 
  20     def __init__(
  21         self, ctx: context.Context, tunnel_conn: connection.Server, send_connect: bool
  22     ):
  23         super().__init__(ctx, tunnel_connection=tunnel_conn, conn=ctx.server)
  24         self.buf = ReceiveBuffer()
  25         self.send_connect = send_connect
  26 
  27     @classmethod
  28     def make(cls, ctx: context.Context, send_connect: bool) -> tunnel.LayerStack:
  29         spec = ctx.server.via
  30         assert spec
  31         assert spec.scheme in ("http", "https")
  32 
  33         http_proxy = connection.Server(spec.address)
  34 
  35         stack = tunnel.LayerStack()
  36         if spec.scheme == "https":
  37             http_proxy.alpn_offers = tls.HTTP1_ALPNS
  38             http_proxy.sni = spec.address[0]
  39             stack /= tls.ServerTLSLayer(ctx, http_proxy)
  40         stack /= cls(ctx, http_proxy, send_connect)
  41 
  42         return stack
  43 
  44     def start_handshake(self) -> layer.CommandGenerator[None]:
  45         if not self.send_connect:
  46             return (yield from super().start_handshake())
  47         assert self.conn.address
  48         flow = http.HTTPFlow(self.context.client, self.tunnel_connection)
  49         flow.request = http.Request(
  50             host=self.conn.address[0],
  51             port=self.conn.address[1],
  52             method=b"CONNECT",
  53             scheme=b"",
  54             authority=f"{self.conn.address[0]}:{self.conn.address[1]}".encode(),
  55             path=b"",
  56             http_version=b"HTTP/1.1",
  57             headers=http.Headers(),
  58             content=b"",
  59             trailers=None,
  60             timestamp_start=time.time(),
  61             timestamp_end=time.time(),
  62         )
  63         yield HttpConnectUpstreamHook(flow)
  64         raw = http1.assemble_request(flow.request)
  65         yield commands.SendData(self.tunnel_connection, raw)
  66 
  67     def receive_handshake_data(
  68         self, data: bytes
  69     ) -> layer.CommandGenerator[tuple[bool, Optional[str]]]:
  70         if not self.send_connect:
  71             return (yield from super().receive_handshake_data(data))
  72         self.buf += data
  73         response_head = self.buf.maybe_extract_lines()
  74         if response_head:
  75             response_head = [
  76                 bytes(x) for x in response_head
  77             ]  # TODO: Make url.parse compatible with bytearrays
  78             try:
  79                 response = http1.read_response_head(response_head)
  80             except ValueError as e:
  81                 proxyaddr = human.format_address(self.tunnel_connection.address)
  82                 yield commands.Log(f"{proxyaddr}: {e}")
  83                 return False, f"Error connecting to {proxyaddr}: {e}"
  84             if 200 <= response.status_code < 300:
  85                 if self.buf:
  86                     yield from self.receive_data(bytes(self.buf))
  87                     del self.buf
  88                 return True, None
  89             else:
  90                 proxyaddr = human.format_address(self.tunnel_connection.address)
  91                 raw_resp = b"\n".join(response_head)
  92                 yield commands.Log(f"{proxyaddr}: {raw_resp!r}", level="debug")
  93                 return (
  94                     False,
  95                     f"Upstream proxy {proxyaddr} refused HTTP CONNECT request: {response.status_code} {response.reason}",
  96                 )
  97         else:
  98             return False, None
  99
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/mitmproxy/proxy/layers/http/_upstream_proxy.py b/mitmproxy/proxy/layers/http/_upstream_proxy.py
  --- a/mitmproxy/proxy/layers/http/_upstream_proxy.py
  +++ b/mitmproxy/proxy/layers/http/_upstream_proxy.py
  @@ -46,12 +46,13 @@
               return (yield from super().start_handshake())
           assert self.conn.address
           flow = http.HTTPFlow(self.context.client, self.tunnel_connection)
  +        authority = self.conn.address[0].encode("idna") + f":{self.conn.address[1]}".encode()
           flow.request = http.Request(
               host=self.conn.address[0],
               port=self.conn.address[1],
               method=b"CONNECT",
               scheme=b"",
  -            authority=f"{self.conn.address[0]}:{self.conn.address[1]}".encode(),
  +            authority=authority,
               path=b"",
               http_version=b"HTTP/1.1",
               headers=http.Headers(),
  
verification_info: {"golden_diff": "diff --git a/mitmproxy/proxy/layers/http/_upstream_proxy.py b/mitmproxy/proxy/layers/http/_upstream_proxy.py\n--- a/mitmproxy/proxy/layers/http/_upstream_proxy.py\n+++ b/mitmproxy/proxy/layers/http/_upstream_proxy.py\n@@ -46,12 +46,13 @@\n             return (yield from super().start_handshake())\n         assert self.conn.address\n         flow = http.HTTPFlow(self.context.client, self.tunnel_connection)\n+        authority = self.conn.address[0].encode(\"idna\") + f\":{self.conn.address[1]}\".encode()\n         flow.request = http.Request(\n             host=self.conn.address[0],\n             port=self.conn.address[1],\n             method=b\"CONNECT\",\n             scheme=b\"\",\n-            authority=f\"{self.conn.address[0]}:{self.conn.address[1]}\".encode(),\n+            authority=authority,\n             path=b\"\",\n             http_version=b\"HTTP/1.1\",\n             headers=http.Headers(),\n", "issue": "Improper handling of Punycode\n#### Problem Description\r\nCan't open an address like `https://\u0441\u0442\u043e\u043f\u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441.\u0440\u0444/` through `mitmproxy` or other applications. My upstream proxy receives a CONNECT request to https://\u0421\u0403\u0421\u201a\u0420\u0455\u0420\u0457\u0420\u0454\u0420\u0455\u0421\u0402\u0420\u0455\u0420\u0405\u0420\u00b0\u0420\u0406\u0420\u0451\u0421\u0402\u0421\u0453\u0421\u0403.\u0421\u0402\u0421\u201e:443 instead. As the current run of `mitmproxy` was supposed to be just a test, it was configured only to forward all requests as-is to the upstream proxy, so this rules out any and all issues that could arise from my tinkering. Note: the actual URL that the browser opens is `https://xn--80aesfpebagmfblc0a.xn--p1ai` in this case.\r\n\r\nDid it fail to properly encode the resulting authority? My upstream proxy normally has no issues with opening Puny-encoded URLs. I can verify that by opening that URL bypassing `mitmproxy`. It looks like it uses the wrong encoding, as it reminds me of the time when Unicode was not widespread and so this is how text in Russian would display when the text encoding wasn't set correctly.\r\n\r\n#### Steps to reproduce the behavior:\r\n1. Configure `mitmproxy` to forward all requests as-is to the upstream proxy that optionally can report what requests it receives. This includes no HTTPS decryption.\r\n2. Navigate your browser to `https://\u0441\u0442\u043e\u043f\u043a\u043e\u0440\u043e\u043d\u0430\u0432\u0438\u0440\u0443\u0441.\u0440\u0444/`.\r\n3. Check what the authority part of the URL the upstream proxy gets, it should be mangled.\r\n\r\n#### System Information\r\nPaste the output of \"mitmproxy --version\" here.\r\n\r\n```Mitmproxy: 8.0.0 binary\r\nPython:    3.10.2\r\nOpenSSL:   OpenSSL 1.1.1n  15 Mar 2022\r\nPlatform:  Windows-10-10.0.19043-SP0\r\n```\n", "before_files": [{"content": "import time\nfrom typing import Optional\n\nfrom h11._receivebuffer import ReceiveBuffer\n\nfrom mitmproxy import http, connection\nfrom mitmproxy.net.http import http1\nfrom mitmproxy.proxy import commands, context, layer, tunnel\nfrom mitmproxy.proxy.layers.http._hooks import HttpConnectUpstreamHook\nfrom mitmproxy.proxy.layers import tls\nfrom mitmproxy.utils import human\n\n\nclass HttpUpstreamProxy(tunnel.TunnelLayer):\n    buf: ReceiveBuffer\n    send_connect: bool\n    conn: connection.Server\n    tunnel_connection: connection.Server\n\n    def __init__(\n        self, ctx: context.Context, tunnel_conn: connection.Server, send_connect: bool\n    ):\n        super().__init__(ctx, tunnel_connection=tunnel_conn, conn=ctx.server)\n        self.buf = ReceiveBuffer()\n        self.send_connect = send_connect\n\n    @classmethod\n    def make(cls, ctx: context.Context, send_connect: bool) -> tunnel.LayerStack:\n        spec = ctx.server.via\n        assert spec\n        assert spec.scheme in (\"http\", \"https\")\n\n        http_proxy = connection.Server(spec.address)\n\n        stack = tunnel.LayerStack()\n        if spec.scheme == \"https\":\n            http_proxy.alpn_offers = tls.HTTP1_ALPNS\n            http_proxy.sni = spec.address[0]\n            stack /= tls.ServerTLSLayer(ctx, http_proxy)\n        stack /= cls(ctx, http_proxy, send_connect)\n\n        return stack\n\n    def start_handshake(self) -> layer.CommandGenerator[None]:\n        if not self.send_connect:\n            return (yield from super().start_handshake())\n        assert self.conn.address\n        flow = http.HTTPFlow(self.context.client, self.tunnel_connection)\n        flow.request = http.Request(\n            host=self.conn.address[0],\n            port=self.conn.address[1],\n            method=b\"CONNECT\",\n            scheme=b\"\",\n            authority=f\"{self.conn.address[0]}:{self.conn.address[1]}\".encode(),\n            path=b\"\",\n            http_version=b\"HTTP/1.1\",\n            headers=http.Headers(),\n            content=b\"\",\n            trailers=None,\n            timestamp_start=time.time(),\n            timestamp_end=time.time(),\n        )\n        yield HttpConnectUpstreamHook(flow)\n        raw = http1.assemble_request(flow.request)\n        yield commands.SendData(self.tunnel_connection, raw)\n\n    def receive_handshake_data(\n        self, data: bytes\n    ) -> layer.CommandGenerator[tuple[bool, Optional[str]]]:\n        if not self.send_connect:\n            return (yield from super().receive_handshake_data(data))\n        self.buf += data\n        response_head = self.buf.maybe_extract_lines()\n        if response_head:\n            response_head = [\n                bytes(x) for x in response_head\n            ]  # TODO: Make url.parse compatible with bytearrays\n            try:\n                response = http1.read_response_head(response_head)\n            except ValueError as e:\n                proxyaddr = human.format_address(self.tunnel_connection.address)\n                yield commands.Log(f\"{proxyaddr}: {e}\")\n                return False, f\"Error connecting to {proxyaddr}: {e}\"\n            if 200 <= response.status_code < 300:\n                if self.buf:\n                    yield from self.receive_data(bytes(self.buf))\n                    del self.buf\n                return True, None\n            else:\n                proxyaddr = human.format_address(self.tunnel_connection.address)\n                raw_resp = b\"\\n\".join(response_head)\n                yield commands.Log(f\"{proxyaddr}: {raw_resp!r}\", level=\"debug\")\n                return (\n                    False,\n                    f\"Upstream proxy {proxyaddr} refused HTTP CONNECT request: {response.status_code} {response.reason}\",\n                )\n        else:\n            return False, None\n", "path": "mitmproxy/proxy/layers/http/_upstream_proxy.py"}], "after_files": [{"content": "import time\nfrom typing import Optional\n\nfrom h11._receivebuffer import ReceiveBuffer\n\nfrom mitmproxy import http, connection\nfrom mitmproxy.net.http import http1\nfrom mitmproxy.proxy import commands, context, layer, tunnel\nfrom mitmproxy.proxy.layers.http._hooks import HttpConnectUpstreamHook\nfrom mitmproxy.proxy.layers import tls\nfrom mitmproxy.utils import human\n\n\nclass HttpUpstreamProxy(tunnel.TunnelLayer):\n    buf: ReceiveBuffer\n    send_connect: bool\n    conn: connection.Server\n    tunnel_connection: connection.Server\n\n    def __init__(\n        self, ctx: context.Context, tunnel_conn: connection.Server, send_connect: bool\n    ):\n        super().__init__(ctx, tunnel_connection=tunnel_conn, conn=ctx.server)\n        self.buf = ReceiveBuffer()\n        self.send_connect = send_connect\n\n    @classmethod\n    def make(cls, ctx: context.Context, send_connect: bool) -> tunnel.LayerStack:\n        spec = ctx.server.via\n        assert spec\n        assert spec.scheme in (\"http\", \"https\")\n\n        http_proxy = connection.Server(spec.address)\n\n        stack = tunnel.LayerStack()\n        if spec.scheme == \"https\":\n            http_proxy.alpn_offers = tls.HTTP1_ALPNS\n            http_proxy.sni = spec.address[0]\n            stack /= tls.ServerTLSLayer(ctx, http_proxy)\n        stack /= cls(ctx, http_proxy, send_connect)\n\n        return stack\n\n    def start_handshake(self) -> layer.CommandGenerator[None]:\n        if not self.send_connect:\n            return (yield from super().start_handshake())\n        assert self.conn.address\n        flow = http.HTTPFlow(self.context.client, self.tunnel_connection)\n        authority = self.conn.address[0].encode(\"idna\") + f\":{self.conn.address[1]}\".encode()\n        flow.request = http.Request(\n            host=self.conn.address[0],\n            port=self.conn.address[1],\n            method=b\"CONNECT\",\n            scheme=b\"\",\n            authority=authority,\n            path=b\"\",\n            http_version=b\"HTTP/1.1\",\n            headers=http.Headers(),\n            content=b\"\",\n            trailers=None,\n            timestamp_start=time.time(),\n            timestamp_end=time.time(),\n        )\n        yield HttpConnectUpstreamHook(flow)\n        raw = http1.assemble_request(flow.request)\n        yield commands.SendData(self.tunnel_connection, raw)\n\n    def receive_handshake_data(\n        self, data: bytes\n    ) -> layer.CommandGenerator[tuple[bool, Optional[str]]]:\n        if not self.send_connect:\n            return (yield from super().receive_handshake_data(data))\n        self.buf += data\n        response_head = self.buf.maybe_extract_lines()\n        if response_head:\n            response_head = [\n                bytes(x) for x in response_head\n            ]  # TODO: Make url.parse compatible with bytearrays\n            try:\n                response = http1.read_response_head(response_head)\n            except ValueError as e:\n                proxyaddr = human.format_address(self.tunnel_connection.address)\n                yield commands.Log(f\"{proxyaddr}: {e}\")\n                return False, f\"Error connecting to {proxyaddr}: {e}\"\n            if 200 <= response.status_code < 300:\n                if self.buf:\n                    yield from self.receive_data(bytes(self.buf))\n                    del self.buf\n                return True, None\n            else:\n                proxyaddr = human.format_address(self.tunnel_connection.address)\n                raw_resp = b\"\\n\".join(response_head)\n                yield commands.Log(f\"{proxyaddr}: {raw_resp!r}\", level=\"debug\")\n                return (\n                    False,\n                    f\"Upstream proxy {proxyaddr} refused HTTP CONNECT request: {response.status_code} {response.reason}\",\n                )\n        else:\n            return False, None\n", "path": "mitmproxy/proxy/layers/http/_upstream_proxy.py"}]}