Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
reactor.netty.http.server.HttpPredicate Maven / Gradle / Ivy
/*
* 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);
}
}
}