Skip to content

Commit 922ceae

Browse files
committed
small fix
1 parent 98c485c commit 922ceae

File tree

3 files changed

+174
-167
lines changed

3 files changed

+174
-167
lines changed

httpclient5/src/main/java/org/apache/hc/client5/http/AddressSelectingDnsResolver.java

Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
import org.slf4j.LoggerFactory;
5151

5252
/**
53-
* {@code Rfc6724AddressSelectingDnsResolver} wraps a delegate {@link DnsResolver}
53+
* {@code AddressSelectingDnsResolver} wraps a delegate {@link DnsResolver}
5454
* and applies RFC 6724 destination address selection rules (RFC 6724 §6)
5555
* to the returned addresses. It can also enforce or bias a protocol family preference.
5656
*
@@ -185,16 +185,10 @@ private static List<InetAddress> filterCandidates(
185185
final InetAddress[] resolved,
186186
final ProtocolFamilyPreference pref) {
187187

188-
final List<InetAddress> out = new ArrayList<>(resolved.length);
189-
for (final InetAddress a : resolved) {
190-
if (!isUsableDestination(a)) {
191-
continue;
192-
}
193-
if (shouldInclude(pref, a)) {
194-
out.add(a);
195-
}
196-
}
197-
return out;
188+
return Arrays.stream(resolved)
189+
.filter(AddressSelectingDnsResolver::isUsableDestination)
190+
.filter(a -> shouldInclude(pref, a))
191+
.collect(Collectors.toList());
198192
}
199193

200194
private static boolean shouldInclude(final ProtocolFamilyPreference pref, final InetAddress a) {
@@ -220,17 +214,9 @@ private List<InetAddress> sortByRfc6724(final List<InetAddress> addrs) {
220214
LOG.trace("RFC6724 input candidates: {}", fmt(addrs));
221215
}
222216

223-
final List<InetSocketAddress> socketAddresses = new ArrayList<>(addrs.size());
224-
for (final InetAddress a : addrs) {
225-
socketAddresses.add(new InetSocketAddress(a, PROBE_PORT));
226-
}
227-
228-
final List<InetAddress> srcs = inferSourceAddresses(socketAddresses);
229-
230217
final List<Info> infos = new ArrayList<>(addrs.size());
231-
for (int i = 0; i < addrs.size(); i++) {
232-
final InetAddress dst = addrs.get(i);
233-
final InetAddress src = srcs.get(i);
218+
for (final InetAddress dst : addrs) {
219+
final InetAddress src = inferSourceAddress(new InetSocketAddress(dst, PROBE_PORT));
234220
infos.add(new Info(dst, src, ipAttrOf(dst), ipAttrOf(src)));
235221
}
236222

@@ -245,10 +231,9 @@ private List<InetAddress> sortByRfc6724(final List<InetAddress> addrs) {
245231

246232
infos.sort(RFC6724_COMPARATOR);
247233

248-
final List<InetAddress> out = new ArrayList<>(infos.size());
249-
for (final Info info : infos) {
250-
out.add(info.dst);
251-
}
234+
final List<InetAddress> out = infos.stream()
235+
.map(info -> info.dst)
236+
.collect(Collectors.toList());
252237

253238
if (LOG.isTraceEnabled()) {
254239
LOG.trace("RFC6724 output order: {}", fmt(out));
@@ -257,30 +242,15 @@ private List<InetAddress> sortByRfc6724(final List<InetAddress> addrs) {
257242
return out;
258243
}
259244

260-
private List<InetAddress> inferSourceAddresses(final List<InetSocketAddress> destinations) {
261-
final List<InetAddress> srcs = new ArrayList<>(destinations.size());
262-
263-
for (final InetSocketAddress dest : destinations) {
264-
InetAddress src = null;
265-
try {
266-
src = sourceAddressResolver.resolveSource(dest);
267-
} catch (final SocketException ignore) {
268-
if (LOG.isTraceEnabled()) {
269-
LOG.trace("RFC6724 could not infer source address for {}: {}", dest, ignore.toString());
270-
}
271-
}
272-
srcs.add(src);
273-
}
274-
275-
if (LOG.isTraceEnabled()) {
276-
final List<String> printable = new ArrayList<>(srcs.size());
277-
for (final InetAddress a : srcs) {
278-
printable.add(addr(a));
245+
private InetAddress inferSourceAddress(final InetSocketAddress destination) {
246+
try {
247+
return sourceAddressResolver.resolveSource(destination);
248+
} catch (final SocketException ex) {
249+
if (LOG.isTraceEnabled()) {
250+
LOG.trace("RFC6724 could not infer source address for {}: {}", destination, ex.toString());
279251
}
280-
LOG.trace("RFC6724 inferred source addresses: {}", printable);
252+
return null;
281253
}
282-
283-
return srcs;
284254
}
285255

286256
private static List<InetAddress> applyFamilyPreference(
@@ -388,7 +358,8 @@ private static final class Attr {
388358
}
389359
}
390360

391-
private enum Scope {
361+
// Package-private for unit testing.
362+
enum Scope {
392363
INTERFACE_LOCAL(0x1),
393364
LINK_LOCAL(0x2),
394365
ADMIN_LOCAL(0x4),
@@ -419,9 +390,12 @@ static Scope fromValue(final int v) {
419390
case 0x8: {
420391
return ORG_LOCAL;
421392
}
422-
default: {
393+
case 0xe: {
423394
return GLOBAL;
424395
}
396+
default: {
397+
throw new IllegalArgumentException("Unknown scope value: 0x" + Integer.toHexString(v));
398+
}
425399
}
426400
}
427401
}
@@ -434,7 +408,8 @@ private static Attr ipAttrOf(final InetAddress ip) {
434408
return new Attr(classifyScope(ip), e.precedence, e.label);
435409
}
436410

437-
private static Scope classifyScope(final InetAddress ip) {
411+
// Package-private for unit testing.
412+
static Scope classifyScope(final InetAddress ip) {
438413
if (ip.isLoopbackAddress()) {
439414
return Scope.INTERFACE_LOCAL;
440415
}
@@ -443,8 +418,14 @@ private static Scope classifyScope(final InetAddress ip) {
443418
}
444419
if (ip.isMulticastAddress()) {
445420
if (ip instanceof Inet6Address) {
446-
// RFC 6724 §3.1 and RFC 4291: low 4 bits of second byte are scope for IPv6 multicast.
447-
return Scope.fromValue(ip.getAddress()[1] & 0x0f);
421+
// RFC 6724 §3.1 and RFC 4291: low 4 bits of second byte encode scope for IPv6 multicast.
422+
// Not all nibble values map to a known Scope constant; treat unknown values as GLOBAL.
423+
final int nibble = ip.getAddress()[1] & 0x0f;
424+
try {
425+
return Scope.fromValue(nibble);
426+
} catch (final IllegalArgumentException e) {
427+
return Scope.GLOBAL;
428+
}
448429
}
449430
return Scope.GLOBAL;
450431
}
@@ -466,7 +447,8 @@ private static final class PolicyEntry {
466447
}
467448
}
468449

469-
private static final class Network {
450+
// Package-private for unit testing.
451+
static final class Network {
470452
final byte[] ip;
471453
final int bits;
472454

@@ -549,6 +531,11 @@ private static PolicyEntry classify(final InetAddress ip) {
549531
final int preferB = 1;
550532

551533
// RFC 6724 §6: destination address selection rules.
534+
//
535+
// Rules 3, 4 and 7 are not implementable with standard JDK APIs:
536+
// Rule 3 (Avoid deprecated source addresses) — InetAddress exposes no deprecation state.
537+
// Rule 4 (Prefer home addresses) — Mobile IPv6 concept; not applicable to an HTTP client.
538+
// Rule 7 (Prefer native transport) — JDK provides no encapsulation/tunneling info.
552539

553540
// Rule 1: Avoid unusable destinations.
554541
final boolean validA = aSrc != null && !aSrc.isAnyLocalAddress();
@@ -571,6 +558,10 @@ private static PolicyEntry classify(final InetAddress ip) {
571558
return preferB;
572559
}
573560

561+
// Rule 3: Avoid deprecated addresses — skipped (see above).
562+
563+
// Rule 4: Prefer home addresses — skipped (see above).
564+
574565
// Rule 5: Prefer matching label.
575566
if (aSrcAttr.label == aDstAttr.label && bSrcAttr.label != bDstAttr.label) {
576567
return preferA;
@@ -587,6 +578,8 @@ private static PolicyEntry classify(final InetAddress ip) {
587578
return preferB;
588579
}
589580

581+
// Rule 7: Prefer native transport — skipped (see above).
582+
590583
// Rule 8: Prefer smaller scope.
591584
if (aDstAttr.scope.value < bDstAttr.scope.value) {
592585
return preferA;
@@ -595,7 +588,7 @@ private static PolicyEntry classify(final InetAddress ip) {
595588
return preferB;
596589
}
597590

598-
// Rule 9: Longest matching prefix (IPv6 only).
591+
// Rule 9: Longest matching prefix (IPv6 only, per RFC 6724 §6).
599592
if (aDst instanceof Inet6Address && bDst instanceof Inet6Address) {
600593
final int commonA = commonPrefixLen(aSrc, aDst);
601594
final int commonB = commonPrefixLen(bSrc, bDst);
@@ -645,19 +638,15 @@ static String addr(final InetAddress a) {
645638
}
646639

647640
static List<String> fmt(final InetAddress[] arr) {
648-
final List<String> out = new ArrayList<>(arr.length);
649-
for (final InetAddress a : arr) {
650-
out.add(addr(a));
651-
}
652-
return out;
641+
return Arrays.stream(arr)
642+
.map(AddressSelectingDnsResolver::addr)
643+
.collect(Collectors.toList());
653644
}
654645

655646
static List<String> fmt(final List<InetAddress> arr) {
656-
final List<String> out = new ArrayList<>(arr.size());
657-
for (final InetAddress a : arr) {
658-
out.add(addr(a));
659-
}
660-
return out;
647+
return arr.stream()
648+
.map(AddressSelectingDnsResolver::addr)
649+
.collect(Collectors.toList());
661650
}
662651

663652
}

0 commit comments

Comments
 (0)