Repository: pallets/werkzeug

Issue:
can't serve on unix socket if directory starts with `.`
I have a strange problem that I can reproduce on werkzeug 2.2.3 and cannot reproduce on werkzeug 2.2.2. 

I'm trying to `flask run --host=unix://.path/to/socket` in development mode (so that I can front the server with an authenticating reverse proxy). This used to work and no longer does on 2.2.3.

With 2.2.3, when I run flask, I get a crash that looks like this (sorry that it's a screenshot instead of text, I'm working in an odd environment):

![image](https://user-images.githubusercontent.com/46406/220500072-732359a2-153c-44c1-a738-85278e09eb5e.png)

With 2.2.2, it just runs fine.

This seems to happen only when the argument to `--host` is a unix domain socket that starts with a `.` character, like what happens if your environment lives in the `.nox` directory. For example, `flask run --host=unix://.nox/dev/tmp/flask.sock`.

You ought to be able to reproduce this with the minimal flask application:

```python
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "<p>is it me you're looking for?</p>"
```

Then:

```bash
python -m venv venv
source venv/bin/activate
pip install flask werkzeug==2.2.3
mkdir -p .nox
socat TCP-LISTEN:6789 UNIX-CONNECT:.nox/test &
flask run --host=unix://.nox/test
```

This should produce a crash. After that:

```bash
pip install werkzeug==2.2.2
socat TCP-LISTEN:6789 UNIX-CONNECT:.nox/test &
flask run --host=unix://.nox/test
```

This should work.

I have a medium hunch that this has something to do with #2517, just because that's where most of the changes between 2.2.2 and 2.2.3 happened in `werkzeug/serving.py`. But I have no idea why they exhibit this behavior change.

Environment:

- Python version: 3.10
- Werkzeug version: 2.2.3



Discussion:
I should add, I dropped a print just before https://github.com/python/cpython/blob/v3.10.10/Lib/socket.py#L793 and `name` is the string `.` in my reproduction of the problem.
This actually looks like an issue with Python, not Werkzeug. `http.server` is calling `socket.getfqdn()`, which wants to decode the URL from IDNA to ASCII, but that only makes sense for hosts, not for unix socket paths. `http.server` doesn't support Unix sockets, that's something we added on top, but we can't get in at the place this is happening to prevent it. You should try to report this to Python, or even ask for/implement Unix support in `http.server`.

I think we could always convert a Unix socket to an absolute path, that should never start with a `.`.
Interesting. I should be able to convert everything to absolute paths, thanks. I suppose the fact that it worked before was mostly an accident. I'll think about what to try to do in `http.server`.

Resolving patch:
diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py
--- a/src/werkzeug/serving.py
+++ b/src/werkzeug/serving.py
@@ -620,7 +620,8 @@ def get_sockaddr(
     """Return a fully qualified socket address that can be passed to
     :func:`socket.bind`."""
     if family == af_unix:
-        return host.split("://", 1)[1]
+        # Absolute path avoids IDNA encoding error when path starts with dot.
+        return os.path.abspath(host.partition("://")[2])
     try:
         res = socket.getaddrinfo(
             host, port, family, socket.SOCK_STREAM, socket.IPPROTO_TCP


Test patch: