Conversation
feat: add regex support and enforce 301/302 redirects
900dcc3 to
3bd0419
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/main/java/org/example/filter/redirect/RedirectRulesLoader.java (2)
26-31: Document that*matches only within a single path segment.
[^/]*excludes the/separator, so/docs/*matches/docs/foobut not/docs/foo/bar. Users expecting glob-style**will get silent non-matching behaviour. A brief Javadoc note oncompileSourcePatternorwildcardToRegexclarifying this constraint prevents confusion.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/redirect/RedirectRulesLoader.java` around lines 26 - 31, Add a brief Javadoc note to the pattern compilation helper (e.g., compileSourcePattern and/or wildcardToRegex) stating that the single asterisk '*' is translated to a segment-local pattern that excludes the path separator (i.e., uses [^/]*), so '/docs/*' matches '/docs/foo' but not '/docs/foo/bar', and that glob-style recursive matching ('**') is not supported by this implementation; document this constraint and behavior so callers won't be surprised by silent non-matches.
34-45: Accumulate literal runs before quoting to produce cleaner patterns.Calling
Pattern.quote(String.valueOf(c))for every non-*character generates a\Qx\Ewrapper around each individual character (e.g.,/docs/*→\Q/\E\Qd\E\Qo\E\Qc\E\Qs\E\Q/\E[^/]*). Accumulating consecutive literals into a single buffer and quoting the whole segment is equivalent and much more readable in logs/debuggers.♻️ Proposed refactor
private static String wildcardToRegex(String wildcard) { StringBuilder sb = new StringBuilder(); + StringBuilder literal = new StringBuilder(); for (int i = 0; i < wildcard.length(); i++) { char c = wildcard.charAt(i); if (c == '*') { - sb.append("[^/]*"); + if (!literal.isEmpty()) { + sb.append(Pattern.quote(literal.toString())); + literal.setLength(0); + } + sb.append("[^/]*"); } else { - sb.append(Pattern.quote(String.valueOf(c))); + literal.append(c); } } + if (!literal.isEmpty()) { + sb.append(Pattern.quote(literal.toString())); + } return sb.toString(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/redirect/RedirectRulesLoader.java` around lines 34 - 45, The wildcardToRegex method currently quotes each non-asterisk character individually which produces many \Q...\E fragments; modify wildcardToRegex in RedirectRulesLoader to accumulate consecutive literal characters in a temporary StringBuilder and only call Pattern.quote once per run: iterate over wildcard, when you see a '*' flush the literal buffer (if non-empty) by appending Pattern.quote(buffer.toString()) to the main sb and clear it, then append the existing "[^/]*" for '*'; after the loop flush any remaining literal buffer similarly so the final regex has consolidated quoted runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/org/example/filter/redirect/RedirectRule.java`:
- Around line 17-19: The targetUrl validation in RedirectRule only checks for
CR/LF but misses null-byte characters which can also terminate headers; update
the validation in the RedirectRule constructor (or where targetUrl is checked)
to also detect '\0' (null character) — e.g., check targetUrl for '\r', '\n' or
'\0' (or use contains("\0")/indexOf('\u0000') >= 0) and throw the same
IllegalArgumentException("targetUrl must not contain CR/LF") (adjust message to
mention null byte if desired) when found.
---
Nitpick comments:
In `@src/main/java/org/example/filter/redirect/RedirectRulesLoader.java`:
- Around line 26-31: Add a brief Javadoc note to the pattern compilation helper
(e.g., compileSourcePattern and/or wildcardToRegex) stating that the single
asterisk '*' is translated to a segment-local pattern that excludes the path
separator (i.e., uses [^/]*), so '/docs/*' matches '/docs/foo' but not
'/docs/foo/bar', and that glob-style recursive matching ('**') is not supported
by this implementation; document this constraint and behavior so callers won't
be surprised by silent non-matches.
- Around line 34-45: The wildcardToRegex method currently quotes each
non-asterisk character individually which produces many \Q...\E fragments;
modify wildcardToRegex in RedirectRulesLoader to accumulate consecutive literal
characters in a temporary StringBuilder and only call Pattern.quote once per
run: iterate over wildcard, when you see a '*' flush the literal buffer (if
non-empty) by appending Pattern.quote(buffer.toString()) to the main sb and
clear it, then append the existing "[^/]*" for '*'; after the loop flush any
remaining literal buffer similarly so the final regex has consolidated quoted
runs.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/org/example/filter/redirect/RedirectFilter.javasrc/main/java/org/example/filter/redirect/RedirectRule.javasrc/main/java/org/example/filter/redirect/RedirectRulesLoader.javasrc/main/resources/.gitkeepsrc/test/java/org/example/filter/redirect/RedirectFilterTest.javasrc/test/resources/.gitkeep
🚧 Files skipped from review as they are similar to previous changes (2)
- src/test/java/org/example/filter/redirect/RedirectFilterTest.java
- src/main/java/org/example/filter/redirect/RedirectFilter.java
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/org/example/filter/redirect/RedirectRule.java (1)
36-43: Consider implementingequalsandhashCode.
RedirectRuleis a value object with three final fields. Without overridingequals/hashCode, two logically identical rules won't be considered equal inSet,Map, orcontainschecks, which can cause silent deduplication failures if the rule list is ever placed in a collection.♻️ Proposed addition
+ `@Override` + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RedirectRule other)) return false; + return statusCode == other.statusCode + && targetUrl.equals(other.targetUrl) + && sourcePattern.pattern().equals(other.sourcePattern.pattern()) + && sourcePattern.flags() == other.sourcePattern.flags(); + } + + `@Override` + public int hashCode() { + return Objects.hash(sourcePattern.pattern(), sourcePattern.flags(), targetUrl, statusCode); + } + `@Override` public String toString() {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/org/example/filter/redirect/RedirectRule.java` around lines 36 - 43, Add proper value semantics to RedirectRule by implementing equals(Object) and hashCode() that consider the three final fields: sourcePattern, targetUrl, and statusCode. In equals, check identity, class, then compare sourcePattern and targetUrl with Objects.equals and compare primitive statusCode directly; in hashCode return Objects.hash(sourcePattern, targetUrl, statusCode). Ensure both methods are declared in the RedirectRule class alongside the existing toString so instances behave correctly in Sets/Maps and contains checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/org/example/filter/redirect/RedirectRule.java`:
- Around line 22-24: The validation in RedirectRule currently rejects 307 and
308; update the check that inspects statusCode in class RedirectRule (the block
that throws IllegalArgumentException) to allow HTTP 301, 302, 307 and 308 (i.e.,
accept 301 || 302 || 307 || 308) and adjust the IllegalArgumentException message
to list the allowed codes (301, 302, 307, 308) so callers get accurate guidance;
ensure any surrounding logic that assumes only 301/302 still works with 307/308
(preserve method semantics).
---
Nitpick comments:
In `@src/main/java/org/example/filter/redirect/RedirectRule.java`:
- Around line 36-43: Add proper value semantics to RedirectRule by implementing
equals(Object) and hashCode() that consider the three final fields:
sourcePattern, targetUrl, and statusCode. In equals, check identity, class, then
compare sourcePattern and targetUrl with Objects.equals and compare primitive
statusCode directly; in hashCode return Objects.hash(sourcePattern, targetUrl,
statusCode). Ensure both methods are declared in the RedirectRule class
alongside the existing toString so instances behave correctly in Sets/Maps and
contains checks.
…o feature/url-redirect-filter
Summary by CodeRabbit
New Features
Tests