Skip to content

Commit 0ce266d

Browse files
committed
Backport search domains support, close AsyncHttpClient#1207
1 parent 244e97f commit 0ce266d

File tree

7 files changed

+818
-279
lines changed

7 files changed

+818
-279
lines changed

netty-bp/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java

Lines changed: 113 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@
4242
import io.netty.util.concurrent.FastThreadLocal;
4343
import io.netty.util.concurrent.Future;
4444
import io.netty.util.concurrent.Promise;
45+
import io.netty.util.internal.EmptyArrays;
4546
import io.netty.util.internal.PlatformDependent;
47+
import io.netty.util.internal.StringUtil2;
4648
import io.netty.util.internal.logging.InternalLogger;
4749
import io.netty.util.internal.logging.InternalLoggerFactory;
4850

51+
import java.lang.reflect.Method;
4952
import java.net.IDN;
5053
import java.net.Inet4Address;
5154
import java.net.InetAddress;
@@ -67,6 +70,7 @@ public class DnsNameResolver extends InetNameResolver {
6770
private static final InetAddress LOCALHOST_ADDRESS;
6871

6972
static final InternetProtocolFamily[] DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[2];
73+
static final String[] DEFAULT_SEACH_DOMAINS;
7074

7175
static {
7276
// Note that we did not use SystemPropertyUtil.getBoolean() here to emulate the behavior of JDK.
@@ -83,6 +87,24 @@ public class DnsNameResolver extends InetNameResolver {
8387
}
8488
}
8589

90+
static {
91+
String[] searchDomains;
92+
try {
93+
Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
94+
Method open = configClass.getMethod("open");
95+
Method nameservers = configClass.getMethod("searchlist");
96+
Object instance = open.invoke(null);
97+
98+
@SuppressWarnings("unchecked")
99+
List<String> list = (List<String>) nameservers.invoke(instance);
100+
searchDomains = list.toArray(new String[list.size()]);
101+
} catch (Exception ignore) {
102+
// Failed to get the system name search domain list.
103+
searchDomains = EmptyArrays.EMPTY_STRINGS;
104+
}
105+
DEFAULT_SEACH_DOMAINS = searchDomains;
106+
}
107+
86108
private static final DatagramDnsResponseDecoder DECODER = new DatagramDnsResponseDecoder();
87109
private static final DatagramDnsQueryEncoder ENCODER = new DatagramDnsQueryEncoder();
88110

@@ -116,6 +138,8 @@ protected DnsServerAddressStream initialValue() throws Exception {
116138
private final int maxPayloadSize;
117139
private final boolean optResourceEnabled;
118140
private final HostsFileEntriesResolver hostsFileEntriesResolver;
141+
private final String[] searchDomains;
142+
private final int ndots;
119143

120144
/**
121145
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
@@ -134,6 +158,8 @@ protected DnsServerAddressStream initialValue() throws Exception {
134158
* @param maxPayloadSize the capacity of the datagram packet buffer
135159
* @param optResourceEnabled if automatic inclusion of a optional records is enabled
136160
* @param hostsFileEntriesResolver the {@link HostsFileEntriesResolver} used to check for local aliases
161+
* @param searchDomains the list of search domain
162+
* @param ndots the ndots value
137163
*/
138164
public DnsNameResolver(
139165
EventLoop eventLoop,
@@ -147,7 +173,9 @@ public DnsNameResolver(
147173
boolean traceEnabled,
148174
int maxPayloadSize,
149175
boolean optResourceEnabled,
150-
HostsFileEntriesResolver hostsFileEntriesResolver) {
176+
HostsFileEntriesResolver hostsFileEntriesResolver,
177+
String[] searchDomains,
178+
int ndots) {
151179

152180
super(eventLoop);
153181
checkNotNull(channelFactory, "channelFactory");
@@ -161,6 +189,8 @@ public DnsNameResolver(
161189
this.optResourceEnabled = optResourceEnabled;
162190
this.hostsFileEntriesResolver = checkNotNull(hostsFileEntriesResolver, "hostsFileEntriesResolver");
163191
this.resolveCache = resolveCache;
192+
this.searchDomains = checkNotNull(searchDomains, "searchDomains").clone();
193+
this.ndots = checkPositive(ndots, "ndots");
164194

165195
Bootstrap b = new Bootstrap();
166196
b.group(executor());
@@ -214,6 +244,14 @@ InternetProtocolFamily[] resolveAddressTypesUnsafe() {
214244
return resolvedAddressTypes;
215245
}
216246

247+
final String[] searchDomains() {
248+
return searchDomains;
249+
}
250+
251+
final int ndots() {
252+
return ndots;
253+
}
254+
217255
/**
218256
* Returns {@code true} if and only if this resolver sends a DNS query with the RD (recursion desired) flag set.
219257
* The default value is {@code true}.
@@ -375,25 +413,37 @@ private static void setSuccess(Promise<InetAddress> promise, InetAddress result)
375413
private void doResolveUncached(String hostname,
376414
Promise<InetAddress> promise,
377415
DnsCache resolveCache) {
378-
final DnsNameResolverContext<InetAddress> ctx =
379-
new DnsNameResolverContext<InetAddress>(this, hostname, promise, resolveCache) {
380-
@Override
381-
protected boolean finishResolve(
382-
InternetProtocolFamily f, List<DnsCacheEntry> resolvedEntries) {
383-
384-
final int numEntries = resolvedEntries.size();
385-
for (int i = 0; i < numEntries; i++) {
386-
final InetAddress a = resolvedEntries.get(i).address();
387-
if (addressMatchFamily(a, f)) {
388-
setSuccess(promise(), a);
389-
return true;
390-
}
391-
}
392-
return false;
393-
}
394-
};
416+
SingleResolverContext ctx = new SingleResolverContext(this, hostname, resolveCache);
417+
ctx.resolve(promise);
418+
}
419+
420+
final class SingleResolverContext extends DnsNameResolverContext<InetAddress> {
421+
422+
SingleResolverContext(DnsNameResolver parent, String hostname, DnsCache resolveCache) {
423+
super(parent, hostname, resolveCache);
424+
}
395425

396-
ctx.resolve();
426+
@Override
427+
DnsNameResolverContext<InetAddress> newResolverContext(DnsNameResolver parent,
428+
String hostname, DnsCache resolveCache) {
429+
return new SingleResolverContext(parent, hostname, resolveCache);
430+
}
431+
432+
@Override
433+
boolean finishResolve(
434+
InternetProtocolFamily f, List<DnsCacheEntry> resolvedEntries,
435+
Promise<InetAddress> promise) {
436+
437+
final int numEntries = resolvedEntries.size();
438+
for (int i = 0; i < numEntries; i++) {
439+
final InetAddress a = resolvedEntries.get(i).address();
440+
if (addressMatchFamily(a, f)) {
441+
setSuccess(promise, a);
442+
return true;
443+
}
444+
}
445+
return false;
446+
}
397447
}
398448

399449
@Override
@@ -471,40 +521,56 @@ private boolean doResolveAllCached(String hostname,
471521
return true;
472522
}
473523

474-
private void doResolveAllUncached(final String hostname,
475-
final Promise<List<InetAddress>> promise,
476-
DnsCache resolveCache) {
477-
final DnsNameResolverContext<List<InetAddress>> ctx =
478-
new DnsNameResolverContext<List<InetAddress>>(this, hostname, promise, resolveCache) {
479-
@Override
480-
protected boolean finishResolve(
481-
InternetProtocolFamily f, List<DnsCacheEntry> resolvedEntries) {
482-
483-
List<InetAddress> result = null;
484-
final int numEntries = resolvedEntries.size();
485-
for (int i = 0; i < numEntries; i++) {
486-
final InetAddress a = resolvedEntries.get(i).address();
487-
if (addressMatchFamily(a, f)) {
488-
if (result == null) {
489-
result = new ArrayList<InetAddress>(numEntries);
490-
}
491-
result.add(a);
492-
}
493-
}
524+
final class ListResolverContext extends DnsNameResolverContext<List<InetAddress>> {
525+
ListResolverContext(DnsNameResolver parent, String hostname, DnsCache resolveCache) {
526+
super(parent, hostname, resolveCache);
527+
}
494528

495-
if (result != null) {
496-
promise().trySuccess(result);
497-
return true;
498-
}
499-
return false;
529+
@Override
530+
DnsNameResolverContext<List<InetAddress>> newResolverContext(DnsNameResolver parent, String hostname,
531+
DnsCache resolveCache) {
532+
return new ListResolverContext(parent, hostname, resolveCache);
533+
}
534+
535+
@Override
536+
boolean finishResolve(
537+
InternetProtocolFamily f, List<DnsCacheEntry> resolvedEntries,
538+
Promise<List<InetAddress>> promise) {
539+
540+
List<InetAddress> result = null;
541+
final int numEntries = resolvedEntries.size();
542+
for (int i = 0; i < numEntries; i++) {
543+
final InetAddress a = resolvedEntries.get(i).address();
544+
if (addressMatchFamily(a, f)) {
545+
if (result == null) {
546+
result = new ArrayList<InetAddress>(numEntries);
500547
}
501-
};
548+
result.add(a);
549+
}
550+
}
551+
552+
if (result != null) {
553+
promise.trySuccess(result);
554+
return true;
555+
}
556+
return false;
557+
}
558+
}
502559

503-
ctx.resolve();
560+
private void doResolveAllUncached(String hostname,
561+
Promise<List<InetAddress>> promise,
562+
DnsCache resolveCache) {
563+
DnsNameResolverContext<List<InetAddress>> ctx = new ListResolverContext(this, hostname, resolveCache);
564+
ctx.resolve(promise);
504565
}
505566

506567
private static String hostname(String inetHost) {
507-
return IDN.toASCII(inetHost);
568+
String hostname = IDN.toASCII(inetHost);
569+
// Check for http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6894622
570+
if (StringUtil2.endsWith(inetHost, '.') && !StringUtil2.endsWith(hostname, '.')) {
571+
hostname += ".";
572+
}
573+
return hostname;
508574
}
509575

510576
/**

netty-bp/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverBuilder.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public final class DnsNameResolverBuilder {
4949
private int maxPayloadSize = 4096;
5050
private boolean optResourceEnabled = true;
5151
private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
52+
private String[] searchDomains = DnsNameResolver.DEFAULT_SEACH_DOMAINS;
53+
private int ndots = 1;
5254

5355
/**
5456
* Creates a new builder.
@@ -286,6 +288,46 @@ public DnsNameResolverBuilder hostsFileEntriesResolver(HostsFileEntriesResolver
286288
return this;
287289
}
288290

291+
/**
292+
* Set the list of search domains of the resolver.
293+
*
294+
* @param searchDomains the search domains
295+
* @return {@code this}
296+
*/
297+
public DnsNameResolverBuilder searchDomains(Iterable<String> searchDomains) {
298+
checkNotNull(searchDomains, "searchDomains");
299+
300+
final List<String> list =
301+
InternalThreadLocalMap.get().arrayList(4);
302+
303+
for (String f : searchDomains) {
304+
if (f == null) {
305+
break;
306+
}
307+
308+
// Avoid duplicate entries.
309+
if (list.contains(f)) {
310+
continue;
311+
}
312+
313+
list.add(f);
314+
}
315+
316+
this.searchDomains = list.toArray(new String[list.size()]);
317+
return this;
318+
}
319+
320+
/**
321+
* Set the number of dots which must appear in a name before an initial absolute query is made.
322+
*
323+
* @param ndots the ndots value
324+
* @return {@code this}
325+
*/
326+
public DnsNameResolverBuilder ndots(int ndots) {
327+
this.ndots = ndots;
328+
return this;
329+
}
330+
289331
/**
290332
* Returns a new {@link DnsNameResolver} instance.
291333
*
@@ -312,6 +354,8 @@ public DnsNameResolver build() {
312354
traceEnabled,
313355
maxPayloadSize,
314356
optResourceEnabled,
315-
hostsFileEntriesResolver);
357+
hostsFileEntriesResolver,
358+
searchDomains,
359+
ndots);
316360
}
317361
}

0 commit comments

Comments
 (0)