Workaround for URL quoting issue with LLv6 host literals. Due to an issue with URL quoting for LLv6 host literals, the original implementation of SystemDefaultDnsResolver does not support constructing URLs with LLv6 literals that have a ZoneID. This commit implements a workaround that strips the ZoneID from LLv6 literals before resolving them. This allows URLs with LLv6 literals to be constructed without quoting the ZoneID. Note that this workaround does not fully comply with RFC 6874, but it should work in most cases.

This commit is contained in:
Arturo Bernal 2023-02-28 19:02:28 +01:00 committed by Oleg Kalnichevski
parent 95e8abbda8
commit efe57e03c6
2 changed files with 84 additions and 1 deletions

View File

@ -40,7 +40,23 @@ public class SystemDefaultDnsResolver implements DnsResolver {
@Override @Override
public InetAddress[] resolve(final String host) throws UnknownHostException { public InetAddress[] resolve(final String host) throws UnknownHostException {
return InetAddress.getAllByName(host); try {
// Try resolving using the default resolver
return InetAddress.getAllByName(host);
} catch (final UnknownHostException e) {
// If default resolver fails, try stripping the IPv6 zone ID and resolving again
String strippedHost = null;
if (host.charAt(0) == '[') {
final int i = host.lastIndexOf('%');
if (i != -1) {
strippedHost = host.substring(0, i) + "]";
}
}
if (strippedHost != null) {
return InetAddress.getAllByName(strippedHost);
}
throw e;
}
} }
@Override @Override

View File

@ -0,0 +1,67 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http;
import org.junit.jupiter.api.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SystemDefaultDnsResolverTest {
@Test
void resolve() throws UnknownHostException {
final SystemDefaultDnsResolver resolver = SystemDefaultDnsResolver.INSTANCE;
final InetAddress[] result1 = resolver.resolve("127.0.0.1");
assertEquals(1, result1.length);
assertArrayEquals(new byte[]{127, 0, 0, 1}, result1[0].getAddress());
}
@Test
void resolveIPv6ZoneId() throws UnknownHostException {
final SystemDefaultDnsResolver resolver = SystemDefaultDnsResolver.INSTANCE;
// This is an IPv6 address literal with zone ID
final InetAddress[] result = resolver.resolve("[fe80::221:b7ff:fe8a:57d5%en4]");
assertEquals(1, result.length);
assertArrayEquals(new byte[]{(byte) 0xfe, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0x02, 0x21, (byte) 0xb7, (byte) 0xff, (byte) 0xfe, (byte) 0x8a, 0x57, (byte) 0xd5}, result[0].getAddress());
}
@Test
void resolveCanonicalHostname() throws UnknownHostException {
final SystemDefaultDnsResolver resolver = SystemDefaultDnsResolver.INSTANCE;
final String result1 = resolver.resolveCanonicalHostname("example.com");
assertEquals("example.com", result1);
}
}