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.
|
* 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 hostname the hostname
|
||||||
* @param additionals the additional records
|
* @param additionals the additional records
|
||||||
* @param cause the resolution failure
|
* @param cause the resolution failure
|
||||||
|
@ -891,24 +891,6 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
return query0(nameServerAddr, question, toArray(additionals, false), promise);
|
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(
|
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query0(
|
||||||
InetSocketAddress nameServerAddr, DnsQuestion question,
|
InetSocketAddress nameServerAddr, DnsQuestion question,
|
||||||
DnsRecord[] additionals,
|
DnsRecord[] additionals,
|
||||||
|
@ -189,11 +189,11 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
assert recordTypes.length > 0;
|
assert recordTypes.length > 0;
|
||||||
final int end = recordTypes.length - 1;
|
final int end = recordTypes.length - 1;
|
||||||
for (int i = 0; i < end; ++i) {
|
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;
|
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,
|
private void query(final DnsServerAddressStream nameServerAddrStream, final int nameServerAddrStreamIndex,
|
||||||
final DnsQuestion question,
|
final DnsQuestion question,
|
||||||
final Promise<T> promise, Throwable cause) {
|
final Promise<T> promise) {
|
||||||
query(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
query(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
||||||
parent.dnsQueryLifecycleObserverFactory().newDnsQueryLifecycleObserver(question), promise, cause);
|
parent.dnsQueryLifecycleObserverFactory().newDnsQueryLifecycleObserver(question), promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void query(final DnsServerAddressStream nameServerAddrStream,
|
private void query(final DnsServerAddressStream nameServerAddrStream,
|
||||||
final int nameServerAddrStreamIndex,
|
final int nameServerAddrStreamIndex,
|
||||||
final DnsQuestion question,
|
final DnsQuestion question,
|
||||||
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
||||||
final Promise<T> promise,
|
final Promise<T> promise) {
|
||||||
final Throwable cause) {
|
|
||||||
if (nameServerAddrStreamIndex >= nameServerAddrStream.size() || allowedQueries == 0 || promise.isCancelled()) {
|
if (nameServerAddrStreamIndex >= nameServerAddrStream.size() || allowedQueries == 0 || promise.isCancelled()) {
|
||||||
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question, queryLifecycleObserver,
|
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question, queryLifecycleObserver,
|
||||||
promise, cause);
|
promise);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,22 +319,21 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Throwable queryCause = future.cause();
|
|
||||||
try {
|
try {
|
||||||
if (queryCause == null) {
|
if (future.isSuccess()) {
|
||||||
onResponse(nameServerAddrStream, nameServerAddrStreamIndex, question, future.getNow(),
|
onResponse(nameServerAddrStream, nameServerAddrStreamIndex, question, future.getNow(),
|
||||||
queryLifecycleObserver, promise);
|
queryLifecycleObserver, promise);
|
||||||
} else {
|
} else {
|
||||||
// Server did not respond or I/O error occurred; try again.
|
// Server did not respond or I/O error occurred; try again.
|
||||||
queryLifecycleObserver.queryFailed(queryCause);
|
queryLifecycleObserver.queryFailed(future.cause());
|
||||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise, queryCause);
|
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
tryToFinishResolve(nameServerAddrStream, nameServerAddrStreamIndex, question,
|
||||||
// queryLifecycleObserver has already been terminated at this point so we must
|
// queryLifecycleObserver has already been terminated at this point so we must
|
||||||
// not allow it to be terminated again by tryToFinishResolve.
|
// not allow it to be terminated again by tryToFinishResolve.
|
||||||
NoopDnsQueryLifecycleObserver.INSTANCE,
|
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.
|
// Retry with the next server if the server did not tell us that the domain does not exist.
|
||||||
if (code != DnsResponseCode.NXDOMAIN) {
|
if (code != DnsResponseCode.NXDOMAIN) {
|
||||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question,
|
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question,
|
||||||
queryLifecycleObserver.queryNoAnswer(code), promise, null);
|
queryLifecycleObserver.queryNoAnswer(code), promise);
|
||||||
} else {
|
} else {
|
||||||
queryLifecycleObserver.queryFailed(NXDOMAIN_QUERY_FAILED_EXCEPTION);
|
queryLifecycleObserver.queryFailed(NXDOMAIN_QUERY_FAILED_EXCEPTION);
|
||||||
}
|
}
|
||||||
@ -422,7 +420,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
|
|
||||||
if (!nameServers.isEmpty()) {
|
if (!nameServers.isEmpty()) {
|
||||||
query(parent.uncachedRedirectDnsServerStream(nameServers), 0, question,
|
query(parent.uncachedRedirectDnsServerStream(nameServers), 0, question,
|
||||||
queryLifecycleObserver.queryRedirected(unmodifiableList(nameServers)), promise, null);
|
queryLifecycleObserver.queryRedirected(unmodifiableList(nameServers)), promise);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,8 +601,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
final int nameServerAddrStreamIndex,
|
final int nameServerAddrStreamIndex,
|
||||||
final DnsQuestion question,
|
final DnsQuestion question,
|
||||||
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
final DnsQueryLifecycleObserver queryLifecycleObserver,
|
||||||
final Promise<T> promise,
|
final Promise<T> promise) {
|
||||||
final Throwable cause) {
|
|
||||||
// There are no queries left to try.
|
// There are no queries left to try.
|
||||||
if (!queriesInProgress.isEmpty()) {
|
if (!queriesInProgress.isEmpty()) {
|
||||||
queryLifecycleObserver.queryCancelled(allowedQueries);
|
queryLifecycleObserver.queryCancelled(allowedQueries);
|
||||||
@ -612,7 +609,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
// There are still some queries we did not receive responses for.
|
// There are still some queries we did not receive responses for.
|
||||||
if (gotPreferredAddress()) {
|
if (gotPreferredAddress()) {
|
||||||
// But it's OK to finish the resolution process if we got a resolved address of the preferred type.
|
// 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.
|
// 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 (queryLifecycleObserver == NoopDnsQueryLifecycleObserver.INSTANCE) {
|
||||||
// If the queryLifecycleObserver has already been terminated we should create a new one for this
|
// If the queryLifecycleObserver has already been terminated we should create a new one for this
|
||||||
// fresh query.
|
// fresh query.
|
||||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise, cause);
|
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, promise);
|
||||||
} else {
|
} else {
|
||||||
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, queryLifecycleObserver,
|
query(nameServerAddrStream, nameServerAddrStreamIndex + 1, question, queryLifecycleObserver,
|
||||||
promise, cause);
|
promise);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -636,15 +633,11 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
queryLifecycleObserver.queryFailed(NAME_SERVERS_EXHAUSTED_EXCEPTION);
|
queryLifecycleObserver.queryFailed(NAME_SERVERS_EXHAUSTED_EXCEPTION);
|
||||||
|
|
||||||
// .. and we could not find any A/AAAA records.
|
// .. and we could not find any A/AAAA records.
|
||||||
|
if (!triedCNAME) {
|
||||||
// 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) {
|
|
||||||
// As the last resort, try to query CNAME, just in case the name server has it.
|
// As the last resort, try to query CNAME, just in case the name server has it.
|
||||||
triedCNAME = true;
|
triedCNAME = true;
|
||||||
|
|
||||||
query(hostname, DnsRecordType.CNAME, getNameServers(hostname), promise, null);
|
query(hostname, DnsRecordType.CNAME, getNameServers(hostname), promise);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -652,7 +645,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We have at least one resolved address or tried CNAME as the last resort..
|
// We have at least one resolved address or tried CNAME as the last resort..
|
||||||
finishResolve(promise, cause);
|
finishResolve(promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean gotPreferredAddress() {
|
private boolean gotPreferredAddress() {
|
||||||
@ -671,7 +664,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishResolve(Promise<T> promise, Throwable cause) {
|
private void finishResolve(Promise<T> promise) {
|
||||||
if (!queriesInProgress.isEmpty()) {
|
if (!queriesInProgress.isEmpty()) {
|
||||||
// If there are queries in progress, we should cancel it because we already finished the resolution.
|
// 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();
|
for (Iterator<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> i = queriesInProgress.iterator();
|
||||||
@ -710,15 +703,10 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
.append(' ');
|
.append(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final UnknownHostException unknownHostException = new UnknownHostException(buf.toString());
|
final UnknownHostException cause = 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
|
resolveCache.cache(hostname, additionals, cause, parent.ch.eventLoop());
|
||||||
// itself.
|
promise.tryFailure(cause);
|
||||||
resolveCache.cache(hostname, additionals, unknownHostException, parent.ch.eventLoop());
|
|
||||||
} else {
|
|
||||||
unknownHostException.initCause(cause);
|
|
||||||
}
|
|
||||||
promise.tryFailure(unknownHostException);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract boolean finishResolve(Class<? extends InetAddress> addressType, List<DnsCacheEntry> resolvedEntries,
|
abstract boolean finishResolve(Class<? extends InetAddress> addressType, List<DnsCacheEntry> resolvedEntries,
|
||||||
@ -759,7 +747,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
queryLifecycleObserver.queryFailed(cause);
|
queryLifecycleObserver.queryFailed(cause);
|
||||||
PlatformDependent.throwException(cause);
|
PlatformDependent.throwException(cause);
|
||||||
}
|
}
|
||||||
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise, null);
|
query(stream, 0, cnameQuestion, queryLifecycleObserver.queryCNAMEd(cnameQuestion), promise);
|
||||||
}
|
}
|
||||||
if (parent.supportsAAAARecords()) {
|
if (parent.supportsAAAARecords()) {
|
||||||
try {
|
try {
|
||||||
@ -770,17 +758,17 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
queryLifecycleObserver.queryFailed(cause);
|
queryLifecycleObserver.queryFailed(cause);
|
||||||
PlatformDependent.throwException(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,
|
private boolean query(String hostname, DnsRecordType type, DnsServerAddressStream dnsServerAddressStream,
|
||||||
Promise<T> promise, Throwable cause) {
|
Promise<T> promise) {
|
||||||
final DnsQuestion question = newQuestion(hostname, type);
|
final DnsQuestion question = newQuestion(hostname, type);
|
||||||
if (question == null) {
|
if (question == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
query(dnsServerAddressStream, 0, question, promise, cause);
|
query(dnsServerAddressStream, 0, question, promise);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import java.net.InetSocketAddress;
|
|||||||
* A {@link RuntimeException} raised when {@link DnsNameResolver} failed to perform a successful query.
|
* A {@link RuntimeException} raised when {@link DnsNameResolver} failed to perform a successful query.
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class DnsNameResolverException extends RuntimeException {
|
public final class DnsNameResolverException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = -8826717909627131850L;
|
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)");
|
.append(" (no stack trace available)");
|
||||||
|
|
||||||
final DnsNameResolverException e;
|
final DnsNameResolverException e;
|
||||||
if (cause == null) {
|
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 {
|
|
||||||
e = new DnsNameResolverException(nameServerAddr, question(), buf.toString(), cause);
|
e = new DnsNameResolverException(nameServerAddr, question(), buf.toString(), cause);
|
||||||
|
} else {
|
||||||
|
e = new DnsNameResolverException(nameServerAddr, question(), buf.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.tryFailure(e);
|
promise.tryFailure(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1322,51 +1322,4 @@ public class DnsNameResolverTest {
|
|||||||
return rm.getEntry();
|
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