Repository: quarkusio/quarkus
Issue: Colon in resource @Path does not work

**Describe the bug**
REST resources that use the colon character (`:`) in their `@Path` cannot be requested. This issue is present on Windows when running the application and on Windows and Linux when running a JUnit test.

**Expected behavior**
REST resources that use the colon character can be requested in tests and when running the application.

**Actual behavior**
When running a JUnit test (Windows & Linux): a 404 response is returned.

When running the application (Windows only): the following error message is returned.

```
java.nio.file.InvalidPathException: Illegal char <:> at index 90: C:/Users/redacted/workspace/rest-json-quickstart/src/main/resources/META-INF/resources/fruits:test
at java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
	at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
	at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
	at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
	at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229)
	at java.base/java.nio.file.Path.resolve(Path.java:515)
	at io.quarkus.bootstrap.classloading.DirectoryClassPathElement.getResource(DirectoryClassPathElement.java:39)
	at io.quarkus.bootstrap.classloading.QuarkusClassLoader.getResource(QuarkusClassLoader.java:281)
	at io.vertx.core.file.impl.FileResolver.getValidClassLoaderResource(FileResolver.java:201)
	at io.vertx.core.file.impl.FileResolver.resolveFile(FileResolver.java:175)
	at io.vertx.core.impl.VertxImpl.resolveFile(VertxImpl.java:805)
	at io.vertx.core.file.impl.FileSystemImpl$20.perform(FileSystemImpl.java:930)
	at io.vertx.core.file.impl.FileSystemImpl$20.perform(FileSystemImpl.java:928)
	at io.vertx.core.file.impl.FileSystemImpl$BlockingAction.handle(FileSystemImpl.java:971)
	at io.vertx.core.file.impl.FileSystemImpl$BlockingAction.handle(FileSystemImpl.java:951)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:313)
	at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)
```

**To Reproduce**
Steps to reproduce the behavior on Windows or Linux:
1. `git clone https://github.com/kekbur/quarkus-path-colon-issue.git && cd quarkus-path-colon-issue`
2. `./mvnw test`

Steps to reproduce the behavior on Windows:
1. `git clone https://github.com/kekbur/quarkus-path-colon-issue.git && cd quarkus-path-colon-issue`
2. `./mvnw quarkus:dev`
3. `curl localhost:8080/fruits:test`

**Environment (please complete the following information):**
Windows:
 - Output of `uname -a` or `ver`: CYGWIN_NT-10.0 DESKTOP 3.1.4(0.340/5/3) 2020-02-19 08:49 x86_64 Cygwin
 - Output of `java -version`: openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
 - GraalVM version (if different from Java): N/A
 - Quarkus version or git rev: 1.6.0.Final
 - Build tool (ie. output of `mvnw --version` or `gradlew --version`): Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)

Linux:
 - Output of `uname -a` or `ver`: Linux LAPTOP 4.4.0-19041-Microsoft #1-Microsoft Fri Dec 06 14:06:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
 - Output of `java -version`: openjdk version "11.0.7" 2020-04-14
OpenJDK Runtime Environment (build 11.0.7+10-post-Ubuntu-2ubuntu218.04)
OpenJDK 64-Bit Server VM (build 11.0.7+10-post-Ubuntu-2ubuntu218.04, mixed mode, sharing)

**Additional context**
The issue is probably with Quarkus and not Resteasy, because using a colon in a pure Reasteasy project works just fine. Sample project: https://github.com/kekbur/resteasy-colon-in-path-test/blob/master/src/main/java/org/jboss/resteasy/examples/service/Library.java
http://localhost:9095/resteasy/library/books/badger:test


Changed files:
core/deployment/src/test/java/io/quarkus/runner/classloading/DirectoryClassPathElementTestCase.java
independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/DirectoryClassPathElement.java

diff --git a/core/deployment/src/test/java/io/quarkus/runner/classloading/DirectoryClassPathElementTestCase.java b/core/deployment/src/test/java/io/quarkus/runner/classloading/DirectoryClassPathElementTestCase.java
index 5f3a41378a5..ed372c921f3 100644
--- a/core/deployment/src/test/java/io/quarkus/runner/classloading/DirectoryClassPathElementTestCase.java
+++ b/core/deployment/src/test/java/io/quarkus/runner/classloading/DirectoryClassPathElementTestCase.java
@@ -5,6 +5,7 @@
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Set;
 
 import org.junit.jupiter.api.AfterAll;
@@ -49,4 +50,17 @@ public void testGetResource() {
         Assertions.assertNotNull(res);
         Assertions.assertEquals("subdir file", new String(res.getData(), StandardCharsets.UTF_8));
     }
+
+    @Test
+    public void testInvalidPath() {
+        final String invalidPath;
+        if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")) {
+            invalidPath = "D:\\\\*";
+        } else {
+            invalidPath = "hello\\u0000world";
+        }
+        final DirectoryClassPathElement classPathElement = new DirectoryClassPathElement(root);
+        final ClassPathResource resource = classPathElement.getResource(invalidPath);
+        Assertions.assertNull(resource, "DirectoryClassPathElement wasn't expected to return a resource for an invalid path");
+    }
 }
diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/DirectoryClassPathElement.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/DirectoryClassPathElement.java
index cbd32f11011..c5d8dfd697d 100644
--- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/DirectoryClassPathElement.java
+++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/DirectoryClassPathElement.java
@@ -7,6 +7,7 @@
 import java.net.URI;
 import java.net.URL;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.CodeSource;
@@ -36,7 +37,13 @@ public Path getRoot() {
 
     @Override
     public ClassPathResource getResource(String name) {
-        Path file = root.resolve(name);
+        final Path file;
+        try {
+            file = root.resolve(name);
+        } catch (InvalidPathException ipe) {
+            // can't resolve the resource
+            return null;
+        }
         Path normal = file.normalize();
         String cn = name;
         if (File.separatorChar == '\\\\') {