- Notifications
You must be signed in to change notification settings - Fork3k
Add a configuration to serve a local directory with a static handler#51186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Conversation
dd79a29 to2bc57dcCompare
ia3andy left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
LGTM, just cleaning non changed files
...nsions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.javaShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpConfig.javaShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
...ions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpStaticDirConfig.javaShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
ia3andy commentedNov 24, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I also forgot, you need to add those files as watched for livereload |
9744cb6 to691e79aComparemathias82 commentedNov 24, 2025
ii have added@ia3andy |
691e79a to4a1de61Compare...vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
...vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
...vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
...rtx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/LocalStaticResourcesConfig.java OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
c6feebb to55a80ffComparemathias82 commentedNov 25, 2025
Improve validation and handling of local static resources directory
|
ia3andy left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks!
ia3andy commentedNov 25, 2025
@mathias82 the code is LGTM, could you add the doc part also, I remember an old doc doing this with the StaticHandler (which was bad), but maybe it was removed. |
This comment has been minimized.
This comment has been minimized.
cdd5850 to76d924bCompare This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
...ions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpStaticDirConfig.javaShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
| To expose the contents of a `static/` directory under the `/local-static` path: | ||
| [source,properties] | ||
| ---- | ||
| quarkus.http.static-dir.path=/local-static | ||
| quarkus.http.static-dir.directory=static | ||
| ---- | ||
| With this configuration, a file located at `static/index.html` will be available at: | ||
| `http://localhost:8080/local-static/index.html`. | ||
| To disable serving local static resources explicitly: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| To expose the contents of a`static/` directory under the`/local-static`path: | |
| [source,properties] | |
| ---- | |
| quarkus.http.static-dir.path=/local-static | |
| quarkus.http.static-dir.directory=static | |
| ---- | |
| With this configuration, a file located at`static/index.html` will be available at: | |
| `http://localhost:8080/local-static/index.html`. | |
| To disable serving local static resources explicitly: | |
| To expose the contents of a`static/` directory under the`/static`endpoint: | |
| [source,properties] | |
| ---- | |
| quarkus.http.static-dir.endpoint=/static | |
| quarkus.http.static-dir.path=static | |
| ---- | |
| With this configuration, a file located at`static/index.html` will be available at: | |
| `http://localhost:8080/static/index.html`. | |
| To disable serving local static resources explicitly: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@mathias82 any reason not to auto enable whenendpoint orpath is not empty as@FroMage suggested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@ia3andy@FroMage There is one reason: this feature exposes a local filesystem directory over HTTP.
If we auto-enable it as soon asendpoint orpath is set, it becomes easier
for large apps with layered configuration to accidentally expose a directory
just because some partial config was inherited or left behind.
By keepingenabled as an explicit opt-in switch, we avoid accidental exposure
and make the intent very clear: nothing is served unless the user consciously
enables it.
That said, if the project convention is to auto-enable on config, I can update
the implementation accordingly, I just wanted to highlight the security/ops
angle behind the current design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@FroMage I let you decide on that one :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@mathias82 the change I suggested is still appllicable
| Routerrouter =httpRouter.getValue(); | ||
| router.route(basePath +"/*") | ||
| .handler(newHttpStaticDirHandler(staticFiles)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@mathias82 what is this?
mathias82Nov 28, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@ia3andy This registers a catch-all Vert.x route for the configured static directory.
registerHttpStaticDirRoute collects all discovered static files at build time and
passes them toregisterHttpStaticDir(...), which at runtime installs:
router.route(basePath + "/*").handler(new HttpStaticDirHandler(staticFiles));So this line effectively exposes every file under the configuredstatic-dir.path
at<basePath>/*, and delegates the resolution toHttpStaticDirHandler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Remove it is not needed
This comment has been minimized.
This comment has been minimized.
672e2a8 to1dc209dCompare This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Andy Damevin <ia3andy@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
c898d56 tof62e7e9CompareStatus for workflow |
quarkus-botbot commentedNov 29, 2025 • edited by github-actionsbot
Loading Uh oh!
There was an error while loading.Please reload this page.
edited by github-actionsbot
Uh oh!
There was an error while loading.Please reload this page.
Status for workflow |
| Status | Name | Step | Failures | Logs | Raw logs | Build scan |
|---|---|---|---|---|---|---|
| ✔️ | JVM Integration Tests - JDK 17 | Logs | Raw logs | 🚧 | ||
| ✔️ | JVM Integration Tests - JDK 17 Windows | Logs | Raw logs | 🚧 | ||
| ✔️ | JVM Integration Tests - JDK 21 | Logs | Raw logs | 🚧 | ||
| ❌ | JVM Integration Tests - JDK 21 Semeru | Build | Failures | Logs | Raw logs | 🚧 |
| ✔️ | JVM Integration Tests - JDK 25 | Logs | Raw logs | 🚧 |
Full information is available in theBuild summary check run.
You can consult theDevelocity build scans.
Failures
⚙️ JVM Integration Tests - JDK 21 Semeru#
- Failing: integration-tests/oidc-wiremock integration-tests/virtual-threads/grpc-virtual-threads📦 integration-tests/oidc-wiremock
❌io.quarkus.it.keycloak.CodeFlowAuthorizationTest. -History -More details -Source on GitHub
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkusat io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:663)at io.quarkus.test.junit.QuarkusTestExtension.interceptBeforeAllMethod(QuarkusTestExtension.java:730)at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)Caused by: java.lang.RuntimeException: Failed to start quarkusat io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)at io.quarkus.runtime.Application.start(Application.java:101)at java.base/java.lang.reflect.Method.invoke(Method.java:586)❌io.quarkus.it.keycloak.CodeFlowAuthorizationTest.testCodeFlowUserInfoCachedInIdToken line431 -History -More details -Source on GitHub
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:31)at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:183)at io.quarkus.it.keycloak.CodeFlowAuthorizationTest.testCodeFlowUserInfoCachedInIdToken(CodeFlowAuthorizationTest.java:431)📦 integration-tests/virtual-threads/grpc-virtual-threads
❌io.quarkus.grpc.example.streaming.VertxVirtualThreadTest. -History -More details -Source on GitHub
org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [io.quarkus.test.junit.QuarkusTestExtension]: Internal error: Test class was loaded with an unexpected classloader (QuarkusClassLoader:Quarkus Base Runtime ClassLoader: TEST for JUnitQuarkusTest-io.quarkus.grpc.test.utils.VertxGRPCTestProfile (QuarkusTest)@d43ac5e3) or the thread context classloader (jdk.internal.loader.ClassLoaders$AppClassLoader@b621dffa) was incorrect.at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1685)...❌io.quarkus.grpc.example.streaming.VertxVirtualThreadTest.testGrpcClient -History -More details -Source on GitHub
java.lang.AssertionError: 1 expectation failed.Expected status code <200> but was <500>.at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:73)at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:108)Flaky tests -Develocity
⚙️ JVM Tests - JDK 21
📦 extensions/smallrye-reactive-messaging/deployment
❌io.quarkus.smallrye.reactivemessaging.hotreload.ConnectorChangeTest.testUpdatingConnector -History
Expecting actual: ["-6","-8","-9","-10","-11","-12","-13","-14"] to start with: ["-6", "-7", "-8", "-9"]-java.lang.AssertionError
java.lang.AssertionError: Expecting actual: ["-6","-8","-9","-10","-11","-12","-13","-14"]to start with: ["-6", "-7", "-8", "-9"]at io.quarkus.smallrye.reactivemessaging.hotreload.ConnectorChangeTest.testUpdatingConnector(ConnectorChangeTest.java:41)⚙️ Gradle Tests - JDK 17 Windows
📦 integration-tests/gradle
❌io.quarkus.gradle.run.AdditionalSourceSetAsDependencyTest.main -History
Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 1 minutes 30 seconds.-org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 1 minutes 30 seconds.at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)at io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:164)at io.quarkus.gradle.devmode.QuarkusDevGradleTestBase.getHttpResponse(QuarkusDevGradleTestBase.java:165)⚙️ MicroProfile TCKs Tests
📦 tcks/microprofile-lra
❌org.eclipse.microprofile.lra.tck.TckRecoveryTests.testCancelWhenParticipantIsUnavailable -History
Expecting the metric Compensated callback was called Expected: a value equal to or greater than <1> but: <0> was less than <1>-java.lang.AssertionError
java.lang.AssertionError: Expecting the metric Compensated callback was calledExpected: a value equal to or greater than <1> but: <0> was less than <1>at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)at org.eclipse.microprofile.lra.tck.TckRecoveryTests.assertMetricCallbackCalled(TckRecoveryTests.java:210)at org.eclipse.microprofile.lra.tck.TckRecoveryTests.testCancelWhenParticipantIsUnavailable(TckRecoveryTests.java:195)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Summary
This PR introduces support for serving static files from a local directory,
configurable via
quarkus.http.local-static-resources.*.New configuration
quarkus.http.local-static-resources.enabled=true
quarkus.http.local-static-resources.path=/local-static/
quarkus.http.local-static-resources.directory=local-static
Tests
Added
LocalStaticResourcesTestwhich verifies: