将 `http::uri::Uri` 的主机解析为 IP 地址

发布于 2025-01-14 07:53:26 字数 1228 浏览 2 评论 0原文

我有一个 http::uri::Uri 值,我想获取主机的 IpAddr。如果主机是IP地址(例如http://127.0.0.1:8080),则只需要对其进行解析。但如果是主机名,则需要进行 DNS 解析。我怎样才能最好地做到这一点?

似乎 std 只有一种公共方式来解析主机: ToSocketAddrs。不幸的是,它在 API 中包含了与 DNS 解析无关的端口。但是哦,好吧。但有了这个,我的第一次尝试是这样的:(

use std::net::ToSocketAddr;

let host = uri.authority().unwrap().host();
let addresses = (host, 0).to_socket_addrs()?
    .map(|socket_addr| socket_addr.ip());

我在这里使用虚拟端口,因为它与 DNS 解析无关。)

这种尝试适用于很多情况,但不适用于方括号 IPv6 形式:http:// /[::1]:8080。这里,host()[::1] 并且不能解析为 IpAddr,因此 to_socket_addrs()尝试将 [::1] 解析为主机,但失败。所以我需要手动检查主机是否是方括号内的 IPv6。不太好,特别是因为我不知道这里到底允许使用什么语法。

我还有其他几个想法,例如将 Authority 更改为始终具有虚拟端口,因为这样我就可以调用 authority.as_str().to_socket_addrs()<&str as ToSocketAddr> 确实支持 [::1]:8080 语法!但该实现需要一个端口,如果没有则失败。

所以是的,我还没有找到一种简单的方法来做到这一点。但看来这应该没那么难!有什么想法吗?

I have an http::uri::Uri value and I want to get the IpAddrs of the host. In case the host is an IP address (e.g. http://127.0.0.1:8080), it just needs to be parsed. But if it's a hostname, it needs to be DNS resolved. How do I best do that?

It seems like std only has one public way to resolve hosts: ToSocketAddrs. Unfortunately, it includes the port in the API which is irrelevant for DNS resolving. But oh well. But with this, my first attempt was thus:

use std::net::ToSocketAddr;

let host = uri.authority().unwrap().host();
let addresses = (host, 0).to_socket_addrs()?
    .map(|socket_addr| socket_addr.ip());

(I am using a dummy port here since it's irrelevant for the DNS resolution.)

This attempt works for many cases, but not for the square-bracket IPv6 form: http://[::1]:8080. Here, host() is [::1] and is not parsable as IpAddr, thus to_socket_addrs() tries to resolve [::1] as host, which fails. So I would need to check manually whether the host is an IPv6 within square-brackets. Not nice, especially since I don't know what grammars are allowed here exactly.

I had several other ideas, like changing the Authority to always have a dummy port, because then I could call authority.as_str().to_socket_addrs(). The <&str as ToSocketAddr> does support the [::1]:8080 syntax! But that impl NEEDS a port and fails if there is none.

So yes, I have not found an easy way to do that. But it seems this should not be that hard! Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城°AllureLove 2025-01-21 07:53:26

尝试将其解析为 std::net:首先:IpAddr,如果失败则查找主机名。您必须自己处理方括号表示法,但这还不错:

use std::net::IpAddr;

fn parse_ip_from_uri_host(host: &str) -> Option<IpAddr> {
    host.parse::<IpAddr>().ok().or_else(||
        // Parsing failed, try as bracketed IPv6
        host.strip_prefix("[")?
            .strip_suffix("]")?
            .parse::<IpAddr>().ok()
    )
}

(游乐场)

如果返回None 则解析失败,下一步是尝试通过 DNS 将该字符串解析为主机名。

Try parsing it as std::net::IpAddr first, then look up the hostname if that fails. You have to handle the square bracket notation yourself, but this isn't too bad:

use std::net::IpAddr;

fn parse_ip_from_uri_host(host: &str) -> Option<IpAddr> {
    host.parse::<IpAddr>().ok().or_else(||
        // Parsing failed, try as bracketed IPv6
        host.strip_prefix("[")?
            .strip_suffix("]")?
            .parse::<IpAddr>().ok()
    )
}

(Playground)

If this returns None then parsing failed, and the next step is to attempt to resolve the string as a hostname through DNS.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文