-
Notifications
You must be signed in to change notification settings - Fork 2
Implement configurable filter pipeline (global + per‑route filters) #11
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Ericthilen
wants to merge
52
commits into
ithsjava25:main
from
ithsjava25:Implement-Configurable-Filter-Pipeline-(Global-+-Per‑Route-Filters)
The head ref may contain hidden characters: "Implement-Configurable-Filter-Pipeline-(Global-+-Per\u2011Route-Filters)"
Closed
Changes from 13 commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
98b40a1
Initial commit med all kod (#16)
Kathify c1b5f70
build: configure pom.xml with needed plugin/tools. (#19)
eeebbaandersson bf4d977
Initial commit för tcp-server (#17)
Kathify 148411e
Issue #12 (#21)
Xeutos 9ac7b57
Feature/docker image builder issue#11 (#25)
Xeutos 875d1ef
Feature/http parse headers (#18)
FeFFe1996 9289c7d
Feature/http response builder (#24)
JohanHiths 6bdb1ef
Feature/http parse request line (#20)
FeFFe1996 781e34a
Add Bucket4j dependency in pom file (#40)
gvaguirres 511b5ee
Add support for serving static files (#42)
codebyNorthsteep aaeba6d
Updates pom.xml, with jackson-dependencies, for config file (#48)
fredrikmohlen 524f33c
* Move HTTP handling to a dedicated ConnectionHandler (#50)
donne41 b9382a3
ensure global detection for empty route patterns
Ericthilen 7d55536
larify global vs route-specific registrations
Ericthilen e712b08
add support for exact and /prefix/* matching
Ericthilen b8a9754
add coverage for global, route-specific, ordering and short-circuit
Ericthilen 114bd2e
configurable global and route-specific filters with ordering
Ericthilen b40a4d1
changed package
Ericthilen a9a12bf
removed from branch
Ericthilen 9bc1eed
Add missing tests for configurable filter pipeline
viktorlindell12 afbe07f
Merge pull request #57 from ithsjava25/fix/filter-pipeline-tests
viktorlindell12 8cc69d8
Feature/13 implement config file (#22)
MartinStenhagen c0e3de6
Enhancement/404 page not found (#53)
codebyNorthsteep aba21a5
Refactor filter pipeline: sort FilterRegistration directly by order
Ericthilen 9334691
Fix RoutePattern wildcard to match base path (/api/* matches /api)
Ericthilen 89c5ddf
Resolve TcpServer merge conflict (keep main version)
viktorlindell12 c78610c
Restore App entry point and basic tests from main
viktorlindell12 bcb828c
Feature/issue59 run configloader (#61)
MartinStenhagen 61c3be0
Bump org.apache.maven.plugins:maven-dependency-plugin (#6) (#55)
Ericthilen 945d32b
23 define and create filter interface (#46)
eraiicphu 3128ac7
Feature/mime type detection #8 (#47)
gitnes94 d4e7481
Dockerfile update (#52) (#63)
Xeutos 5c80eaa
Added comprehensive README.MD (#67)
gitnes94 fcdcadb
Add short-circuit tests for configurable filter pipeline
viktorlindell12 f6dc32e
Add tests for response-phase and global-vs-route ordering
viktorlindell12 afa9373
pom fix - no changes
viktorlindell12 6950c14
Fix: Path traversal vulnerability in StaticFileHandler (#65)
apaegs 78f7e21
Resolve port: CLI > config > default (#29)
viktorlindell12 86f2ba7
Refactor status codes to constants #71 (#77)
eeebbaandersson 3e3a217
Merge remote-tracking branch 'origin/main' into Implement-Configurabl…
viktorlindell12 103178a
fixed file path (#86)
gurkvatten e72f073
Fix path in Dockerfile for `www` directory copy operation (#87)
codebyNorthsteep ff4cd12
Feature/27 ipfilter (#70)
apaegs 7652687
Feature/LocaleFilter (#81)
AntonAhlqvist d6f1d26
Create LoggFilter (#83)
AnnaZiafar 27e627c
Return status code 500 (#79)
AnnaZiafar db0c574
Feature/LocaleFilterCookie (#92)
AntonAhlqvist b7154fa
added brotli4j (#94)
gurkvatten fa1599a
Issue/69 remove html concat (#73)
Rickank 032d91d
Merge remote-tracking branch 'origin/main' into Implement-Configurabl…
viktorlindell12 abed9f6
Align server filter pipeline with main FilterChainImpl and HttpRespon…
viktorlindell12 6de96b2
Align filter pipeline with main filter chain and harden immutability
viktorlindell12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| name: Java CI with Maven | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ "main" ] | ||
| pull_request: | ||
| branches: [ "main" ] | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Get Java Version | ||
| run: | | ||
| JAVA_VERSION=$(mvn help:evaluate "-Dexpression=maven.compiler.release" -q -DforceStdout) | ||
| echo "JAVA_VERSION=$JAVA_VERSION" >> $GITHUB_ENV | ||
|
|
||
| - name: Set up JDK ${{ env.JAVA_VERSION }} | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: ${{ env.JAVA_VERSION }} | ||
| distribution: 'temurin' | ||
| cache: maven | ||
|
|
||
| - name: Compile with Maven | ||
| run: mvn -B compile --file pom.xml | ||
|
|
||
| - name: Test with Maven | ||
| run: mvn -B test --file pom.xml | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| name: Publish Docker Image to Github Packages on Release | ||
| on: | ||
| release: | ||
| types: | ||
| - published | ||
| jobs: | ||
| publish: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| steps: | ||
| - uses: actions/checkout@v6.0.2 | ||
| - uses: docker/setup-qemu-action@v3.7.0 | ||
| - uses: docker/setup-buildx-action@v3.12.0 | ||
| - name: Log in to GHCR | ||
| uses: docker/login-action@v3.7.0 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Extract metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5.10.0 | ||
| with: | ||
| images: ghcr.io/ithsjava25/webserver | ||
| - name: Build and push | ||
| uses: docker/build-push-action@v6.18.0 | ||
| with: | ||
| context: . | ||
| push: true | ||
| platforms: linux/amd64, linux/arm64 | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
146 changes: 146 additions & 0 deletions
146
src/main/java/org/example/server/ConfigurableFilterPipeline.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| package org.example.server; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.Comparator; | ||
| import java.util.List; | ||
|
|
||
| public class ConfigurableFilterPipeline { | ||
|
|
||
| private final List<FilterRegistration> registrations; | ||
|
|
||
| public ConfigurableFilterPipeline(List<FilterRegistration> registrations) { | ||
| this.registrations = registrations; | ||
| } | ||
|
|
||
| public HttpResponse execute(HttpRequest request, TerminalHandler handler) { | ||
|
|
||
| List<HttpFilter> globalFilters = new ArrayList<>(); | ||
| List<HttpFilter> routeFilters = new ArrayList<>(); | ||
|
|
||
| for (FilterRegistration reg : registrations) { | ||
|
|
||
| if (reg.isGlobal()) { | ||
| globalFilters.add(reg.filter()); | ||
| } else { | ||
| if (matchesAny(reg.routePatterns(), request.path())) { | ||
| routeFilters.add(reg.filter()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Collections.sort(globalFilters, new Comparator<HttpFilter>() { | ||
| @Override | ||
| public int compare(HttpFilter f1, HttpFilter f2) { | ||
| return Integer.compare(getOrder(f1), getOrder(f2)); | ||
| } | ||
| }); | ||
|
|
||
| Collections.sort(routeFilters, new Comparator<HttpFilter>() { | ||
| @Override | ||
| public int compare(HttpFilter f1, HttpFilter f2) { | ||
| return Integer.compare(getOrder(f1), getOrder(f2)); | ||
| } | ||
| }); | ||
|
|
||
| List<HttpFilter> allFilters = new ArrayList<>(); | ||
| allFilters.addAll(globalFilters); | ||
| allFilters.addAll(routeFilters); | ||
|
|
||
| return buildChain(allFilters, handler).next(request); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| private boolean matchesAny(List<String> patterns, String path) { | ||
| if (patterns == null) return false; | ||
|
|
||
| for (String pattern : patterns) { | ||
| if (RoutePattern.matches(pattern, path)) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| private FilterChain buildChain(List<HttpFilter> filters, TerminalHandler handler) { | ||
|
|
||
| FilterChain chain = new FilterChain() { | ||
| @Override | ||
| public HttpResponse next(HttpRequest request) { | ||
| return handler.handle(request); | ||
| } | ||
| }; | ||
|
|
||
| for (int i = filters.size() - 1; i >= 0; i--) { | ||
|
|
||
| HttpFilter currentFilter = filters.get(i); | ||
| FilterChain nextChain = chain; | ||
|
|
||
| chain = new FilterChain() { | ||
| @Override | ||
| public HttpResponse next(HttpRequest request) { | ||
| return currentFilter.handle(request, nextChain); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| return chain; | ||
| } | ||
|
|
||
| private int getOrder(HttpFilter filter) { | ||
| for (FilterRegistration reg : registrations) { | ||
| if (reg.filter() == filter) { | ||
| return reg.order(); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| class HttpRequest { | ||
| private final String method; | ||
| private final String path; | ||
|
|
||
| public HttpRequest(String method, String path) { | ||
| this.method = method; | ||
| this.path = path; | ||
| } | ||
|
|
||
| public String path() { | ||
| return path; | ||
| } | ||
|
|
||
| public String getMethod() { | ||
| return method; | ||
| } | ||
| } | ||
|
|
||
| class HttpResponse { | ||
| private final int statusCode; | ||
| private final String body; | ||
|
|
||
| public HttpResponse(int statusCode, String body) { | ||
| this.statusCode = statusCode; | ||
| this.body = body; | ||
| } | ||
|
|
||
| public int getStatusCode() { | ||
| return statusCode; | ||
| } | ||
|
|
||
| public String getBody() { | ||
| return body; | ||
| } | ||
| } | ||
|
|
||
| interface HttpFilter { | ||
| HttpResponse handle(HttpRequest request, FilterChain chain); | ||
| } | ||
|
|
||
| interface FilterChain { | ||
| HttpResponse next(HttpRequest request); | ||
| } | ||
|
|
||
| interface TerminalHandler { | ||
| HttpResponse handle(HttpRequest request); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package org.example.server; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record FilterRegistration( | ||
| HttpFilter filter, | ||
| int order, | ||
| List<String> routePatterns | ||
| ) { | ||
|
|
||
| public boolean isGlobal() { | ||
| return routePatterns == null || routePatterns.isEmpty(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package org.example.server; | ||
|
|
||
| public final class RoutePattern { | ||
|
|
||
| private RoutePattern() {} | ||
|
|
||
| public static boolean matches(String pattern, String path) { | ||
| if (pattern == null || path == null) return false; | ||
|
|
||
| if (pattern.endsWith("/*")) { | ||
| String prefix = pattern.substring(0, pattern.length() - 1); | ||
| return path.startsWith(prefix); | ||
| } | ||
|
|
||
| return pattern.equals(path); | ||
| } | ||
| } |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Spotless format check is not enforced in CI.
The
spotless-maven-plugincheck is bound to theverifyphase inpom.xml, but CI only runscompileandtest. Formatting violations will go undetected. Either add a separatemvn spotless:checkstep or change the test step to runmvn -B verify.Proposed fix: add a Spotless check step
- name: Test with Maven run: mvn -B test --file pom.xml + + - name: Check formatting with Spotless + run: mvn -B spotless:check --file pom.xml📝 Committable suggestion
🤖 Prompt for AI Agents