Jetty-12 Rewrite RuleProcessor (#8934)

* Rewrite RuleProcessor

This decouples the rewrite module from the `WrapperProcessor` class, which is being considered for significant refactoring or removal.
Having a module specific version of that class allows better code readability and a more appropriate API that avoids duplication request instances.

* Fixed javadoc

* Updates from review.

* Updates from review.
This commit is contained in:
Greg Wilkins 2022-11-25 14:27:21 +11:00 committed by GitHub
parent a0a8acd8b9
commit 09594361a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 128 additions and 100 deletions

View File

@ -35,7 +35,7 @@ public class RewriteCustomizer extends RuleContainer implements Customizer
try
{
// TODO: rule are able to complete the request/response, but customizers cannot.
Request.WrapperProcessor input = new Request.WrapperProcessor(request);
Processor input = new Processor(request);
return matchAndApply(input);
}
catch (IOException e)

View File

@ -26,23 +26,16 @@ import org.eclipse.jetty.util.URIUtil;
public class CompactPathRule extends Rule
{
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor request) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
String path = request.getHttpURI().getCanonicalPath();
String path = input.getHttpURI().getCanonicalPath();
String compacted = URIUtil.compactPath(path);
if (path.equals(compacted))
return null;
HttpURI uri = Request.newHttpURIFrom(request, compacted);
HttpURI uri = Request.newHttpURIFrom(input, compacted);
return new Request.WrapperProcessor(request)
{
@Override
public HttpURI getHttpURI()
{
return uri;
}
};
return new HttpURIProcessor(input, uri);
}
}

View File

