2 * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.aaa.web;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import org.eclipse.jdt.annotation.NonNull;
15 * Utility methods for dealing with aspects of Java Servlet Specification. We currently support
16 * <a href="https://github.com/javaee/servlet-spec/blob/gh-pages/downloads/servlet-3.1/Final/servlet-3_1-final.pdf">
19 final class ServletSpec {
20 private ServletSpec() {
25 * Verify that the specified string is a valid Context Path as defined in Section 3.5.
27 * @param str String to check
29 * @throws IllegalArgumentException if {@code str} is not a valid context path
30 * @throws NullPointerException if {@code str} is {@code null}
32 static @NonNull String requireContextPath(final String str) {
33 // We do not allow this:
34 // If this context is the “default” context rooted at the base of the
35 // Web server’s URL name space, this path will be an empty string.
36 checkArgument(!str.isEmpty(), "Context path is empty");
39 // context is not rooted at the root of the server’s name space, the path starts with a
40 // character but does not end with a / character.
41 checkArgument(str.charAt(0) == '/', "Context path '%s' does not start with '/'", str);
42 checkArgument(str.charAt(str.length() - 1) != '/', "Context path '%s' ends with '/'", str);
44 // TODO: validate according to https://www.rfc-editor.org/rfc/rfc3986#section-3.3
50 * Verify that the specified string is a valid Specification of Mapping as defined in Section 12.2.
52 * @param str String to check
54 * @throws IllegalArgumentException if {@code str} is not a valid mapping specification
55 * @throws NullPointerException if {@code str} is {@code null}
57 static @NonNull String requireMappingSpec(final String str) {
59 // The empty string ("") is a special URL pattern that exactly maps to the
60 // application's context root, i.e., requests of the form http://host:port/<context-
61 // root>/. In this case the path info is ’ / ’ and the servlet path and context path is
67 final char firstChar = str.charAt(0);
68 final int len = str.length();
69 if (firstChar == '/') {
71 // A string containing only the ’ / ’ character indicates the "default" servlet of the
72 // application. In this case the servlet path is the request URI minus the context path
73 // and the path info is null.
76 // ... more checks starting at the second character
77 final int star = str.indexOf('*', 1);
80 // All other strings are used for exact matches only.
83 // A string beginning with a ‘ / ’ character and ending with a ‘ /*’ suffix is used for
85 || star == len - 1 && str.charAt(star - 1) == '/',
86 // ... otherwise it is a '*' in an exact path
87 "Prefix-based spec '%s' with a '*' at offset %s", str, star);
91 // A string beginning with a ‘ *. ’ prefix is used as an extension mapping
92 checkArgument(firstChar == '.' && len > 1 && str.charAt(1) == '*',
93 "Spec '%s' is neither prefix-based nor suffix-based", str);
95 final int slash = str.indexOf('/', 2);
96 checkArgument(slash == -1, "Suffix-based spec '%s' with a '/' at offset %s", str, slash);
97 final int star = str.indexOf('*', 2);
98 checkArgument(star == -1, "Suffix-based spec '%s' with a '*' at offset %s", str, star);