All Downloads are FREE. Search and download functionalities are using the official Maven repository.

netflix.karyon.transport.http.ServletStyleUriConstraintKey Maven / Gradle / Ivy

There is a newer version: 2.9.2
Show newest version
package netflix.karyon.transport.http;

import io.reactivex.netty.protocol.http.server.HttpServerRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides constraint implementation for {@link netflix.karyon.transport.interceptor.InterceptorKey} similar to java servlet specifications. 

* The following types of constraints are supported: *
  • Exact uri mapping: Give the exact string that should match the URI path of the incoming request. eg: "/myresource/foo" will match ALL the URIs:
    • "/myresource/foo"
    • "/myresource/foo/"
  • Prefix uri mapping: Give the prefix in the URI path you want to match, ending with a "*". eg: "/myresource/foo/*" will match ALL the URIs:
    • "/myresource/foo/bar"
    • "/myresource/foo/"
    • "/myresource/foo"
* * In any of the pattersn above the leading slash in the constraint is optional, i.e., "/myresource/foo" is equivalent to * "myresource/foo". * * As compared to servlets/web applications there are no context paths of an application so the URI path has to be * absolute.
* * The request URI path is as retrieved using: {@link HttpKeyEvaluationContext#getRequestUriPath(HttpServerRequest)} * * @author Nitesh Kant */ public class ServletStyleUriConstraintKey implements HttpInterceptorKey { private static final Logger logger = LoggerFactory.getLogger(ServletStyleUriConstraintKey.class); private final Matcher matcher; private final String contextPath; public ServletStyleUriConstraintKey(final String constraint, final String contextPath) { if (null == constraint) { throw new NullPointerException("Constraint can not be null."); } this.contextPath = contextPath.startsWith("/") ? contextPath : '/' + contextPath; // uri & constraint always starts with a / String normalizedConstraint = constraint; if (!constraint.startsWith("/")) { // URI always comes with a leading '/' normalizedConstraint = '/' + constraint; } if (normalizedConstraint.startsWith("/*.")) { matcher = new ExtensionMatcher( constraint); // not normalizedConstraint as then we will have to ignore the first character. } else if (normalizedConstraint.endsWith("/*")) { matcher = new PrefixMatcher(normalizedConstraint.substring(0, normalizedConstraint.length() - 1), new Matcher(normalizedConstraint.substring(0, normalizedConstraint.length() - 2), null)); // Prefix match removing * or exact match removing /* } else if (normalizedConstraint.endsWith("*")) { matcher = new PrefixMatcher(normalizedConstraint.substring(0, normalizedConstraint.length() - 1), null); } else { matcher = new Matcher(normalizedConstraint, new Matcher(normalizedConstraint + '/', null)); } } /** * This must be called if and only if {@link #apply(HttpServerRequest, HttpKeyEvaluationContext)} * returned for the same request. * * @param request Request which satisfies this key. * @param context The key evaluation context. * * @return The servlet path. */ public String getServletPath(HttpServerRequest request, HttpKeyEvaluationContext context) { String requestUriPath = context.getRequestUriPath(request); if (null != requestUriPath) { return matcher.getServletPath(requestUriPath); } return ""; } @Override public boolean apply(HttpServerRequest request, HttpKeyEvaluationContext context) { String requestUriPath = context.getRequestUriPath(request); boolean matches = false; if (null != requestUriPath) { matches = matcher.match(requestUriPath); } return matches; } private class Matcher { protected final String constraint; protected final String constraintWithoutContextPath; private final Matcher nextMatcher; private Matcher(String constraint, Matcher nextMatcher) { this.constraint = constraint; constraintWithoutContextPath = constraint.isEmpty() ? constraint : constraint.substring(contextPath.length()); this.nextMatcher = nextMatcher; } protected boolean match(String requestUriPath) { return isMatching(requestUriPath, false) || null != nextMatcher && nextMatcher.match(requestUriPath); } protected boolean isMatching(String requestUriPath, boolean noLog) { boolean matches = requestUriPath.equals(constraint); if (!noLog && logger.isDebugEnabled()) { logger.debug("Exact match result for servlet style uri constraint for uri path {} and constraint {} : {}", requestUriPath, constraint, matches); } return matches; } public String getServletPath(String requestUriPath) { if (requestUriPath.equals(constraint)) { // exact match & hence not required to query the next matcher. return constraintWithoutContextPath; } return null != nextMatcher ? nextMatcher.getServletPath(requestUriPath) : ""; } @Override public String toString() { return "Matcher{" + "constraint='" + constraint + '\'' + ", nextMatcher=" + nextMatcher + '}'; } } private class PrefixMatcher extends Matcher { private PrefixMatcher(String prefix, Matcher nextMatcher) { super(prefix, nextMatcher); } @Override protected boolean isMatching(String requestUriPath, boolean noLog) { boolean matches = requestUriPath.startsWith(constraint); if (!noLog && logger.isDebugEnabled()) { logger.debug("Prefix match result for servlet style uri constraint for uri path {} and constraint {} : {}", requestUriPath, constraint, matches); } return matches; } @Override public String getServletPath(String requestUriPath) { if (isMatching(requestUriPath, true)) { return constraintWithoutContextPath.substring(0, constraintWithoutContextPath.length() - 1); // Leaving out the postfix of *, this is what we need. } return super.getServletPath(requestUriPath); } } private class ExtensionMatcher extends Matcher { private ExtensionMatcher(String constraint) { super(constraint.substring(1), null); // This matcher does a contains query removing the * prefix } @Override protected boolean isMatching(String requestUriPath, boolean noLog) { boolean matches = requestUriPath.contains(constraint);// The constructor removes the preciding * in the constraint. if (!noLog && logger.isDebugEnabled()) { logger.debug("Extension match result for servlet style uri constraint for uri path {} and constraint {} : {}", requestUriPath, constraint, matches); } return matches; } @Override public String getServletPath(String requestUriPath) { if (isMatching(requestUriPath, true)) { return ""; // Extension mapping does not have servlet path. } return super.getServletPath(requestUriPath); } } @Override public String toString() { return "ServletStyleUriConstraintKey{" + "matcher=" + matcher + '}'; } }