@ -76,9 +76,8 @@ public class CookiePatternRule extends PatternRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
public Processor apply(Processor input) throws IOException
{
// TODO: fix once Request.getCookies() is implemented (currently always returns null)
// Check that cookie is not already set
List<HttpCookie> cookies = Request.getCookies(input);
if (cookies != null)
@ -90,13 +89,13 @@ public class CookiePatternRule extends PatternRule
}
}
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback) throws Exception
public void process(Response response, Callback callback) throws Exception
{
Response.addCookie(response, new HttpCookie(_name, _value));
super.process(this, response, callback);
super.process(response, callback);
}
};
}

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.server.Request;
public class ForceRequestHeaderValueRule extends Rule
{
@ -44,7 +43,7 @@ public class ForceRequestHeaderValueRule extends Rule
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
HttpFields headers = input.getHeaders();
String existingValue = headers.get(headerName);
@ -60,7 +59,7 @@ public class ForceRequestHeaderValueRule extends Rule
HttpFields.Mutable newHeaders = HttpFields.build(headers);
newHeaders.remove(headerName);
newHeaders.add(headerName, headerValue);
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public HttpFields getHeaders()

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.rewrite.handler;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.Request;
/**
* <p>Sets the request URI scheme, by default {@code https}.</p>
@ -34,16 +33,9 @@ public class ForwardedSchemeHeaderRule extends HeaderRule
}
@Override
protected Request.WrapperProcessor apply(Request.WrapperProcessor input, String value)
protected Processor apply(Processor input, String value)
{
HttpURI newURI = HttpURI.build(input.getHttpURI()).scheme(getScheme());
return new Request.WrapperProcessor(input)
{
@Override
public HttpURI getHttpURI()
{
return newURI;
}
};
return new HttpURIProcessor(input, newURI);
}
}

View File

@ -15,7 +15,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.Name;
@ -74,18 +73,18 @@ public class HeaderPatternRule extends PatternRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
public Processor apply(Processor input) throws IOException
{
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback) throws Exception
public void process(Response response, Callback callback) throws Exception
{
if (isAdd())
response.getHeaders().add(getHeaderName(), getHeaderValue());
else
response.getHeaders().put(getHeaderName(), getHeaderValue());
super.process(ignored, response, callback);
super.process(response, callback);
}
};
}

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import java.util.regex.Matcher;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.Name;
@ -75,18 +74,18 @@ public class HeaderRegexRule extends RegexRule
}
@Override
protected Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher) throws IOException
protected Processor apply(Processor input, Matcher matcher) throws IOException
{
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback) throws Exception
public void process(Response response, Callback callback) throws Exception
{
if (isAdd())
response.getHeaders().add(getHeaderName(), matcher.replaceAll(getHeaderValue()));
else
response.getHeaders().put(getHeaderName(), matcher.replaceAll(getHeaderValue()));
super.process(ignored, response, callback);
super.process(response, callback);
}
};
}

View File

@ -15,8 +15,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.server.Request;
/**
* <p>Abstract rule that matches against request headers.</p>
*/
@ -50,7 +48,7 @@ public abstract class HeaderRule extends Rule
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
String value = input.getHeaders().get(getHeaderName());
if (value == null)
@ -69,7 +67,7 @@ public abstract class HeaderRule extends Rule
* @return the possibly wrapped {@code Request} and {@code Processor}
* @throws IOException if applying the rule failed
*/
protected abstract Request.WrapperProcessor apply(Request.WrapperProcessor input, String value) throws IOException;
protected abstract Processor apply(Processor input, String value) throws IOException;
@Override
public String toString()

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.StringUtil;
@ -75,7 +74,7 @@ public class InvalidURIRule extends Rule
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
String path = input.getHttpURI().getDecodedPath();
@ -91,12 +90,12 @@ public class InvalidURIRule extends Rule
return null;
}
private Request.WrapperProcessor apply(Request.WrapperProcessor input)
private Processor apply(Processor input)
{
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback)
public void process(Response response, Callback callback)
{
String message = getMessage();
if (StringUtil.isBlank(message))

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
import org.eclipse.jetty.server.Request;
/**
* <p>Abstract rule that uses the Servlet pattern syntax via
@ -46,7 +45,7 @@ public abstract class PatternRule extends Rule
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
if (ServletPathSpec.match(_pattern, input.getHttpURI().getPath()))
return apply(input);
@ -60,7 +59,7 @@ public abstract class PatternRule extends Rule
* @return the possibly wrapped {@code Request} and {@code Processor}
* @throws IOException if applying the rule failed
*/
protected abstract Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException;
protected abstract Processor apply(Processor input) throws IOException;
@Override
public String toString()

View File

@ -77,12 +77,12 @@ public class RedirectPatternRule extends PatternRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
public Processor apply(Processor input) throws IOException
{
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback)
public void process(Response response, Callback callback)
{
String location = getLocation();
response.setStatus(getStatusCode());

View File

@ -76,12 +76,12 @@ public class RedirectRegexRule extends RegexRule
}
@Override
protected Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher) throws IOException
protected Processor apply(Processor input, Matcher matcher) throws IOException
{
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback)
public void process(Response response, Callback callback)
{
String target = matcher.replaceAll(getLocation());
response.setStatus(_statusCode);

View File

@ -17,8 +17,6 @@ import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.server.Request;
/**
* <p>Abstract rule that uses the regular expression syntax for path pattern matching.</p>
*/
@ -54,7 +52,7 @@ public abstract class RegexRule extends Rule
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
String target = input.getHttpURI().getPathQuery();
Matcher matcher = _regex.matcher(target);
@ -71,7 +69,7 @@ public abstract class RegexRule extends Rule
* @return the possibly wrapped {@code Request} and {@code Processor}
* @throws IOException if applying the rule failed
*/
protected abstract Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher) throws IOException;
protected abstract Processor apply(Processor input, Matcher matcher) throws IOException;
@Override
public String toString()

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.StringUtil;
@ -76,15 +75,15 @@ public class ResponsePatternRule extends PatternRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
public Processor apply(Processor input) throws IOException
{
if (getCode() < HttpStatus.CONTINUE_100)
return null;
return new Request.WrapperProcessor(input)
return new Processor(input)
{
@Override
public void process(Request ignored, Response response, Callback callback)
public void process(Response response, Callback callback)
{
String message = getMessage();
if (StringUtil.isBlank(message))

View File

@ -108,8 +108,8 @@ public class RewriteHandler extends Handler.Wrapper
if (!isStarted())
return null;
Request.WrapperProcessor input = new Request.WrapperProcessor(request);
Request.WrapperProcessor output = _rules.matchAndApply(input);
Rule.Processor input = new Rule.Processor(request);
Rule.Processor output = _rules.matchAndApply(input);
// No rule matched, call super with the original request.
if (output == null)

View File

@ -17,7 +17,6 @@ import java.io.IOException;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.Name;
import org.slf4j.Logger;
@ -64,7 +63,7 @@ public class RewritePatternRule extends PatternRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
public Processor apply(Processor input) throws IOException
{
HttpURI httpURI = input.getHttpURI();
String newQuery = URIUtil.addQueries(httpURI.getQuery(), _query);
@ -72,14 +71,7 @@ public class RewritePatternRule extends PatternRule
HttpURI newURI = HttpURI.build(httpURI, newPath, httpURI.getParam(), newQuery);
if (LOG.isDebugEnabled())
LOG.debug("rewriting {} to {}", httpURI, newURI);
return new Request.WrapperProcessor(input)
{
@Override
public HttpURI getHttpURI()
{
return newURI;
}
};
return new HttpURIProcessor(input, newURI);
}
@Override

View File

@ -17,7 +17,6 @@ import java.io.IOException;
import java.util.regex.Matcher;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.annotation.Name;
/**
@ -50,20 +49,13 @@ public class RewriteRegexRule extends RegexRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher) throws IOException
public Processor apply(Processor input, Matcher matcher) throws IOException
{
HttpURI httpURI = input.getHttpURI();
String replacedPath = matcher.replaceAll(replacement);
HttpURI newURI = HttpURI.build(httpURI, replacedPath);
return new Request.WrapperProcessor(input)
{
@Override
public HttpURI getHttpURI()
{
return newURI;
}
};
return new HttpURIProcessor(input, newURI);
}
@Override

View File

@ -15,7 +15,10 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
/**
* <p>An abstract rule that, upon matching a certain condition, may wrap
@ -32,7 +35,7 @@ public abstract class Rule
* @return the possibly wrapped {@code Request} and {@code Processor}, or {@code null} if the rule did not match
* @throws IOException if applying the rule failed
*/
public abstract Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException;
public abstract Processor matchAndApply(Processor input) throws IOException;
/**
* @return when {@code true}, rules after this one are not processed
@ -55,4 +58,75 @@ public abstract class Rule
{
return "%s@%x[terminating=%b]".formatted(getClass().getSimpleName(), hashCode(), isTerminating());
}
/**
* <p>A {@link Request.Wrapper} that is also a {@link org.eclipse.jetty.server.Request.Processor},
* used to chain a sequence of {@link Rule}s together.
* The tuple is initialized with only the request, then the processor is
* then passed to a chain of rules before the ultimate processor is
* passed in {@link #wrapProcessor(Processor)}. Finally, the response
* and callback are provided in a call to {@link #process(Request, Response, Callback)},
* which calls the {@link #process(Response, Callback)}.</p>
*/
public static class Processor extends Request.Wrapper implements Request.Processor
{
private volatile Processor _processor;
public Processor(Request request)
{
super(request);
}
@Override
public void process(Request request, Response response, Callback callback) throws Exception
{
process(response, callback);
}
/**
* <p>Processes this wrapped request together with the passed response and
* callback, using the processor set in {@link #wrapProcessor(Processor)}.
* This method should be extended if additional processing of the wrapped
* request is required.</p>
* @param response The response
* @param callback The callback
* @throws Exception If there is a problem processing
* @see #wrapProcessor(Processor)
*/
protected void process(Response response, Callback callback) throws Exception
{
Processor processor = _processor;
if (processor != null)
processor.process(this, response, callback);
}
/**
* <p>Wraps the given {@code Processor} within this instance and returns this instance.</p>
*
* @param processor the {@code Processor} to wrap
* @return this instance
*/
public Processor wrapProcessor(Processor processor)
{
_processor = processor;
return processor == null ? null : this;
}
}
public static class HttpURIProcessor extends Processor
{
private final HttpURI _uri;
public HttpURIProcessor(Request request, HttpURI uri)
{
super(request);
_uri = uri;
}
@Override
public HttpURI getHttpURI()
{
return _uri;
}
}
}

View File

@ -19,7 +19,6 @@ import java.util.Iterator;
import java.util.List;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.component.Dumpable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -104,7 +103,7 @@ public class RuleContainer extends Rule implements Iterable<Rule>, Dumpable
* or {@code null} if no rule matched
*/
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
String originalPathAttribute = getOriginalPathAttribute();
if (originalPathAttribute != null)
@ -121,7 +120,7 @@ public class RuleContainer extends Rule implements Iterable<Rule>, Dumpable
{
if (LOG.isDebugEnabled())
LOG.debug("applying {}", rule);
Request.WrapperProcessor output = rule.matchAndApply(input);
Processor output = rule.matchAndApply(input);
if (output == null)
{
if (LOG.isDebugEnabled())

View File

@ -15,8 +15,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.server.Request;
/**
* <p>If this rule matches, terminates the processing of other rules, allowing
* the request to be processed by the handlers after the {@link RewriteHandler}.</p>
@ -39,7 +37,7 @@ public class TerminatingPatternRule extends PatternRule
}
@Override
protected Request.WrapperProcessor apply(Request.WrapperProcessor input) throws IOException
protected Processor apply(Processor input) throws IOException
{
return input;
}

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import java.util.regex.Matcher;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.annotation.Name;
/**
@ -41,7 +40,7 @@ public class TerminatingRegexRule extends RegexRule
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher) throws IOException
public Processor apply(Processor input, Matcher matcher) throws IOException
{
return input;
}

View File

@ -55,7 +55,7 @@ public class VirtualHostRuleContainer extends RuleContainer
}
@Override
public Request.WrapperProcessor matchAndApply(Request.WrapperProcessor input) throws IOException
public Processor matchAndApply(Processor input) throws IOException
{
if (_virtualHosts.isEmpty())
return super.matchAndApply(input);

View File

@ -157,7 +157,7 @@ public class PatternRuleTest extends AbstractRuleTest
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input)
public Processor apply(Processor input)
{
_applied = true;
return input;

View File

@ -124,7 +124,7 @@ public class RegexRuleTest extends AbstractRuleTest
}
@Override
public Request.WrapperProcessor apply(Request.WrapperProcessor input, Matcher matcher)
public Processor apply(Processor input, Matcher matcher)
{
_applied = true;
return input;