UnknownHostException should mention search domain if used

Motivation:
ba80fbbe05 modified the UnknownHostException to not include the search domain if the DNS query failed, but this masks what DNS query actually failed. Have the full hostname (including the search domain) provides more visibility and may help diagnose a configuration error if queries are unexpectedly failing.

Modifications:
- Remove DnsNameResolverContext#pristineHostname

Result:
UnknownHostException is more accurate and reflect what hostname actually resulted in failure.
This commit is contained in:
Scott Mitchell 2017-06-22 00:13:13 -07:00
parent d672a5a483
commit efe37e0d28
2 changed files with 36 additions and 16 deletions

View File

@ -100,7 +100,6 @@ abstract class DnsNameResolverContext<T> {
Collections.newSetFromMap(
new IdentityHashMap<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>, Boolean>());
private String pristineHostname;
private List<DnsCacheEntry> resolvedEntries;
private int allowedQueries;
private boolean triedCNAME;
@ -142,20 +141,31 @@ abstract class DnsNameResolverContext<T> {
} else if (count < parent.searchDomains().length) {
doSearchDomainQuery(count++, this);
} else {
promise.tryFailure(future.cause());
promise.tryFailure(new SearchDomainUnknownHostException(future.cause(), hostname));
}
}
});
}
}
private static final class SearchDomainUnknownHostException extends UnknownHostException {
SearchDomainUnknownHostException(Throwable cause, String originalHostname) {
super("Search domain query failed. Original hostname: '" + originalHostname + "' " + cause.getMessage());
setStackTrace(cause.getStackTrace());
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
private void doSearchDomainQuery(int count, FutureListener<T> listener) {
DnsNameResolverContext<T> nextContext = newResolverContext(parent,
hostname + '.' + parent.searchDomains()[count],
additionals,
resolveCache,
nameServerAddrs);
nextContext.pristineHostname = hostname;
Promise<T> nextPromise = parent.executor().newPromise();
nextContext.internalResolve(nextPromise);
nextPromise.addListener(listener);
@ -636,13 +646,7 @@ abstract class DnsNameResolverContext<T> {
final int tries = maxAllowedQueries - allowedQueries;
final StringBuilder buf = new StringBuilder(64);
buf.append("failed to resolve '");
if (pristineHostname != null) {
buf.append(pristineHostname);
} else {
buf.append(hostname);
}
buf.append('\'');
buf.append("failed to resolve '").append(hostname).append('\'');
if (tries > 1) {
if (tries < maxAllowedQueries) {
buf.append(" after ")

View File

@ -33,6 +33,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
@ -273,10 +274,8 @@ public class SearchDomainTest {
}
@Test
public void testExceptionMsgNoSearchDomain() throws Exception {
Set<String> domains = new HashSet<String>();
TestDnsServer.MapRecordStoreA store = new TestDnsServer.MapRecordStoreA(domains);
public void testExceptionMsgContainsSearchDomain() throws Exception {
TestDnsServer.MapRecordStoreA store = new TestDnsServer.MapRecordStoreA(Collections.<String>emptySet());
dnsServer = new TestDnsServer(store);
dnsServer.start();
@ -286,8 +285,25 @@ public class SearchDomainTest {
assertTrue(fut.await(10, TimeUnit.SECONDS));
assertFalse(fut.isSuccess());
final Throwable cause = fut.cause();
assertEquals(UnknownHostException.class, cause.getClass());
assertThat(cause, instanceOf(UnknownHostException.class));
assertThat("search domain is included in UnknownHostException", cause.getMessage(),
not(containsString("foo.com")));
containsString("foo.com"));
}
@Test
public void testExceptionMsgDoesNotContainSearchDomainIfNdotsNotHighEnough() throws Exception {
TestDnsServer.MapRecordStoreA store = new TestDnsServer.MapRecordStoreA(Collections.<String>emptySet());
dnsServer = new TestDnsServer(store);
dnsServer.start();
resolver = newResolver().searchDomains(Collections.singletonList("foo.com")).ndots(1).build();
Future<InetAddress> fut = resolver.resolve("unknown.hostname");
assertTrue(fut.await(10, TimeUnit.SECONDS));
assertFalse(fut.isSuccess());
final Throwable cause = fut.cause();
assertThat(cause, instanceOf(UnknownHostException.class));
assertThat("search domain is included in UnknownHostException", cause.getMessage(),
not(containsString("foo.com")));
}
}