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

reactor.netty.http.server.HttpPredicate Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright (c) 2011-2023 VMware, Inc. or its affiliates, All Rights Reserved.
 *
 * 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
 *
 *   https://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 reactor.netty.http.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import reactor.netty.internal.util.MapUtils;
import reactor.util.annotation.Nullable;

import static java.util.Objects.requireNonNull;

/**
 * A Predicate to match against ServerRequest.
 *
 * @author Stephane Maldini
 */
final class HttpPredicate
		implements Predicate, Function> {

	/**
	 * An alias for {@link HttpPredicate#http}.
	 * 

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for DELETE Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate delete(String uri) { return http(uri, null, HttpMethod.DELETE); } /** * An alias for {@link HttpPredicate#http}. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for GET Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate get(String uri) { return http(uri, null, HttpMethod.GET); } /** * An alias for {@link HttpPredicate#http}. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for HEAD Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate head(String uri) { return http(uri, null, HttpMethod.HEAD); } /** * Creates a {@link Predicate} based on a URI template. * This will listen for all Methods. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link HttpPredicate}. * * @see Predicate */ public static Predicate http(String uri, @Nullable HttpVersion protocol, HttpMethod method) { return new HttpPredicate(uri, protocol, method); } /** * An alias for {@link HttpPredicate#http}. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for OPTIONS Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate options(String uri) { return http(uri, null, HttpMethod.OPTIONS); } /** * An alias for {@link HttpPredicate#http}. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for POST Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate post(String uri) { return http(uri, null, HttpMethod.POST); } /** * An alias for {@link HttpPredicate#get} prefix ([prefix]/**), useful for file system * mapping. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for WebSocket Method. * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate prefix(String prefix) { return prefix(prefix, HttpMethod.GET); } /** * An alias for {@link HttpPredicate#get} prefix (/**), useful for file system mapping. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for WebSocket Method. * * @return The new {@link Predicate}. * * * @see Predicate */ public static Predicate prefix(String prefix, HttpMethod method) { requireNonNull(prefix, "Prefix must be provided"); requireNonNull(method, "method"); String target = prefix.startsWith("/") ? prefix : "/".concat(prefix); //target = target.endsWith("/") ? target : prefix.concat("/"); return new HttpPrefixPredicate(target, method); } /** * An alias for {@link HttpPredicate#http}. *

* Creates a {@link Predicate} based on a URI template filtering . *

* This will listen for PUT Method. * * @param uri The string to compile into a URI template and use for matching * * @return The new {@link Predicate}. * * @see Predicate */ public static Predicate put(String uri) { return http(uri, null, HttpMethod.PUT); } final HttpVersion protocol; final HttpMethod method; final String uri; final UriPathTemplate template; public HttpPredicate(String uri, @Nullable HttpVersion protocol, HttpMethod method) { this.protocol = protocol; this.uri = requireNonNull(uri, "uri"); this.method = requireNonNull(method, "method"); this.template = new UriPathTemplate(uri); } @Override public Map apply(Object key) { Map headers = template.match(key.toString()); if (null != headers && !headers.isEmpty()) { return headers; } return null; } @Override public final boolean test(HttpServerRequest key) { return (protocol == null || protocol.equals(key.version())) && method.equals(key.method()) && template.matches(key.uri()); } /** * Represents a URI template. A URI template is a URI-like String that contains * variables enclosed by braces ({, }), which can be * expanded to produce an actual URI. * * @author Arjen Poutsma * @author Juergen Hoeller * @author Jon Brisbin * @see RFC 6570: URI Templates */ static final class UriPathTemplate { private static final Pattern FULL_SPLAT_PATTERN = Pattern.compile("[\\*][\\*]"); private static final String FULL_SPLAT_REPLACEMENT = ".*"; private static final Pattern NAME_SPLAT_PATTERN = Pattern.compile("\\{([^/]+?)\\}[\\*][\\*]"); private static final Pattern NAME_PATTERN = Pattern.compile("\\{([^/]+?)\\}"); // JDK 6 doesn't support named capture groups private static final Pattern URL_PATTERN = Pattern.compile("(?:(\\w+)://)?((?:\\[.+?])|(? pathVariables = new ArrayList<>(); private final Pattern uriPattern; private static String getNameSplatReplacement(String name) { return "(?<" + name + ">.*)"; } private static String getNameReplacement(String name) { return "(?<" + name + ">[^\\/]*)"; } static String filterQueryParams(String uri) { int hasQuery = uri.lastIndexOf('?'); if (hasQuery != -1) { return uri.substring(0, hasQuery); } else { return uri; } } static String filterHostAndPort(String uri) { if (uri.startsWith("/")) { return uri; } else { Matcher matcher = URL_PATTERN.matcher(uri); if (matcher.matches()) { String path = matcher.group(4); return path == null ? "/" : path; } else { throw new IllegalArgumentException("Unable to parse url [" + uri + "]"); } } } /** * Creates a new {@code UriPathTemplate} from the given {@code uriPattern}. * * @param uriPattern The pattern to be used by the template */ UriPathTemplate(String uriPattern) { String s = "^" + filterQueryParams(filterHostAndPort(uriPattern)); Matcher m = NAME_SPLAT_PATTERN.matcher(s); while (m.find()) { for (int i = 1; i <= m.groupCount(); i++) { String name = m.group(i); pathVariables.add(name); s = m.replaceFirst(getNameSplatReplacement(name)); m.reset(s); } } m = NAME_PATTERN.matcher(s); while (m.find()) { for (int i = 1; i <= m.groupCount(); i++) { String name = m.group(i); pathVariables.add(name); s = m.replaceFirst(getNameReplacement(name)); m.reset(s); } } m = FULL_SPLAT_PATTERN.matcher(s); while (m.find()) { s = m.replaceAll(FULL_SPLAT_REPLACEMENT); m.reset(s); } this.uriPattern = Pattern.compile(s + "$"); } /** * Tests the given {@code uri} against this template, returning {@code true} if * the uri matches the template, {@code false} otherwise. * * @param uri The uri to match * * @return {@code true} if there's a match, {@code false} otherwise */ public boolean matches(String uri) { return matcher(uri).matches(); } /** * Matches the template against the given {@code uri} returning a map of path * parameters extracted from the uri, keyed by the names in the template. If the * uri does not match, or there are no path parameters, an empty map is returned. * * @param uri The uri to match * * @return the path parameters from the uri. Never {@code null}. */ final Map match(String uri) { Map pathParameters = new HashMap<>(MapUtils.calculateInitialCapacity(pathVariables.size())); Matcher m = matcher(uri); if (m.matches()) { int i = 1; for (String name : pathVariables) { String val = m.group(i++); pathParameters.put(name, val); } } return pathParameters; } private Matcher matcher(String uri) { uri = filterQueryParams(filterHostAndPort(uri)); return uriPattern.matcher(uri); } } static final class HttpPrefixPredicate implements Predicate { final HttpMethod method; final String prefix; public HttpPrefixPredicate(String prefix, HttpMethod method) { this.prefix = prefix; this.method = method; } @Override public boolean test(HttpServerRequest key) { return method.equals(key.method()) && key.uri().startsWith(prefix); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy