TIdHTTP indy 组件和 IPVersion 属性 (firemonkey)

TIdHTTP indy component and IPVersion property (firemonkey)

我正在多设备应用程序(在 Rad Studio Tokyo 10.2.3 中构建)上使用 TIdHTTP 组件。我所做的只是将文件下载到我的本地应用程序文件夹 (iOS)。我想确保它适用于 IPv6,但我没有看到 TIdHTTP 的 "IPVersion" 属性。我在 rad studio 的其他 indy 组件上看到它(例如 IdFTP)。

有没有办法在 TIdHTTP 组件的代码中设置 IPVersion?下面是我用来下载文件的代码片段。如果它在 IPv4 上失败,接下来应该尝试 IPv6:

UnicodeString LFileName = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "myfile.txt");
TFileStream* fs = new TFileStream(LFileName, fmCreate);
Form1->TIdHTTP->ConnectTimeout = 8000;  // give it 8 seconds
Form1->TIdHTTP->ReadTimeout = 8000;

try
{
    UnicodeString URL = "http://myservername.com/myfile.txt";
    Form1->TIdHTTP->Get(URL, fs);
    Form1->TIdHTTP->Disconnect();  
    // ShowMessage("Good download via IPv4");
}
catch(const System::Sysutils::Exception &)
{
    try
    {
     Form1->TIdHTTP->Disconnect(); // clean up from IPv4 try
     UnicodeString URL = "http://[myservername.com]/myfile.txt";
     Form1->TIdHTTP->Get(URL, fs);
     Form1->TIdHTTP->Disconnect();  
     // ShowMessage("Good download via IPv6");

现在我只是把域名放在方括号中,希望这对 IPv6 有效......我不确定,直到我能得到一个真正的 IPv6 网络设置(正在处理它)。

更新:我刚刚有一个使用这种方法的应用程序被 Apple Store 接受,所以很明显它通过了 IPv6 测试。仅供参考

我发现 this discussion 其中 Remy Lebeau 指出:

TIdHTTP parses IP version info only from the URL itself, so if you need to send a request to an IPv6 target (IP address or hostname), you have to tell TIdHTTP to use IPv6 by wrapping the hostname portion of the URL in square brackets, eg:

s := idHTTP.Post('http://[IPv6 address or hostname]/resource', ...);

Otherwise TIdHTTP uses IPv4 instead.

This bracketed syntax is a requirement when using IPv6 address literals in URLs, per RFCs 2732 and 3986. But when using a hostname instead, there is no such syntax requirement. Connecting to a hostname requires a DNS lookup to discover the host's available IP addresses and their respective IP versions, and then connect to those addresses as needed until one succeeds.

Indy does not currently implement that kind of connection model. It first allocates a socket based on the client's IPVersion property, THEN performs a DNS request suited for that IPVersion, and then finally connects to the first IP address reported by DNS. This is a known limitation of Indy, which would require a redesign of Indy's internal logic to fix. However, it can be worked around manually in most Indy client components by performing your own DNS lookup ahead of time and then looping through the results, setting Indy's Host and IPVersion properties and calling Connect() on each loop iteration.

However, TIdHTTP is a special case, because it derives the Host and IPVersion values from the requested URL, overriding anything the calling code might set manually. However, it is also because of this model that would potentially allow TIdHTTP to be updated to perform its own DNS loop internally without having to rewrite all of Indy's client components to match. Except that Indy does not currently implement a function that returns all of the IP addresses of a hostname, only the first IP address of a particular version. Until such a function is added to Indy in a cross-platform manner, TIdHTTP cannot be updated to auto-detect IPv4/IPv6 hosts.

因此,这证实了我的方法应该有效(先尝试 IPv4,如果失败再尝试 IPv6)。

此外,我编辑了我的代码以在尝试 IPv6 之前显示 "Disconnect",以防 IPv4 造成混乱。