Quarkus: Colon in resource @Path does not work

Created on 15 Jul 2020  路  6Comments  路  Source: quarkusio/quarkus

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

kinbug

All 6 comments

@asoldano is adding a colon even allowed by the JAX-RS spec?

Hello @geoand, I think this still is a bug in the classloading code of Quarkus which deals with resource resolutions. I've opened https://github.com/quarkusio/quarkus/pull/10777/ with a potential fix and explaining why I think it's a bug.

Yeah, I agree, I just wanted to know what the JAX-RS spec said before doing anything :)

Hi, I've looked into this a bit.

TL:DR: It should be fine relative to the spec, and it works in RESTEasy. I would be interested in where it doesn't work in Quarkus.

More information:

  1. From https://tools.ietf.org/html/rfc1738 "Uniform Resource Locators (URL)",

    httpurl = "http://" hostport [ "/" hpath [ "?" search ]]
    hpath = hsegment *[ "/" hsegment ]
    hsegment = *[ uchar | ";" | ":" | "@" | "&" | "=" ]
    ...

so that suggests ':' is fine.

  1. Note that https://tools.ietf.org/html/rfc3986 "Uniform Resource Identifier (URI): Generic Syntax" says

    This document obsoletes [RFC2396], which merged "Uniform Resource
    Locators" [RFC1738] and "Relative Uniform Resource Locators"
    [RFC1808] in order to define a single, generic syntax for all URIs.
    It obsoletes [RFC2732], which introduced syntax for an IPv6 address.
    It excludes portions of RFC 1738 that defined the specific syntax of
    individual URI schemes; those portions will be updated as separate
    documents.

but I don't see any evidence that "those portions will be updated" ever happened, so I'm assuming RFC1738 is still relevant.

The only references to the use of ':' in http URIs are these:

A. ':' is characterized as a reserved general delimiter, where

If data for a URI component would conflict with a reserved
character's purpose as a delimiter, then the conflicting data must be
percent-encoded before the URI is formed.

 But ':' doesn't have a role as a delimiter in an HTTP path, so it doesn't have to be encoded.

B. There's a rule about not having a ':' in the first path segment of a relative URI.

  1. The code

    @Path("/")
    public static class TestResource {

      @GET
      @Path("a:b/{p}")
      public void testColon(@PathParam("p") String p) {
         System.out.println("p: " + p);
      }
    

    }

    @Test
    public void test() {
    Builder request = client.target("http://localhost:8081/a:b/c:d").request();
    Response response = request.get();
    System.out.println("status: " + response.getStatus());
    response.close();
    }

outputs

p: c:d
status: 204

on master branch.

Thanks a lot @ronsigal !

Thanks for looking into this guys.

I thought using colons in paths was not unusual. Google's API design guide recommends using a colon for implementing actions not covered by the basic 5 HTTP verbs.

POST /files/a/long/file/name:undelete

Was this page helpful?
0 / 5 - 0 ratings