/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package io.undertow.server.handlers;

import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.cache.LRUCache;
import io.undertow.util.PathMatcher;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

Handler that dispatches to a given handler based of a prefix match of the path.

This only matches a single level of a request, e.g if you have a request that takes the form:

/foo/bar

Author:Stuart Douglas
/** * Handler that dispatches to a given handler based of a prefix match of the path. * <p> * This only matches a single level of a request, e.g if you have a request that takes the form: * <p> * /foo/bar * <p> * * @author Stuart Douglas */
public class PathHandler implements HttpHandler { private final PathMatcher<HttpHandler> pathMatcher = new PathMatcher<>(); private final LRUCache<String, PathMatcher.PathMatch<HttpHandler>> cache; public PathHandler(final HttpHandler defaultHandler) { this(0); pathMatcher.addPrefixPath("/", defaultHandler); } public PathHandler(final HttpHandler defaultHandler, int cacheSize) { this(cacheSize); pathMatcher.addPrefixPath("/", defaultHandler); } public PathHandler() { this(0); } public PathHandler(int cacheSize) { if(cacheSize > 0) { cache = new LRUCache<>(cacheSize, -1, true); } else { cache = null; } } @Override public String toString() { Set<Entry<String,HttpHandler>> paths = pathMatcher.getPaths().entrySet(); if (paths.size() == 1) { return "path( " + paths.toArray()[0] + " )"; } else { return "path( {" + paths.stream().map(s -> s.getValue().toString()).collect(Collectors.joining(", ")) + "} )"; } } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { PathMatcher.PathMatch<HttpHandler> match = null; boolean hit = false; if(cache != null) { match = cache.get(exchange.getRelativePath()); hit = true; } if(match == null) { match = pathMatcher.match(exchange.getRelativePath()); } if (match.getValue() == null) { ResponseCodeHandler.HANDLE_404.handleRequest(exchange); return; } if(hit) { cache.add(exchange.getRelativePath(), match); } exchange.setRelativePath(match.getRemaining()); if(exchange.getResolvedPath().isEmpty()) { //first path handler, we can just use the matched part exchange.setResolvedPath(match.getMatched()); } else { //already something in the resolved path exchange.setResolvedPath(exchange.getResolvedPath() + match.getMatched()); } match.getValue().handleRequest(exchange); }
Adds a path prefix and a handler for that path. If the path does not start with a / then one will be prepended.

The match is done on a prefix bases, so registering /foo will also match /bar. Exact path matches are taken into account first.

If / is specified as the path then it will replace the default handler.

Params:
  • path – The path
  • handler – The handler
See Also:
Deprecated:Superseded by addPrefixPath(String, HttpHandler).
/** * Adds a path prefix and a handler for that path. If the path does not start * with a / then one will be prepended. * <p> * The match is done on a prefix bases, so registering /foo will also match /bar. Exact * path matches are taken into account first. * <p> * If / is specified as the path then it will replace the default handler. * * @param path The path * @param handler The handler * @see #addPrefixPath(String, io.undertow.server.HttpHandler) * @deprecated Superseded by {@link #addPrefixPath(String, io.undertow.server.HttpHandler)}. */
@Deprecated public synchronized PathHandler addPath(final String path, final HttpHandler handler) { return addPrefixPath(path, handler); }
Adds a path prefix and a handler for that path. If the path does not start with a / then one will be prepended.

The match is done on a prefix bases, so registering /foo will also match /foo/bar. Though exact path matches are taken into account before prefix path matches. So if an exact path match exists it's handler will be triggered.

If / is specified as the path then it will replace the default handler.

Params:
  • path – If the request contains this prefix, run handler.
  • handler – The handler which is activated upon match.
Returns:The resulting PathHandler after this path has been added to it.
/** * Adds a path prefix and a handler for that path. If the path does not start * with a / then one will be prepended. * <p> * The match is done on a prefix bases, so registering /foo will also match /foo/bar. * Though exact path matches are taken into account before prefix path matches. So * if an exact path match exists it's handler will be triggered. * <p> * If / is specified as the path then it will replace the default handler. * * @param path If the request contains this prefix, run handler. * @param handler The handler which is activated upon match. * @return The resulting PathHandler after this path has been added to it. */
public synchronized PathHandler addPrefixPath(final String path, final HttpHandler handler) { Handlers.handlerNotNull(handler); pathMatcher.addPrefixPath(path, handler); return this; }
If the request path is exactly equal to the given path, run the handler.

Exact paths are prioritized higher than prefix paths.

Params:
  • path – If the request path is exactly this, run handler.
  • handler – Handler run upon exact path match.
Returns:The resulting PathHandler after this path has been added to it.
/** * If the request path is exactly equal to the given path, run the handler. * <p> * Exact paths are prioritized higher than prefix paths. * * @param path If the request path is exactly this, run handler. * @param handler Handler run upon exact path match. * @return The resulting PathHandler after this path has been added to it. */
public synchronized PathHandler addExactPath(final String path, final HttpHandler handler) { Handlers.handlerNotNull(handler); pathMatcher.addExactPath(path, handler); return this; } @Deprecated public synchronized PathHandler removePath(final String path) { return removePrefixPath(path); } public synchronized PathHandler removePrefixPath(final String path) { pathMatcher.removePrefixPath(path); return this; } public synchronized PathHandler removeExactPath(final String path) { pathMatcher.removeExactPath(path); return this; } public synchronized PathHandler clearPaths() { pathMatcher.clearPaths(); return this; } }