Repository: netty/netty (Java)

Issue:
Unexpected WebClient blocks reported by BlockHound
I'm new to webflux so I posted a [question on stackoverflow](https://stackoverflow.com/questions/66091050/why-is-webclient-blocking-in-this-web-flux-app) thinking I was doing something wrong in my code, but after seeing [this issue](https://github.com/netty/netty/issues/10925) and related [pull request](https://github.com/netty/netty/pull/10935), I'm thinking I just need to tell BlockHound to ignore some calls. 

I created [my own BlockHoundIntegration](https://github.com/aztosca/web-client-test/blob/master/src/main/java/org/app/webclienttest/MyBlockHoundIntegration.java) that suppresses the BlockHound exceptions when added to the BlockHound.install() call, but wanted to raise an issue here to see if maybe this is something that should be addressed in NettyBlockHoundIntegration.

### Expected behavior
No blocking calls reported by BlockHound
### Actual behavior
Blocking calls reported by BlockHound
### Steps to reproduce

1. Run the simple boot app linked below in the _reproducer code_ section.
2. target http://localhost:8080/test-web-client

### Minimal yet complete reproducer code (or URL to code)
https://github.com/aztosca/web-client-test
https://github.com/aztosca/web-client-test/blob/master/src/main/java/org/app/webclienttest/WebClientTestApplication.java
### Netty version
4.1.58
### JVM version (e.g. `java -version`)
openjdk version "11.0.2"
### OS version (e.g. `uname -a`)
MacOS 11.2


Hints:

Patch:
diff --git a/common/src/main/java/io/netty/util/internal/Hidden.java b/common/src/main/java/io/netty/util/internal/Hidden.java
--- a/common/src/main/java/io/netty/util/internal/Hidden.java
+++ b/common/src/main/java/io/netty/util/internal/Hidden.java
@@ -119,6 +119,18 @@ public void applyTo(BlockHound.Builder builder) {
                     "io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
                     "parse");
 
+            builder.allowBlockingCallsInside(
+                    "io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
+                    "parseEtcResolverSearchDomains");
+
+            builder.allowBlockingCallsInside(
+                    "io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
+                    "parseEtcResolverOptions");
+
+            builder.allowBlockingCallsInside(
+                    "io.netty.resolver.HostsFileParser",
+                    "parse");
+
             builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
                 @Override
                 public Predicate<Thread> apply(final Predicate<Thread> p) {
diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java b/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java
--- a/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java
+++ b/resolver-dns/src/main/java/io/netty/resolver/dns/UnixResolverDnsServerAddressStreamProvider.java
@@ -86,7 +86,7 @@ static DnsServerAddressStreamProvider parseSilently() {
      * the default DNS server to use, and also overrides for individual domains. Also parse list of files of the format
      * <a href="
      * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
-     * /etc/resolver</a> which may contain multiple files to override the name servers used for multimple domains.
+     * /etc/resolver</a> which may contain multiple files to override the name servers used for multiple domains.
      * @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
      * @param etcResolverFiles List of files of the format defined in
      * <a href="
@@ -121,7 +121,7 @@ public UnixResolverDnsServerAddressStreamProvider(File etcResolvConf, File... et
      * the default DNS server to use, and also overrides for individual domains. Also parse a directory of the format
      * <a href="
      * https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
-     * /etc/resolver</a> which may contain multiple files to override the name servers used for multimple domains.
+     * /etc/resolver</a> which may contain multiple files to override the name servers used for multiple domains.
      * @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
      * @param etcResolverDir Directory containing files of the format defined in
      * <a href="
@@ -379,7 +379,7 @@ static List<String> parseEtcResolverSearchDomains(File etcResolvConf) throws IOE
                 } else if (line.startsWith(SEARCH_ROW_LABEL)) {
                     int i = indexOfNonWhiteSpace(line, SEARCH_ROW_LABEL.length());
                     if (i >= 0) {
-                        // May contain more then one entry, either seperated by whitespace or tab.
+                        // May contain more then one entry, either separated by whitespace or tab.
                         // See https://linux.die.net/man/5/resolver
                         String[] domains = WHITESPACE_PATTERN.split(line.substring(i));
                         Collections.addAll(searchDomains, domains);


Test patch:
diff --git a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
--- a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+++ b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
@@ -26,6 +26,7 @@
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.channel.socket.nio.NioSocketChannel;
 import io.netty.handler.ssl.SslContext;
@@ -35,7 +36,7 @@
 import io.netty.handler.ssl.SslProvider;
 import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import io.netty.handler.ssl.util.SelfSignedCertificate;
-import io.netty.resolver.dns.DnsServerAddressStreamProvider;
+import io.netty.resolver.dns.DnsNameResolverBuilder;
 import io.netty.resolver.dns.DnsServerAddressStreamProviders;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.ReferenceCountUtil;
@@ -59,6 +60,7 @@
 import java.util.List;
 import java.util.Queue;
 import java.util.ServiceLoader;
+import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
@@ -320,7 +322,30 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
     }
 
     @Test(timeout = 5000L)
-    public void testParseEtcResolverFilesAllowsBlockingCalls() throws InterruptedException {
+    public void testUnixResolverDnsServerAddressStreamProvider_Parse() throws InterruptedException {
+        doTestParseResolverFilesAllowsBlockingCalls(DnsServerAddressStreamProviders::unixDefault);
+    }
+
+    @Test(timeout = 5000L)
+    public void testHostsFileParser_Parse() throws InterruptedException {
+        doTestParseResolverFilesAllowsBlockingCalls(DnsNameResolverBuilder::new);
+    }
+
+    @Test(timeout = 5000L)
+    public void testUnixResolverDnsServerAddressStreamProvider_ParseEtcResolverSearchDomainsAndOptions()
+            throws InterruptedException {
+        NioEventLoopGroup group = new NioEventLoopGroup();
+        try {
+            DnsNameResolverBuilder builder = new DnsNameResolverBuilder(group.next())
+                    .channelFactory(NioDatagramChannel::new);
+            doTestParseResolverFilesAllowsBlockingCalls(builder::build);
+        } finally {
+            group.shutdownGracefully();
+        }
+    }
+
+    private static void doTestParseResolverFilesAllowsBlockingCalls(Callable<Object> callable)
+            throws InterruptedException {
         SingleThreadEventExecutor executor =
                 new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
                     @Override
@@ -335,11 +360,11 @@ protected void run() {
                 };
         try {
             CountDownLatch latch = new CountDownLatch(1);
-            List<DnsServerAddressStreamProvider> result = new ArrayList<>();
+            List<Object> result = new ArrayList<>();
             List<Throwable> error = new ArrayList<>();
             executor.execute(() -> {
                 try {
-                    result.add(DnsServerAddressStreamProviders.unixDefault());
+                    result.add(callable.call());
                 } catch (Throwable t) {
                     error.add(t);
                 }