IPv6 failed
import options, asyncdispatch
import httpx, net
proc onRequest(req: Request): Future[void] {.async.} =
# Log the incoming request
echo "Received request: ", req.httpMethod.get(), " ", req.path
if req.httpMethod == some(HttpGet):
case req.path.get()
of "/":
req.send("Hello World")
echo "Sent response: Hello World"
else:
req.send(Http404)
echo "Sent response: 404 Not Found"
let settings = Settings(
port: Port(80),
bindAddr: "::", # IPv6 address
listener: newSocket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6)
)
# Start the server and log that it's running
echo "Starting server on port ", settings.port
run(onRequest, settings)
echo "Server is running"
error
/Users/of/Work/Nim/web_test/ssr_test/src/serverv6.nim(22) serverv6
/Users/of/.choosenim/toolchains/nim-2.2.0/lib/pure/net.nim(309) newSocket
/Users/of/.choosenim/toolchains/nim-2.2.0/lib/std/oserrors.nim(92) raiseOSError
Error: unhandled exception: Bad file descriptor [OSError]
Yes, that's a problem. Is it an httpx problem?
Here's a much simpler version:
import net
let l = newSocket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6)
which gives me:
/home/infinoid/workspace/forms/nim/test2.nim(3) test2
/home/infinoid/.choosenim/toolchains/nim-2.2.0/lib/pure/net.nim(309) newSocket
/home/infinoid/.choosenim/toolchains/nim-2.2.0/lib/std/oserrors.nim(92) raiseOSError
Same error, no httpx.
(note: I'm not an httpx developer, I'm just having a similar problem and found this issue. But I don't think this one is httpx's fault.)
Here's what's wrong with your program:
- you probably meant to open a TCP socket with an IPv6 address , not a (raw) IPv6 socket. The third argument should be IPPROTO_TCP.
- there's a few more calls needed to set up a socket as a TCP listener. httpx does that here, but since you provided your own socket, you need to do it yourself. At the very least it will need
bindandlistencalls.
The linux tcp(7) manpage says:
To receive new incoming connections, first bind(2) the socket to a local address and port and then call listen(2) to put the socket into the listening state.
And the nim docs do the same.
Here's a corrected example:
import options, asyncdispatch
import httpx, net
proc onRequest(req: Request): Future[void] {.async.} =
# Log the incoming request
echo "Received request: ", req.httpMethod.get(), " ", req.path
if req.httpMethod == some(HttpGet):
case req.path.get()
of "/":
req.send("Hello World")
echo "Sent response: Hello World"
else:
req.send(Http404)
echo "Sent response: 404 Not Found"
let settings = Settings(
port: Port(8888),
bindAddr: "::", # IPv6 address
listener: newSocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)
)
settings.listener.setSockOpt(OptReuseAddr, true)
settings.listener.setSockOpt(OptReusePort, true)
settings.listener.bindAddr(settings.port, settings.bindAddr)
settings.listener.listen()
echo "Starting server on port ", settings.port
run(onRequest, settings)
echo "Server is running"
And here's some curl verbose output confirming that it connected over ipv6:
% curl -v6 http://localhost:8888/
* Host localhost:8888 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8888...
* Connected to localhost (::1) port 8888
* using HTTP/1.x
> GET / HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/8.12.1-DEV
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200
< Content-Length: 11
< Server: Nim-HTTPX
< Date: Sat, 22 Feb 2025 17:09:16 GMT
<
* Connection #0 to host localhost left intact
Hello World%
So that's working!
That said, it would be great if httpx could create the right kind of socket based on the address given.