Revert "Allow to detect failed query caused by an Timeout / IO error and also not cache these."
This reverts commit 12a413bf02
as it needs some more changes due some changes that were merged into 4.1 before.
This commit is contained in:
parent
12a413bf02
commit
433dbeb149
@ -65,8 +65,6 @@ public interface DnsCache {
|
||||
|
||||
/**
|
||||
* Cache the resolution failure for a given hostname.
|
||||
* Be aware this <strong>won't</strong> be called with timeout / cancel / transport exceptions.
|
||||
*
|
||||
* @param hostname the hostname
|
||||
* @param additionals the additional records
|
||||
* @param cause the resolution failure
|
||||
|
@ -891,24 +891,6 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
return query0(nameServerAddr, question, toArray(additionals, false), promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the {@link Throwable} was caused by an timeout or transport error.
|
||||
* These methods can be used on the {@link Future#cause()} that is returned by the various methods exposed by this
|
||||
* {@link DnsNameResolver}.
|
||||
*/
|
||||
public static boolean isTransportOrTimeoutError(Throwable cause) {
|
||||
return cause != null && cause.getCause() instanceof DnsNameResolverException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the {@link Throwable} was caused by an timeout.
|
||||
* These methods can be used on the {@link Future#cause()} that is returned by the various methods exposed by this
|
||||
* {@link DnsNameResolver}.
|
||||
*/
|
||||
public static boolean isTimeoutError(Throwable cause) {
|
||||
return cause != null && cause.getCause() instanceof DnsNameResolverTimeoutException;
|
||||
}
|
||||
|
||||
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query0(
|
||||
InetSocketAddress nameServerAddr, DnsQuestion question,
|
||||
DnsRecord[] additionals,
|
||||
|
@ -189,11 +189,11 @@ abstract class DnsNameResolverContext<T> {
|
||||
assert recordTypes.length > 0;
|
||||
final int end = recordTypes.length - 1;
|
||||
for (int i = 0; i < end; ++i) {
|
||||
if (!query(hostname, recordTypes[i], nameServerAddressStream.duplicate(), promise, null)) {
|
||||
if (!query(hostname, recordTypes[i], nameServerAddressStream.duplicate(), promise)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
query(hostname, recordTypes[end], nameServerAddressStream, promise, null);
|
||||
query(hostname, recordTypes[end], nameServerAddressStream, promise);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,20 +283,19 @@ abstract class DnsNameResolverContext<T> {
|
||||
|
||||
private void query(final DnsServerAddressStream nameServerAddrStream, final int nameServerAddrStreamIndex,
|
||||
final DnsQuestion question,
|
||||
final Promise<T> promise, Throwable cause) {
|
||||
final Promise<T> promise) {
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
||||
parent.dnsQueryLifecycleObserverFactory().newDnsQueryLifecycleObserver(question), promise, cause);
|
||||
parent.dnsQueryLifecycleObserverFactory().newDnsQueryLifecycleObserver(question), promise);
|
||||
}
|
||||
|
||||
private void query(final DnsServerAddressStream nameServerAddrStream,
|
||||
final int nameServerAddrStreamIndex,
|
||||
final DnsQuestion question,
|
||||
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
||||
final Promise<T> promise,
|
||||
final Throwable cause) {
|
||||
final Promise<T> promise) {
|
||||
if (nameServerAddrStreamIndex >= nameServerAddrStream.size() || allowedQueries == 0 || promise.isCancelled()) {
|
||||
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question, queryLifecycleObserver,
|
||||
promise, cause);
|
||||
promise);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -320,22 +319,21 @@ abstract class DnsNameResolverContext<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
final Throwable queryCause = future.cause();
|
||||
try {
|
||||
if (queryCause == null) {
|
||||
if (future.isSuccess()) {
|
||||
onResponse(nameServerAddrStream, nameServerAddrStreamIndex, question, future.getNow(),
|
||||
queryLifecycleObserver, promise);
|
||||
} else {
|
||||
// Server did not respond or I/O error occurred; try again.
|
||||
queryLifecycleObserver.queryFailed(queryCause);
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise, queryCause);
|
||||
queryLifecycleObserver.queryFailed(future.cause());
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise);
|
||||
}
|
||||
} finally {
|
||||
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
||||
// queryLifecycleObserver has already been terminated at this point so we must
|
||||
// not allow it to be terminated again by tryToFinishResolve.
|
||||
NoopDnsQueryLifecycleObserver.INSTANCE,
|
||||
promise, queryCause);
|
||||
promise);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -368,7 +366,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
// Retry with the next server if the server did not tell us that the domain does not exist.
|
||||
if (code != DnsResponseCode.NXDOMAIN) {
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question,
|
||||
queryLifecycleObserver.queryNoAnswer(code), promise, null);
|
||||
queryLifecycleObserver.queryNoAnswer(code), promise);
|
||||
} else {
|
||||
queryLifecycleObserver.queryFailed(NXDOMAIN_QUERY_FAILED_EXCEPTION);
|
||||
}
|
||||
@ -422,7 +420,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
|
||||
if (!nameServers.isEmpty()) {
|
||||
query(parent.uncachedRedirectDnsServerStream(nameServers), 0, question,
|
||||
queryLifecycleObserver.queryRedirected(unmodifiableList(nameServers)), promise, null);
|
||||
queryLifecycleObserver.queryRedirected(unmodifiableList(nameServers)), promise);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -603,8 +601,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
final int nameServerAddrStreamIndex,
|
||||
final DnsQuestion question,
|
||||
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
||||
final Promise<T> promise,
|
||||
final Throwable cause) {
|
||||
final Promise<T> promise) {
|
||||
// There are no queries left to try.
|
||||
if (!queriesInProgress.isEmpty()) {
|
||||
queryLifecycleObserver.queryCancelled(allowedQueries);
|
||||
@ -612,7 +609,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
// There are still some queries we did not receive responses for.
|
||||
if (gotPreferredAddress()) {
|
||||
// But it's OK to finish the resolution process if we got a resolved address of the preferred type.
|
||||
finishResolve(promise, cause);
|
||||
finishResolve(promise);
|
||||
}
|
||||
|
||||
// We did not get any resolved address of the preferred type, so we can't finish the resolution process.
|
||||
@ -625,10 +622,10 @@ abstract class DnsNameResolverContext<T> {
|
||||
if (queryLifecycleObserver == NoopDnsQueryLifecycleObserver.INSTANCE) {
|
||||
// If the queryLifecycleObserver has already been terminated we should create a new one for this
|
||||
// fresh query.
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise, cause);
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise);
|
||||
} else {
|
||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, queryLifecycleObserver,
|
||||
promise, cause);
|
||||
promise);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -636,15 +633,11 @@ abstract class DnsNameResolverContext<T> {
|
||||
queryLifecycleObserver.queryFailed(NAME_SERVERS_EXHAUSTED_EXCEPTION);
|
||||
|
||||
// .. and we could not find any A/AAAA records.
|
||||
|
||||
// If cause != null we know this was caused by a timeout / cancel / transport exception. In this case we
|
||||
// won't try to resolve the CNAME as we only should do this if we could not get the A/AAAA records because
|
||||
// these not exists and the DNS server did probably signal it.
|
||||
if (cause == null && !triedCNAME) {
|
||||
if (!triedCNAME) {
|
||||
// As the last resort, try to query CNAME, just in case the name server has it.
|
||||
triedCNAME = true;
|
||||
|
||||
query(hostname, DnsRecordType.CNAME, getNameServers(hostname), promise, null);
|
||||
query(hostname, DnsRecordType.CNAME, getNameServers(hostname), promise);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -652,7 +645,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
}
|
||||
|
||||
// We have at least one resolved address or tried CNAME as the last resort..
|
||||
finishResolve(promise, cause);
|
||||
finishResolve(promise);
|
||||
}
|
||||
|
||||
private boolean gotPreferredAddress() {
|
||||
@ -671,7 +664,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void finishResolve(Promise<T> promise, Throwable cause) {
|
||||
private void finishResolve(Promise<T> promise) {
|
||||
if (!queriesInProgress.isEmpty()) {
|
||||
// If there are queries in progress, we should cancel it because we already finished the resolution.
|
||||
for (Iterator<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> i = queriesInProgress.iterator();
|
||||
@ -710,15 +703,10 @@ abstract class DnsNameResolverContext<T> {
|
||||
.append(' ');
|
||||
}
|
||||
}
|
||||
final UnknownHostException unknownHostException = new UnknownHostException(buf.toString());
|
||||
if (cause == null) {
|
||||
// Only cache if the failure was not because of an IO error / timeout that was caused by the query
|
||||
// itself.
|
||||
resolveCache.cache(hostname, additionals, unknownHostException, parent.ch.eventLoop());
|
||||
} else {
|
||||
unknownHostException.initCause(cause);
|
||||
}
|
||||
promise.tryFailure(unknownHostException);
|
||||
final UnknownHostException cause = new UnknownHostException(buf.toString());
|
||||
|
||||
resolveCache.cache(hostname, additionals, cause, parent.ch.eventLoop());
|
||||
promise.tryFailure(cause);
|
||||
}
|
||||
|
||||
abstract boolean finishResolve(Class<? extends InetAddress> addressType, List<DnsCacheEntry> resolvedEntries,
|
||||
@ -759,7 +747,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
queryLifecycleObserver.queryFailed(cause);
|
||||
PlatformDependent.throwException(cause);
|
||||
}
|
||||
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise, null);
|
||||
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise);
|
||||
}
|
||||
if (parent.supportsAAAARecords()) {
|
||||
try {
|
||||
@ -770,17 +758,17 @@ abstract class DnsNameResolverContext<T> {
|
||||
queryLifecycleObserver.queryFailed(cause);
|
||||
PlatformDependent.throwException(cause);
|
||||
}
|
||||
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise, null);
|
||||
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean query(String hostname, DnsRecordType type, DnsServerAddressStream dnsServerAddressStream,
|
||||
Promise<T> promise, Throwable cause) {
|
||||
Promise<T> promise) {
|
||||
final DnsQuestion question = newQuestion(hostname, type);
|
||||
if (question == null) {
|
||||
return false;
|
||||
}
|
||||
query(dnsServerAddressStream, 0, question, promise, cause);
|
||||
query(dnsServerAddressStream, 0, question, promise);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import java.net.InetSocketAddress;
|
||||
* A {@link RuntimeException} raised when {@link DnsNameResolver} failed to perform a successful query.
|
||||
*/
|
||||
@UnstableApi
|
||||
public class DnsNameResolverException extends RuntimeException {
|
||||
public final class DnsNameResolverException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -8826717909627131850L;
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 The Netty Project
|
||||
*
|
||||
* The Netty Project 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.
|
||||
*/
|
||||
package io.netty.resolver.dns;
|
||||
|
||||
import io.netty.handler.codec.dns.DnsQuestion;
|
||||
import io.netty.util.internal.UnstableApi;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* A {@link DnsNameResolverException} raised when {@link DnsNameResolver} failed to perform a successful query because
|
||||
* of an timeout. In this case you may want to retry the operation.
|
||||
*/
|
||||
@UnstableApi
|
||||
public final class DnsNameResolverTimeoutException extends DnsNameResolverException {
|
||||
private static final long serialVersionUID = -8826717969627131854L;
|
||||
|
||||
public DnsNameResolverTimeoutException(
|
||||
InetSocketAddress remoteAddress, DnsQuestion question, String message) {
|
||||
super(remoteAddress, question, message);
|
||||
}
|
||||
}
|
@ -213,13 +213,12 @@ final class DnsQueryContext {
|
||||
.append(" (no stack trace available)");
|
||||
|
||||
final DnsNameResolverException e;
|
||||
if (cause == null) {
|
||||
// This was caused by an timeout so use DnsNameResolverTimeoutException to allow the user to
|
||||
// handle it special (like retry the query).
|
||||
e = new DnsNameResolverTimeoutException(nameServerAddr, question(), buf.toString());
|
||||
} else {
|
||||
if (cause != null) {
|
||||
e = new DnsNameResolverException(nameServerAddr, question(), buf.toString(), cause);
|
||||
} else {
|
||||
e = new DnsNameResolverException(nameServerAddr, question(), buf.toString());
|
||||
}
|
||||
|
||||
promise.tryFailure(e);
|
||||
}
|
||||
}
|
||||
|
@ -1322,51 +1322,4 @@ public class DnsNameResolverTest {
|
||||
return rm.getEntry();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 3000)
|
||||
public void testTimeoutNotCached() {
|
||||
DnsCache cache = new DnsCache() {
|
||||
@Override
|
||||
public void clear() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clear(String hostname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends DnsCacheEntry> get(String hostname, DnsRecord[] additionals) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsCacheEntry cache(String hostname, DnsRecord[] additionals, InetAddress address,
|
||||
long originalTtl, EventLoop loop) {
|
||||
fail("Should not be cached");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsCacheEntry cache(String hostname, DnsRecord[] additionals, Throwable cause, EventLoop loop) {
|
||||
fail("Should not be cached");
|
||||
return null;
|
||||
}
|
||||
};
|
||||
DnsNameResolverBuilder builder = newResolver();
|
||||
builder.queryTimeoutMillis(100)
|
||||
.authoritativeDnsServerCache(cache)
|
||||
.resolveCache(cache)
|
||||
.nameServerProvider(new SingletonDnsServerAddressStreamProvider(
|
||||
new InetSocketAddress(NetUtil.LOCALHOST, 12345)));
|
||||
DnsNameResolver resolver = builder.build();
|
||||
Future<InetAddress> result = resolver.resolve("doesnotexist.netty.io").awaitUninterruptibly();
|
||||
Throwable cause = result.cause();
|
||||
assertTrue(cause instanceof UnknownHostException);
|
||||
assertTrue(cause.getCause() instanceof DnsNameResolverTimeoutException);
|
||||
assertTrue(DnsNameResolver.isTimeoutError(cause));
|
||||
assertTrue(DnsNameResolver.isTransportOrTimeoutError(cause));
|
||||
resolver.close();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user