This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.InputStream;
import java.util.Locale;
import java.util.Properties;
import org.apache.tomcat.util.ExceptionUtils;
/**
* Utility class that attempts to map from a Locale to the corresponding
* character set to be used for interpreting input text (or generating
* output text) when the Content-Type header does not include one. You
* can customize the behavior of this class by modifying the mapping data
* it loads, or by subclassing it (to change the algorithm) and then using
* your own version for a particular web application.
*
* @author Craig R. McClanahan
*/
public class CharsetMapper {
// ---------------------------------------------------- Manifest Constants
/**
* Default properties resource name.
*/
public static final String DEFAULT_RESOURCE =
"/org/apache/catalina/util/CharsetMapperDefault.properties";
// ---------------------------------------------------------- Constructors
/**
* Construct a new CharsetMapper using the default properties resource.
*/
public CharsetMapper() {
this(DEFAULT_RESOURCE);
}
/**
* Construct a new CharsetMapper using the specified properties resource.
*
* @param name Name of a properties resource to be loaded
*
* @exception IllegalArgumentException if the specified properties
* resource could not be loaded for any reason.
*/
public CharsetMapper(String name) {
try (InputStream stream = this.getClass().getResourceAsStream(name)) {
map.load(stream);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
throw new IllegalArgumentException(t.toString());
}
}
// ---------------------------------------------------- Instance Variables
/**
* The mapping properties that have been initialized from the specified or
* default properties resource.
*/
private Properties map = new Properties();
// ------------------------------------------------------- Public Methods
/**
* Calculate the name of a character set to be assumed, given the specified
* Locale and the absence of a character set specified as part of the
* content type header.
*
* @param locale The locale for which to calculate a character set
* @return the charset name
*/
public String getCharset(Locale locale) {
// Match full language_country_variant first, then language_country,
// then language only
String charset = map.getProperty(locale.toString());
if (charset == null) {
charset = map.getProperty(locale.getLanguage() + "_"
+ locale.getCountry());
if (charset == null) {
charset = map.getProperty(locale.getLanguage());
}
}
return charset;
}
/**
* The deployment descriptor can have a
* locale-encoding-mapping-list element which describes the
* webapp's desired mapping from locale to charset. This method
* gets called when processing the web.xml file for a context
*
* @param locale The locale for a character set
* @param charset The charset to be associated with the locale
*/
public void addCharsetMappingFromDeploymentDescriptor(String locale, String charset) {
map.put(locale, charset);
}
}

View File

@@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
en=ISO-8859-1
fr=ISO-8859-1

View File

@@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Queue;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* A thread safe wrapper around {@link SimpleDateFormat} that does not make use
* of ThreadLocal and - broadly - only creates enough SimpleDateFormat objects
* to satisfy the concurrency requirements.
*
* @deprecated Unused. This will be removed in Tomcat 10.
* Use {@link org.apache.tomcat.util.http.ConcurrentDateFormat}
*/
@Deprecated
public class ConcurrentDateFormat {
private final String format;
private final Locale locale;
private final TimeZone timezone;
private final Queue<SimpleDateFormat> queue = new ConcurrentLinkedQueue<>();
public static final String RFC1123_DATE = "EEE, dd MMM yyyy HH:mm:ss zzz";
public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
private static final ConcurrentDateFormat FORMAT_RFC1123;
static {
FORMAT_RFC1123 = new ConcurrentDateFormat(RFC1123_DATE, Locale.US, GMT);
}
public static String formatRfc1123(Date date) {
return FORMAT_RFC1123.format(date);
}
public ConcurrentDateFormat(String format, Locale locale,
TimeZone timezone) {
this.format = format;
this.locale = locale;
this.timezone = timezone;
SimpleDateFormat initial = createInstance();
queue.add(initial);
}
public String format(Date date) {
SimpleDateFormat sdf = queue.poll();
if (sdf == null) {
sdf = createInstance();
}
String result = sdf.format(date);
queue.add(sdf);
return result;
}
private SimpleDateFormat createInstance() {
SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
sdf.setTimeZone(timezone);
return sdf;
}
}

View File

@@ -0,0 +1,176 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.Locale;
/**
* Utility class to manage context names so there is one place where the
* conversions between baseName, path and version take place.
*/
public final class ContextName {
public static final String ROOT_NAME = "ROOT";
private static final String VERSION_MARKER = "##";
private static final String FWD_SLASH_REPLACEMENT = "#";
private final String baseName;
private final String path;
private final String version;
private final String name;
/**
* Creates an instance from a context name, display name, base name,
* directory name, WAR name or context.xml name.
*
* @param name The name to use as the basis for this object
* @param stripFileExtension If a .war or .xml file extension is present
* at the end of the provided name should it be
* removed?
*/
public ContextName(String name, boolean stripFileExtension) {
String tmp1 = name;
// Convert Context names and display names to base names
// Strip off any leading "/"
if (tmp1.startsWith("/")) {
tmp1 = tmp1.substring(1);
}
// Replace any remaining /
tmp1 = tmp1.replaceAll("/", FWD_SLASH_REPLACEMENT);
// Insert the ROOT name if required
if (tmp1.startsWith(VERSION_MARKER) || "".equals(tmp1)) {
tmp1 = ROOT_NAME + tmp1;
}
// Remove any file extensions
if (stripFileExtension &&
(tmp1.toLowerCase(Locale.ENGLISH).endsWith(".war") ||
tmp1.toLowerCase(Locale.ENGLISH).endsWith(".xml"))) {
tmp1 = tmp1.substring(0, tmp1.length() -4);
}
baseName = tmp1;
String tmp2;
// Extract version number
int versionIndex = baseName.indexOf(VERSION_MARKER);
if (versionIndex > -1) {
version = baseName.substring(versionIndex + 2);
tmp2 = baseName.substring(0, versionIndex);
} else {
version = "";
tmp2 = baseName;
}
if (ROOT_NAME.equals(tmp2)) {
path = "";
} else {
path = "/" + tmp2.replaceAll(FWD_SLASH_REPLACEMENT, "/");
}
if (versionIndex > -1) {
this.name = path + VERSION_MARKER + version;
} else {
this.name = path;
}
}
/**
* Construct an instance from a path and version.
*
* @param path Context path to use
* @param version Context version to use
*/
public ContextName(String path, String version) {
// Path should never be null, '/' or '/ROOT'
if (path == null || "/".equals(path) || "/ROOT".equals(path)) {
this.path = "";
} else {
this.path = path;
}
// Version should never be null
if (version == null) {
this.version = "";
} else {
this.version = version;
}
// Name is path + version
if ("".equals(this.version)) {
name = this.path;
} else {
name = this.path + VERSION_MARKER + this.version;
}
// Base name is converted path + version
StringBuilder tmp = new StringBuilder();
if ("".equals(this.path)) {
tmp.append(ROOT_NAME);
} else {
tmp.append(this.path.substring(1).replaceAll("/",
FWD_SLASH_REPLACEMENT));
}
if (this.version.length() > 0) {
tmp.append(VERSION_MARKER);
tmp.append(this.version);
}
this.baseName = tmp.toString();
}
public String getBaseName() {
return baseName;
}
public String getPath() {
return path;
}
public String getVersion() {
return version;
}
public String getName() {
return name;
}
public String getDisplayName() {
StringBuilder tmp = new StringBuilder();
if ("".equals(path)) {
tmp.append('/');
} else {
tmp.append(path);
}
if (!"".equals(version)) {
tmp.append(VERSION_MARKER);
tmp.append(version);
}
return tmp.toString();
}
@Override
public String toString() {
return getDisplayName();
}
}

View File

@@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.apache.juli.logging.Log;
import org.apache.tomcat.util.res.StringManager;
/**
* Custom subclass of <code>ObjectInputStream</code> that loads from the
* class loader for this web application. This allows classes defined only
* with the web application to be found correctly.
*
* @author Craig R. McClanahan
* @author Bip Thelin
*/
public final class CustomObjectInputStream extends ObjectInputStream {
private static final StringManager sm = StringManager.getManager(CustomObjectInputStream.class);
private static final WeakHashMap<ClassLoader, Set<String>> reportedClassCache =
new WeakHashMap<>();
/**
* The class loader we will use to resolve classes.
*/
private final ClassLoader classLoader;
private final Set<String> reportedClasses;
private final Log log;
private final Pattern allowedClassNamePattern;
private final String allowedClassNameFilter;
private final boolean warnOnFailure;
/**
* Construct a new instance of CustomObjectInputStream without any filtering
* of deserialized classes.
*
* @param stream The input stream we will read from
* @param classLoader The class loader used to instantiate objects
*
* @exception IOException if an input/output error occurs
*/
public CustomObjectInputStream(InputStream stream, ClassLoader classLoader) throws IOException {
this(stream, classLoader, null, null, false);
}
/**
* Construct a new instance of CustomObjectInputStream with filtering of
* deserialized classes.
*
* @param stream The input stream we will read from
* @param classLoader The class loader used to instantiate objects
* @param log The logger to use to report any issues. It may only be null if
* the filterMode does not require logging
* @param allowedClassNamePattern The regular expression to use to filter
* deserialized classes. The fully qualified
* class name must match this pattern for
* deserialization to be allowed if filtering
* is enabled.
* @param warnOnFailure Should any failures be logged?
*
* @exception IOException if an input/output error occurs
*/
public CustomObjectInputStream(InputStream stream, ClassLoader classLoader,
Log log, Pattern allowedClassNamePattern, boolean warnOnFailure)
throws IOException {
super(stream);
if (log == null && allowedClassNamePattern != null && warnOnFailure) {
throw new IllegalArgumentException(
sm.getString("customObjectInputStream.logRequired"));
}
this.classLoader = classLoader;
this.log = log;
this.allowedClassNamePattern = allowedClassNamePattern;
if (allowedClassNamePattern == null) {
this.allowedClassNameFilter = null;
} else {
this.allowedClassNameFilter = allowedClassNamePattern.toString();
}
this.warnOnFailure = warnOnFailure;
Set<String> reportedClasses;
synchronized (reportedClassCache) {
reportedClasses = reportedClassCache.get(classLoader);
}
if (reportedClasses == null) {
reportedClasses = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
synchronized (reportedClassCache) {
Set<String> original = reportedClassCache.get(classLoader);
if (original == null) {
reportedClassCache.put(classLoader, reportedClasses);
} else {
// Concurrent attempts to create the new Set. Make sure all
// threads use the first successfully added Set.
reportedClasses = original;
}
}
}
this.reportedClasses = reportedClasses;
}
/**
* Load the local class equivalent of the specified stream class
* description, by using the class loader assigned to this Context.
*
* @param classDesc Class description from the input stream
*
* @exception ClassNotFoundException if this class cannot be found
* @exception IOException if an input/output error occurs
*/
@Override
public Class<?> resolveClass(ObjectStreamClass classDesc)
throws ClassNotFoundException, IOException {
String name = classDesc.getName();
if (allowedClassNamePattern != null) {
boolean allowed = allowedClassNamePattern.matcher(name).matches();
if (!allowed) {
boolean doLog = warnOnFailure && reportedClasses.add(name);
String msg = sm.getString("customObjectInputStream.nomatch", name, allowedClassNameFilter);
if (doLog) {
log.warn(msg);
} else if (log.isDebugEnabled()) {
log.debug(msg);
}
throw new InvalidClassException(msg);
}
}
try {
return Class.forName(name, false, classLoader);
} catch (ClassNotFoundException e) {
try {
// Try also the superclass because of primitive types
return super.resolveClass(classDesc);
} catch (ClassNotFoundException e2) {
// Rethrow original exception, as it can have more information
// about why the class was not found. BZ 48007
throw e;
}
}
}
/**
* Return a proxy class that implements the interfaces named in a proxy
* class descriptor. Do this using the class loader assigned to this
* Context.
*/
@Override
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException {
Class<?>[] cinterfaces = new Class[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
cinterfaces[i] = classLoader.loadClass(interfaces[i]);
}
try {
return Proxy.getProxyClass(classLoader, cinterfaces);
} catch (IllegalArgumentException e) {
throw new ClassNotFoundException(null, e);
}
}
}

View File

@@ -0,0 +1,266 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.PrintWriter;
import java.io.Writer;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* A sample DOM writer. This sample program illustrates how to traverse a DOM
* tree in order to print a document that is parsed.
*/
public class DOMWriter {
/** Default Encoding */
private static final String PRINTWRITER_ENCODING = "UTF8";
/** Print writer.
*
* @deprecated Will be made private in Tomcat 9.
*/
@Deprecated
protected final PrintWriter out;
/** Canonical output.
*
* @deprecated Will be made private in Tomcat 9.
*/
@Deprecated
protected final boolean canonical;
public DOMWriter(Writer writer) {
this (writer, true);
}
@Deprecated
public DOMWriter(Writer writer, boolean canonical) {
out = new PrintWriter(writer);
this.canonical = canonical;
}
/**
* @deprecated Unused. Will be removed in Tomcat 9.
*
* @return Always <code>UTF-8</code>
*/
@Deprecated
public static String getWriterEncoding() {
return (PRINTWRITER_ENCODING);
}
/**
* Prints the specified node, recursively.
* @param node The node to output
*/
public void print(Node node) {
// is there anything to do?
if (node == null) {
return;
}
int type = node.getNodeType();
switch (type) {
// print document
case Node.DOCUMENT_NODE:
if (!canonical) {
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
}
print(((Document) node).getDocumentElement());
out.flush();
break;
// print element with attributes
case Node.ELEMENT_NODE:
out.print('<');
out.print(node.getLocalName());
Attr attrs[] = sortAttributes(node.getAttributes());
for (int i = 0; i < attrs.length; i++) {
Attr attr = attrs[i];
out.print(' ');
out.print(attr.getLocalName());
out.print("=\"");
out.print(normalize(attr.getNodeValue()));
out.print('"');
}
out.print('>');
printChildren(node);
break;
// handle entity reference nodes
case Node.ENTITY_REFERENCE_NODE:
if (canonical) {
printChildren(node);
} else {
out.print('&');
out.print(node.getLocalName());
out.print(';');
}
break;
// print cdata sections
case Node.CDATA_SECTION_NODE:
if (canonical) {
out.print(normalize(node.getNodeValue()));
} else {
out.print("<![CDATA[");
out.print(node.getNodeValue());
out.print("]]>");
}
break;
// print text
case Node.TEXT_NODE:
out.print(normalize(node.getNodeValue()));
break;
// print processing instruction
case Node.PROCESSING_INSTRUCTION_NODE:
out.print("<?");
out.print(node.getLocalName());
String data = node.getNodeValue();
if (data != null && data.length() > 0) {
out.print(' ');
out.print(data);
}
out.print("?>");
break;
}
if (type == Node.ELEMENT_NODE) {
out.print("</");
out.print(node.getLocalName());
out.print('>');
}
out.flush();
} // print(Node)
private void printChildren(Node node) {
NodeList children = node.getChildNodes();
if (children != null) {
int len = children.getLength();
for (int i = 0; i < len; i++) {
print(children.item(i));
}
}
}
/**
* Returns a sorted list of attributes.
* @param attrs The map to sort
* @return a sorted attribute array
*
* @deprecated Will be made private in Tomcat 9.
*/
@Deprecated
protected Attr[] sortAttributes(NamedNodeMap attrs) {
if (attrs == null) {
return new Attr[0];
}
int len = attrs.getLength();
Attr array[] = new Attr[len];
for (int i = 0; i < len; i++) {
array[i] = (Attr) attrs.item(i);
}
for (int i = 0; i < len - 1; i++) {
String name = null;
name = array[i].getLocalName();
int index = i;
for (int j = i + 1; j < len; j++) {
String curName = null;
curName = array[j].getLocalName();
if (curName.compareTo(name) < 0) {
name = curName;
index = j;
}
}
if (index != i) {
Attr temp = array[i];
array[i] = array[index];
array[index] = temp;
}
}
return array;
}
/**
* Normalizes the given string.
* @param s The string to escape
* @return the escaped string
*
* @deprecated Will be made private in Tomcat 9.
*/
@Deprecated
protected String normalize(String s) {
if (s == null) {
return "";
}
StringBuilder str = new StringBuilder();
int len = s.length();
for (int i = 0; i < len; i++) {
char ch = s.charAt(i);
switch (ch) {
case '<':
str.append("&lt;");
break;
case '>':
str.append("&gt;");
break;
case '&':
str.append("&amp;");
break;
case '"':
str.append("&quot;");
break;
case '\r':
case '\n':
if (canonical) {
str.append("&#");
str.append(Integer.toString(ch));
str.append(';');
break;
}
// else, default append char
//$FALL-THROUGH$
default:
str.append(ch);
}
}
return str.toString();
}
}

View File

@@ -0,0 +1,108 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
/**
* Provides support for tracking per exception type and per HTTP status code
* error pages.
*/
public class ErrorPageSupport {
// Fully qualified class name to error page
private ConcurrentMap<String, ErrorPage> exceptionPages = new ConcurrentHashMap<>();
// HTTP status code to error page
private ConcurrentMap<Integer, ErrorPage> statusPages = new ConcurrentHashMap<>();
public void add(ErrorPage errorPage) {
String exceptionType = errorPage.getExceptionType();
if (exceptionType == null) {
statusPages.put(Integer.valueOf(errorPage.getErrorCode()), errorPage);
} else {
exceptionPages.put(exceptionType, errorPage);
}
}
public void remove(ErrorPage errorPage) {
String exceptionType = errorPage.getExceptionType();
if (exceptionType == null) {
statusPages.remove(Integer.valueOf(errorPage.getErrorCode()), errorPage);
} else {
exceptionPages.remove(exceptionType, errorPage);
}
}
public ErrorPage find(int statusCode) {
return statusPages.get(Integer.valueOf(statusCode));
}
/**
* Find the ErrorPage, if any, for the named exception type.
*
* @param exceptionType The fully qualified class name of the exception type
*
* @return The ErrorPage for the named exception type, or {@code null} if
* none is configured
*
* @deprecated Unused. Will be removed in Tomcat 10.
* Use {@link #find(Throwable)} instead.
*/
@Deprecated
public ErrorPage find(String exceptionType) {
return exceptionPages.get(exceptionType);
}
public ErrorPage find(Throwable exceptionType) {
if (exceptionType == null) {
return null;
}
Class<?> clazz = exceptionType.getClass();
String name = clazz.getName();
while (!Object.class.equals(clazz)) {
ErrorPage errorPage = exceptionPages.get(name);
if (errorPage != null) {
return errorPage;
}
clazz = clazz.getSuperclass();
if (clazz == null) {
break;
}
name = clazz.getName();
}
return null;
}
public ErrorPage[] findAll() {
Set<ErrorPage> errorPages = new HashSet<>();
errorPages.addAll(exceptionPages.values());
errorPages.addAll(statusPages.values());
return errorPages.toArray(new ErrorPage[errorPages.size()]);
}
}

View File

@@ -0,0 +1,299 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.StringTokenizer;
/**
* Utility class that represents either an available "Optional Package"
* (formerly known as "Standard Extension") as described in the manifest
* of a JAR file, or the requirement for such an optional package. It is
* used to support the requirements of the Servlet Specification, version
* 2.3, related to providing shared extensions to all webapps.
* <p>
* In addition, static utility methods are available to scan a manifest
* and return an array of either available or required optional modules
* documented in that manifest.
* <p>
* For more information about optional packages, see the document
* <em>Optional Package Versioning</em> in the documentation bundle for your
* Java2 Standard Edition package, in file
* <code>guide/extensions/versioning.html</code>.
*
* @author Craig McClanahan
* @author Justyna Horwat
* @author Greg Murray
*/
public final class Extension {
// ------------------------------------------------------------- Properties
/**
* The name of the optional package being made available, or required.
*/
private String extensionName = null;
public String getExtensionName() {
return this.extensionName;
}
public void setExtensionName(String extensionName) {
this.extensionName = extensionName;
}
/**
* The URL from which the most recent version of this optional package
* can be obtained if it is not already installed.
*/
private String implementationURL = null;
public String getImplementationURL() {
return this.implementationURL;
}
public void setImplementationURL(String implementationURL) {
this.implementationURL = implementationURL;
}
/**
* The name of the company or organization that produced this
* implementation of this optional package.
*/
private String implementationVendor = null;
public String getImplementationVendor() {
return this.implementationVendor;
}
public void setImplementationVendor(String implementationVendor) {
this.implementationVendor = implementationVendor;
}
/**
* The unique identifier of the company that produced the optional
* package contained in this JAR file.
*/
private String implementationVendorId = null;
public String getImplementationVendorId() {
return this.implementationVendorId;
}
public void setImplementationVendorId(String implementationVendorId) {
this.implementationVendorId = implementationVendorId;
}
/**
* The version number (dotted decimal notation) for this implementation
* of the optional package.
*/
private String implementationVersion = null;
public String getImplementationVersion() {
return this.implementationVersion;
}
public void setImplementationVersion(String implementationVersion) {
this.implementationVersion = implementationVersion;
}
/**
* The name of the company or organization that originated the
* specification to which this optional package conforms.
*/
private String specificationVendor = null;
public String getSpecificationVendor() {
return this.specificationVendor;
}
public void setSpecificationVendor(String specificationVendor) {
this.specificationVendor = specificationVendor;
}
/**
* The version number (dotted decimal notation) of the specification
* to which this optional package conforms.
*/
private String specificationVersion = null;
public String getSpecificationVersion() {
return this.specificationVersion;
}
public void setSpecificationVersion(String specificationVersion) {
this.specificationVersion = specificationVersion;
}
/**
* fulfilled is true if all the required extension dependencies have been
* satisfied
*/
private boolean fulfilled = false;
public void setFulfilled(boolean fulfilled) {
this.fulfilled = fulfilled;
}
public boolean isFulfilled() {
return fulfilled;
}
// --------------------------------------------------------- Public Methods
/**
* Return <code>true</code> if the specified <code>Extension</code>
* (which represents an optional package required by this application)
* is satisfied by this <code>Extension</code> (which represents an
* optional package that is already installed. Otherwise, return
* <code>false</code>.
*
* @param required Extension of the required optional package
* @return <code>true</code> if the extension is satisfied
*/
public boolean isCompatibleWith(Extension required) {
// Extension Name must match
if (extensionName == null)
return false;
if (!extensionName.equals(required.getExtensionName()))
return false;
// If specified, available specification version must be >= required
if (required.getSpecificationVersion() != null) {
if (!isNewer(specificationVersion,
required.getSpecificationVersion()))
return false;
}
// If specified, Implementation Vendor ID must match
if (required.getImplementationVendorId() != null) {
if (implementationVendorId == null)
return false;
if (!implementationVendorId.equals(required
.getImplementationVendorId()))
return false;
}
// If specified, Implementation version must be >= required
if (required.getImplementationVersion() != null) {
if (!isNewer(implementationVersion,
required.getImplementationVersion()))
return false;
}
// This available optional package satisfies the requirements
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Extension[");
sb.append(extensionName);
if (implementationURL != null) {
sb.append(", implementationURL=");
sb.append(implementationURL);
}
if (implementationVendor != null) {
sb.append(", implementationVendor=");
sb.append(implementationVendor);
}
if (implementationVendorId != null) {
sb.append(", implementationVendorId=");
sb.append(implementationVendorId);
}
if (implementationVersion != null) {
sb.append(", implementationVersion=");
sb.append(implementationVersion);
}
if (specificationVendor != null) {
sb.append(", specificationVendor=");
sb.append(specificationVendor);
}
if (specificationVersion != null) {
sb.append(", specificationVersion=");
sb.append(specificationVersion);
}
sb.append("]");
return sb.toString();
}
// -------------------------------------------------------- Private Methods
/**
* Return <code>true</code> if the first version number is greater than
* or equal to the second; otherwise return <code>false</code>.
*
* @param first First version number (dotted decimal)
* @param second Second version number (dotted decimal)
*
* @exception NumberFormatException on a malformed version number
*/
private boolean isNewer(String first, String second)
throws NumberFormatException {
if ((first == null) || (second == null))
return false;
if (first.equals(second))
return true;
StringTokenizer fTok = new StringTokenizer(first, ".", true);
StringTokenizer sTok = new StringTokenizer(second, ".", true);
int fVersion = 0;
int sVersion = 0;
while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) {
if (fTok.hasMoreTokens())
fVersion = Integer.parseInt(fTok.nextToken());
else
fVersion = 0;
if (sTok.hasMoreTokens())
sVersion = Integer.parseInt(sTok.nextToken());
else
sVersion = 0;
if (fVersion < sVersion)
return false;
else if (fVersion > sVersion)
return true;
if (fTok.hasMoreTokens()) // Swallow the periods
fTok.nextToken();
if (sTok.hasMoreTokens())
sTok.nextToken();
}
return true; // Exact match
}
}

View File

@@ -0,0 +1,365 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.apache.catalina.Context;
import org.apache.catalina.WebResource;
import org.apache.catalina.WebResourceRoot;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;
/**
* Ensures that all extension dependencies are resolved for a WEB application
* are met. This class builds a master list of extensions available to an
* application and then validates those extensions.
*
* See http://docs.oracle.com/javase/1.4.2/docs/guide/extensions/spec.html
* for a detailed explanation of the extension mechanism in Java.
*
* @author Greg Murray
* @author Justyna Horwat
*/
public final class ExtensionValidator {
private static final Log log = LogFactory.getLog(ExtensionValidator.class);
/**
* The string resources for this package.
*/
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
private static volatile ArrayList<Extension> containerAvailableExtensions =
null;
private static final ArrayList<ManifestResource> containerManifestResources =
new ArrayList<>();
// ----------------------------------------------------- Static Initializer
/**
* This static initializer loads the container level extensions that are
* available to all web applications. This method scans all extension
* directories available via the "java.ext.dirs" System property.
*
* The System Class-Path is also scanned for jar files that may contain
* available extensions.
*/
static {
// check for container level optional packages
String systemClasspath = System.getProperty("java.class.path");
StringTokenizer strTok = new StringTokenizer(systemClasspath,
File.pathSeparator);
// build a list of jar files in the classpath
while (strTok.hasMoreTokens()) {
String classpathItem = strTok.nextToken();
if (classpathItem.toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
File item = new File(classpathItem);
if (item.isFile()) {
try {
addSystemResource(item);
} catch (IOException e) {
log.error(sm.getString
("extensionValidator.failload", item), e);
}
}
}
}
// add specified folders to the list
addFolderList("java.ext.dirs");
}
// --------------------------------------------------------- Public Methods
/**
* Runtime validation of a Web Application.
*
* This method uses JNDI to look up the resources located under a
* <code>DirContext</code>. It locates Web Application MANIFEST.MF
* file in the /META-INF/ directory of the application and all
* MANIFEST.MF files in each JAR file located in the WEB-INF/lib
* directory and creates an <code>ArrayList</code> of
* <code>ManifestResource</code> objects. These objects are then passed
* to the validateManifestResources method for validation.
*
* @param resources The resources configured for this Web Application
* @param context The context from which the Logger and path to the
* application
*
* @return true if all required extensions satisfied
* @throws IOException Error reading resources needed for validation
*/
public static synchronized boolean validateApplication(
WebResourceRoot resources,
Context context)
throws IOException {
String appName = context.getName();
ArrayList<ManifestResource> appManifestResources = new ArrayList<>();
// Web application manifest
WebResource resource = resources.getResource("/META-INF/MANIFEST.MF");
if (resource.isFile()) {
try (InputStream inputStream = resource.getInputStream()) {
Manifest manifest = new Manifest(inputStream);
ManifestResource mre = new ManifestResource
(sm.getString("extensionValidator.web-application-manifest"),
manifest, ManifestResource.WAR);
appManifestResources.add(mre);
}
}
// Web application library manifests
WebResource[] manifestResources =
resources.getClassLoaderResources("/META-INF/MANIFEST.MF");
for (WebResource manifestResource : manifestResources) {
if (manifestResource.isFile()) {
// Primarily used for error reporting
String jarName = manifestResource.getURL().toExternalForm();
Manifest jmanifest = manifestResource.getManifest();
if (jmanifest != null) {
ManifestResource mre = new ManifestResource(jarName,
jmanifest, ManifestResource.APPLICATION);
appManifestResources.add(mre);
}
}
}
return validateManifestResources(appName, appManifestResources);
}
/**
* Checks to see if the given system JAR file contains a MANIFEST, and adds
* it to the container's manifest resources.
*
* @param jarFile The system JAR whose manifest to add
* @throws IOException Error reading JAR file
*/
public static void addSystemResource(File jarFile) throws IOException {
try (InputStream is = new FileInputStream(jarFile)) {
Manifest manifest = getManifest(is);
if (manifest != null) {
ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest,
ManifestResource.SYSTEM);
containerManifestResources.add(mre);
}
}
}
// -------------------------------------------------------- Private Methods
/**
* Validates a <code>ArrayList</code> of <code>ManifestResource</code>
* objects. This method requires an application name (which is the
* context root of the application at runtime).
*
* <code>false</false> is returned if the extension dependencies
* represented by any given <code>ManifestResource</code> objects
* is not met.
*
* This method should also provide static validation of a Web Application
* if provided with the necessary parameters.
*
* @param appName The name of the Application that will appear in the
* error messages
* @param resources A list of <code>ManifestResource</code> objects
* to be validated.
*
* @return true if manifest resource file requirements are met
*/
private static boolean validateManifestResources(String appName,
ArrayList<ManifestResource> resources) {
boolean passes = true;
int failureCount = 0;
ArrayList<Extension> availableExtensions = null;
for (ManifestResource mre : resources) {
ArrayList<Extension> requiredList = mre.getRequiredExtensions();
if (requiredList == null) {
continue;
}
// build the list of available extensions if necessary
if (availableExtensions == null) {
availableExtensions = buildAvailableExtensionsList(resources);
}
// load the container level resource map if it has not been built
// yet
if (containerAvailableExtensions == null) {
containerAvailableExtensions
= buildAvailableExtensionsList(containerManifestResources);
}
// iterate through the list of required extensions
for (Extension requiredExt : requiredList) {
boolean found = false;
// check the application itself for the extension
if (availableExtensions != null) {
for (Extension targetExt : availableExtensions) {
if (targetExt.isCompatibleWith(requiredExt)) {
requiredExt.setFulfilled(true);
found = true;
break;
}
}
}
// check the container level list for the extension
if (!found && containerAvailableExtensions != null) {
for (Extension targetExt : containerAvailableExtensions) {
if (targetExt.isCompatibleWith(requiredExt)) {
requiredExt.setFulfilled(true);
found = true;
break;
}
}
}
if (!found) {
// Failure
log.info(sm.getString(
"extensionValidator.extension-not-found-error",
appName, mre.getResourceName(),
requiredExt.getExtensionName()));
passes = false;
failureCount++;
}
}
}
if (!passes) {
log.info(sm.getString(
"extensionValidator.extension-validation-error", appName,
failureCount + ""));
}
return passes;
}
/*
* Build this list of available extensions so that we do not have to
* re-build this list every time we iterate through the list of required
* extensions. All available extensions in all of the
* <code>ManifestResource</code> objects will be added to a
* <code>HashMap</code> which is returned on the first dependency list
* processing pass.
*
* The key is the name + implementation version.
*
* NOTE: A list is built only if there is a dependency that needs
* to be checked (performance optimization).
*
* @param resources A list of <code>ManifestResource</code> objects
*
* @return HashMap Map of available extensions
*/
private static ArrayList<Extension> buildAvailableExtensionsList(
ArrayList<ManifestResource> resources) {
ArrayList<Extension> availableList = null;
for (ManifestResource mre : resources) {
ArrayList<Extension> list = mre.getAvailableExtensions();
if (list != null) {
for (Extension ext : list) {
if (availableList == null) {
availableList = new ArrayList<>();
availableList.add(ext);
} else {
availableList.add(ext);
}
}
}
}
return availableList;
}
/**
* Return the Manifest from a jar file or war file
*
* @param inStream Input stream to a WAR or JAR file
* @return The WAR's or JAR's manifest
*/
private static Manifest getManifest(InputStream inStream) throws IOException {
Manifest manifest = null;
try (JarInputStream jin = new JarInputStream(inStream)) {
manifest = jin.getManifest();
}
return manifest;
}
/**
* Add the JARs specified to the extension list.
*/
private static void addFolderList(String property) {
// get the files in the extensions directory
String extensionsDir = System.getProperty(property);
if (extensionsDir != null) {
StringTokenizer extensionsTok
= new StringTokenizer(extensionsDir, File.pathSeparator);
while (extensionsTok.hasMoreTokens()) {
File targetDir = new File(extensionsTok.nextToken());
if (!targetDir.isDirectory()) {
continue;
}
File[] files = targetDir.listFiles();
if (files == null) {
continue;
}
for (int i = 0; i < files.length; i++) {
if (files[i].getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") &&
files[i].isFile()) {
try {
addSystemResource(files[i]);
} catch (IOException e) {
log.error
(sm.getString
("extensionValidator.failload", files[i]), e);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
/**
* Contains commonly needed I/O-related methods
*
* @author Dan Sandberg
*/
public class IOTools {
protected static final int DEFAULT_BUFFER_SIZE=4*1024; //4k
private IOTools() {
//Ensure non-instantiability
}
/**
* Read input from reader and write it to writer until there is no more
* input from reader.
*
* @param reader the reader to read from.
* @param writer the writer to write to.
* @param buf the char array to use as a buffer
* @throws IOException IO error
*/
public static void flow( Reader reader, Writer writer, char[] buf )
throws IOException {
int numRead;
while ( (numRead = reader.read(buf) ) >= 0) {
writer.write(buf, 0, numRead);
}
}
/**
* Read input from reader and write it to writer until there is no more
* input from reader.
*
* @param reader the reader to read from.
* @param writer the writer to write to.
* @throws IOException IO error
* @see #flow( Reader, Writer, char[] )
*/
public static void flow( Reader reader, Writer writer )
throws IOException {
char[] buf = new char[DEFAULT_BUFFER_SIZE];
flow( reader, writer, buf );
}
/**
* Read input from input stream and write it to output stream until there is
* no more input from input stream using a new buffer of the default size
* (4kB).
*
* @param is input stream the input stream to read from.
* @param os output stream the output stream to write to.
*
* @throws IOException If an I/O error occurs during the copy
*/
public static void flow(InputStream is, OutputStream os) throws IOException {
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int numRead;
while ( (numRead = is.read(buf) ) >= 0) {
if (os != null) {
os.write(buf, 0, numRead);
}
}
}
/**
* Read until EOF or the buffer is filled.
*
* @param is The source to read from
* @param buf The buffer to write to
*
* @return The number of bytes read
*
* @throws IOException If an I/O error occurs during the read
*/
public static int readFully(InputStream is, byte[] buf) throws IOException {
int bytesRead = 0;
int read;
while (bytesRead < buf.length && ((read = is.read(buf, bytesRead, buf.length - bytesRead)) >= 0)) {
bytesRead += read;
}
return bytesRead;
}
}

View File

@@ -0,0 +1,192 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.juli.logging.Log;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;
/**
* Provides introspection utilities that either require knowledge of Tomcat
* internals or are solely used by Tomcat internals.
*/
public class Introspection {
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
/**
* Extract the Java Bean property name from the setter name.
*
* Note: This method assumes that the method name has already been checked
* for correctness.
* @param setter The setter method
* @return the bean property name
*/
public static String getPropertyName(Method setter) {
return Introspector.decapitalize(setter.getName().substring(3));
}
/**
* Determines if a method has a valid name and signature for a Java Bean
* setter.
*
* @param method The method to test
*
* @return <code>true</code> if the method does have a valid name and
* signature, else <code>false</code>
*/
public static boolean isValidSetter(Method method) {
if (method.getName().startsWith("set")
&& method.getName().length() > 3
&& method.getParameterTypes().length == 1
&& method.getReturnType().getName().equals("void")) {
return true;
}
return false;
}
/**
* Determines if a method is a valid lifecycle callback method.
*
* @param method
* The method to test
*
* @return <code>true</code> if the method is a valid lifecycle callback
* method, else <code>false</code>
*/
public static boolean isValidLifecycleCallback(Method method) {
if (method.getParameterTypes().length != 0
|| Modifier.isStatic(method.getModifiers())
|| method.getExceptionTypes().length > 0
|| !method.getReturnType().getName().equals("void")) {
return false;
}
return true;
}
/**
* Obtain the declared fields for a class taking account of any security
* manager that may be configured.
* @param clazz The class to introspect
* @return the class fields as an array
*/
public static Field[] getDeclaredFields(final Class<?> clazz) {
Field[] fields = null;
if (Globals.IS_SECURITY_ENABLED) {
fields = AccessController.doPrivileged(
new PrivilegedAction<Field[]>(){
@Override
public Field[] run(){
return clazz.getDeclaredFields();
}
});
} else {
fields = clazz.getDeclaredFields();
}
return fields;
}
/**
* Obtain the declared methods for a class taking account of any security
* manager that may be configured.
* @param clazz The class to introspect
* @return the class methods as an array
*/
public static Method[] getDeclaredMethods(final Class<?> clazz) {
Method[] methods = null;
if (Globals.IS_SECURITY_ENABLED) {
methods = AccessController.doPrivileged(
new PrivilegedAction<Method[]>(){
@Override
public Method[] run(){
return clazz.getDeclaredMethods();
}
});
} else {
methods = clazz.getDeclaredMethods();
}
return methods;
}
/**
* Attempt to load a class using the given Container's class loader. If the
* class cannot be loaded, a debug level log message will be written to the
* Container's log and null will be returned.
* @param context The class loader of this context will be used to attempt
* to load the class
* @param className The class name
* @return the loaded class or <code>null</code> if loading failed
*/
public static Class<?> loadClass(Context context, String className) {
ClassLoader cl = context.getLoader().getClassLoader();
Log log = context.getLogger();
Class<?> clazz = null;
try {
clazz = cl.loadClass(className);
} catch (ClassNotFoundException | NoClassDefFoundError | ClassFormatError e) {
log.debug(sm.getString("introspection.classLoadFailed", className), e);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.debug(sm.getString("introspection.classLoadFailed", className), t);
}
return clazz;
}
/**
* Converts the primitive type to its corresponding wrapper.
*
* @param clazz
* Class that will be evaluated
* @return if the parameter is a primitive type returns its wrapper;
* otherwise returns the same class
*/
public static Class<?> convertPrimitiveType(Class<?> clazz) {
if (clazz.equals(char.class)) {
return Character.class;
} else if (clazz.equals(int.class)) {
return Integer.class;
} else if (clazz.equals(boolean.class)) {
return Boolean.class;
} else if (clazz.equals(double.class)) {
return Double.class;
} else if (clazz.equals(byte.class)) {
return Byte.class;
} else if (clazz.equals(short.class)) {
return Short.class;
} else if (clazz.equals(long.class)) {
return Long.class;
} else if (clazz.equals(float.class)) {
return Float.class;
} else {
return clazz;
}
}
}

View File

@@ -0,0 +1,447 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;
/**
* Base implementation of the {@link Lifecycle} interface that implements the
* state transition rules for {@link Lifecycle#start()} and
* {@link Lifecycle#stop()}
*/
public abstract class LifecycleBase implements Lifecycle {
private static final Log log = LogFactory.getLog(LifecycleBase.class);
private static final StringManager sm = StringManager.getManager(LifecycleBase.class);
/**
* The list of registered LifecycleListeners for event notifications.
*/
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
/**
* The current state of the source component.
*/
private volatile LifecycleState state = LifecycleState.NEW;
private boolean throwOnFailure = true;
/**
* Will a {@link LifecycleException} thrown by a sub-class during
* {@link #initInternal()}, {@link #startInternal()},
* {@link #stopInternal()} or {@link #destroyInternal()} be re-thrown for
* the caller to handle or will it be logged instead?
*
* @return {@code true} if the exception will be re-thrown, otherwise
* {@code false}
*/
public boolean getThrowOnFailure() {
return throwOnFailure;
}
/**
* Configure if a {@link LifecycleException} thrown by a sub-class during
* {@link #initInternal()}, {@link #startInternal()},
* {@link #stopInternal()} or {@link #destroyInternal()} will be re-thrown
* for the caller to handle or if it will be logged instead.
*
* @param throwOnFailure {@code true} if the exception should be re-thrown,
* otherwise {@code false}
*/
public void setThrowOnFailure(boolean throwOnFailure) {
this.throwOnFailure = throwOnFailure;
}
/**
* {@inheritDoc}
*/
@Override
public void addLifecycleListener(LifecycleListener listener) {
lifecycleListeners.add(listener);
}
/**
* {@inheritDoc}
*/
@Override
public LifecycleListener[] findLifecycleListeners() {
return lifecycleListeners.toArray(new LifecycleListener[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void removeLifecycleListener(LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
/**
* Allow sub classes to fire {@link Lifecycle} events.
*
* @param type Event type
* @param data Data associated with event.
*/
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
setStateInternal(LifecycleState.INITIALIZING, null, false);
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
/**
* Sub-classes implement this method to perform any instance initialisation
* required.
*
* @throws LifecycleException If the initialisation fails
*/
protected abstract void initInternal() throws LifecycleException;
/**
* {@inheritDoc}
*/
@Override
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
handleSubClassException(t, "lifecycleBase.startFail", toString());
}
}
/**
* Sub-classes must ensure that the state is changed to
* {@link LifecycleState#STARTING} during the execution of this method.
* Changing state will trigger the {@link Lifecycle#START_EVENT} event.
*
* If a component fails to start it may either throw a
* {@link LifecycleException} which will cause it's parent to fail to start
* or it can place itself in the error state in which case {@link #stop()}
* will be called on the failed component but the parent component will
* continue to start normally.
*
* @throws LifecycleException Start error occurred
*/
protected abstract void startInternal() throws LifecycleException;
/**
* {@inheritDoc}
*/
@Override
public final synchronized void stop() throws LifecycleException {
if (LifecycleState.STOPPING_PREP.equals(state) || LifecycleState.STOPPING.equals(state) ||
LifecycleState.STOPPED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStopped", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStopped", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
state = LifecycleState.STOPPED;
return;
}
if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) {
invalidTransition(Lifecycle.BEFORE_STOP_EVENT);
}
try {
if (state.equals(LifecycleState.FAILED)) {
// Don't transition to STOPPING_PREP as that would briefly mark the
// component as available but do ensure the BEFORE_STOP_EVENT is
// fired
fireLifecycleEvent(BEFORE_STOP_EVENT, null);
} else {
setStateInternal(LifecycleState.STOPPING_PREP, null, false);
}
stopInternal();
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
if (!state.equals(LifecycleState.STOPPING) && !state.equals(LifecycleState.FAILED)) {
invalidTransition(Lifecycle.AFTER_STOP_EVENT);
}
setStateInternal(LifecycleState.STOPPED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.stopFail", toString());
} finally {
if (this instanceof Lifecycle.SingleUse) {
// Complete stop process first
setStateInternal(LifecycleState.STOPPED, null, false);
destroy();
}
}
}
/**
* Sub-classes must ensure that the state is changed to
* {@link LifecycleState#STOPPING} during the execution of this method.
* Changing state will trigger the {@link Lifecycle#STOP_EVENT} event.
*
* @throws LifecycleException Stop error occurred
*/
protected abstract void stopInternal() throws LifecycleException;
@Override
public final synchronized void destroy() throws LifecycleException {
if (LifecycleState.FAILED.equals(state)) {
try {
// Triggers clean-up
stop();
} catch (LifecycleException e) {
// Just log. Still want to destroy.
log.error(sm.getString("lifecycleBase.destroyStopFail", toString()), e);
}
}
if (LifecycleState.DESTROYING.equals(state) || LifecycleState.DESTROYED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyDestroyed", toString()), e);
} else if (log.isInfoEnabled() && !(this instanceof Lifecycle.SingleUse)) {
// Rather than have every component that might need to call
// destroy() check for SingleUse, don't log an info message if
// multiple calls are made to destroy()
log.info(sm.getString("lifecycleBase.alreadyDestroyed", toString()));
}
return;
}
if (!state.equals(LifecycleState.STOPPED) && !state.equals(LifecycleState.FAILED) &&
!state.equals(LifecycleState.NEW) && !state.equals(LifecycleState.INITIALIZED)) {
invalidTransition(Lifecycle.BEFORE_DESTROY_EVENT);
}
try {
setStateInternal(LifecycleState.DESTROYING, null, false);
destroyInternal();
setStateInternal(LifecycleState.DESTROYED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.destroyFail", toString());
}
}
/**
* Sub-classes implement this method to perform any instance destruction
* required.
*
* @throws LifecycleException If the destruction fails
*/
protected abstract void destroyInternal() throws LifecycleException;
/**
* {@inheritDoc}
*/
@Override
public LifecycleState getState() {
return state;
}
/**
* {@inheritDoc}
*/
@Override
public String getStateName() {
return getState().toString();
}
/**
* Provides a mechanism for sub-classes to update the component state.
* Calling this method will automatically fire any associated
* {@link Lifecycle} event. It will also check that any attempted state
* transition is valid for a sub-class.
*
* @param state The new state for this component
* @throws LifecycleException when attempting to set an invalid state
*/
protected synchronized void setState(LifecycleState state) throws LifecycleException {
setStateInternal(state, null, true);
}
/**
* Provides a mechanism for sub-classes to update the component state.
* Calling this method will automatically fire any associated
* {@link Lifecycle} event. It will also check that any attempted state
* transition is valid for a sub-class.
*
* @param state The new state for this component
* @param data The data to pass to the associated {@link Lifecycle} event
* @throws LifecycleException when attempting to set an invalid state
*/
protected synchronized void setState(LifecycleState state, Object data)
throws LifecycleException {
setStateInternal(state, data, true);
}
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
throws LifecycleException {
if (log.isDebugEnabled()) {
log.debug(sm.getString("lifecycleBase.setState", this, state));
}
if (check) {
// Must have been triggered by one of the abstract methods (assume
// code in this class is correct)
// null is never a valid state
if (state == null) {
invalidTransition("null");
// Unreachable code - here to stop eclipse complaining about
// a possible NPE further down the method
return;
}
// Any method can transition to failed
// startInternal() permits STARTING_PREP to STARTING
// stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
// STOPPING
if (!(state == LifecycleState.FAILED ||
(this.state == LifecycleState.STARTING_PREP &&
state == LifecycleState.STARTING) ||
(this.state == LifecycleState.STOPPING_PREP &&
state == LifecycleState.STOPPING) ||
(this.state == LifecycleState.FAILED &&
state == LifecycleState.STOPPING))) {
// No other transition permitted
invalidTransition(state.name());
}
}
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
private void invalidTransition(String type) throws LifecycleException {
String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state);
throw new LifecycleException(msg);
}
private void handleSubClassException(Throwable t, String key, Object... args) throws LifecycleException {
setStateInternal(LifecycleState.FAILED, null, false);
ExceptionUtils.handleThrowable(t);
String msg = sm.getString(key, args);
if (getThrowOnFailure()) {
if (!(t instanceof LifecycleException)) {
t = new LifecycleException(msg, t);
}
throw (LifecycleException) t;
} else {
log.error(msg, t);
}
}
}

View File

@@ -0,0 +1,247 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.catalina.Globals;
import org.apache.catalina.JmxEnabled;
import org.apache.catalina.LifecycleException;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.res.StringManager;
public abstract class LifecycleMBeanBase extends LifecycleBase
implements JmxEnabled {
private static final Log log = LogFactory.getLog(LifecycleMBeanBase.class);
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
/* Cache components of the MBean registration. */
private String domain = null;
private ObjectName oname = null;
protected MBeanServer mserver = null;
/**
* Sub-classes wishing to perform additional initialization should override
* this method, ensuring that super.initInternal() is the first call in the
* overriding method.
*/
@Override
protected void initInternal() throws LifecycleException {
// If oname is not null then registration has already happened via
// preRegister().
if (oname == null) {
mserver = Registry.getRegistry(null, null).getMBeanServer();
oname = register(this, getObjectNameKeyProperties());
}
}
/**
* Sub-classes wishing to perform additional clean-up should override this
* method, ensuring that super.destroyInternal() is the last call in the
* overriding method.
*/
@Override
protected void destroyInternal() throws LifecycleException {
unregister(oname);
}
/**
* Specify the domain under which this component should be registered. Used
* with components that cannot (easily) navigate the component hierarchy to
* determine the correct domain to use.
*/
@Override
public final void setDomain(String domain) {
this.domain = domain;
}
/**
* Obtain the domain under which this component will be / has been
* registered.
*/
@Override
public final String getDomain() {
if (domain == null) {
domain = getDomainInternal();
}
if (domain == null) {
domain = Globals.DEFAULT_MBEAN_DOMAIN;
}
return domain;
}
/**
* Method implemented by sub-classes to identify the domain in which MBeans
* should be registered.
*
* @return The name of the domain to use to register MBeans.
*/
protected abstract String getDomainInternal();
/**
* Obtain the name under which this component has been registered with JMX.
*/
@Override
public final ObjectName getObjectName() {
return oname;
}
/**
* Allow sub-classes to specify the key properties component of the
* {@link ObjectName} that will be used to register this component.
*
* @return The string representation of the key properties component of the
* desired {@link ObjectName}
*/
protected abstract String getObjectNameKeyProperties();
/**
* Utility method to enable sub-classes to easily register additional
* components that don't implement {@link JmxEnabled} with an MBean server.
* <br>
* Note: This method should only be used once {@link #initInternal()} has
* been called and before {@link #destroyInternal()} has been called.
*
* @param obj The object the register
* @param objectNameKeyProperties The key properties component of the
* object name to use to register the
* object
*
* @return The name used to register the object
*/
protected final ObjectName register(Object obj,
String objectNameKeyProperties) {
// Construct an object name with the right domain
StringBuilder name = new StringBuilder(getDomain());
name.append(':');
name.append(objectNameKeyProperties);
ObjectName on = null;
try {
on = new ObjectName(name.toString());
Registry.getRegistry(null, null).registerComponent(obj, on, null);
} catch (MalformedObjectNameException e) {
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
e);
} catch (Exception e) {
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
e);
}
return on;
}
/**
* Utility method to enable sub-classes to easily unregister additional
* components that don't implement {@link JmxEnabled} with an MBean server.
* <br>
* Note: This method should only be used once {@link #initInternal()} has
* been called and before {@link #destroyInternal()} has been called.
*
* @param on The name of the component to unregister
*/
protected final void unregister(ObjectName on) {
// If null ObjectName, just return without complaint
if (on == null) {
return;
}
// If the MBeanServer is null, log a warning & return
if (mserver == null) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterNoServer", on));
return;
}
try {
mserver.unregisterMBean(on);
} catch (MBeanRegistrationException e) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
} catch (InstanceNotFoundException e) {
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
}
}
/**
* Not used - NOOP.
*/
@Override
public final void postDeregister() {
// NOOP
}
/**
* Not used - NOOP.
*/
@Override
public final void postRegister(Boolean registrationDone) {
// NOOP
}
/**
* Not used - NOOP.
*/
@Override
public final void preDeregister() throws Exception {
// NOOP
}
/**
* Allows the object to be registered with an alternative
* {@link MBeanServer} and/or {@link ObjectName}.
*/
@Override
public final ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception {
this.mserver = server;
this.oname = name;
this.domain = name.getDomain().intern();
return oname;
}
}

View File

@@ -0,0 +1,58 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block.
customObjectInputStream.logRequired=A valid logger is required for class name filtering with logging
customObjectInputStream.nomatch=The class [{0}] did not match the regular expression [{1}] for classes allowed to be deserialized
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension [{2}] not found.
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failed to find [{1}] required extension(s).
extensionValidator.failload=Failure loading extension [{0}]
extensionValidator.web-application-manifest=Web Application Manifest
hexUtil.bad=Bad hexadecimal digit
hexUtil.odd=Odd number of hexadecimal digits
introspection.classLoadFailed=Failed to load class [{0}]
lifecycleBase.alreadyDestroyed=The destroy() method was called on component [{0}] after destroy() had already been called. The second call will be ignored.
lifecycleBase.alreadyStarted=The start() method was called on component [{0}] after start() had already been called. The second call will be ignored.
lifecycleBase.alreadyStopped=The stop() method was called on component [{0}] after stop() had already been called. The second call will be ignored.
lifecycleBase.destroyFail=Failed to destroy component [{0}]
lifecycleBase.destroyStopFail=Called stop() on failed component [{0}] to trigger clean-up but it failed too
lifecycleBase.initFail=Failed to initialize component [{0}]
lifecycleBase.invalidTransition=An invalid Lifecycle transition was attempted ([{0}]) for component [{1}] in state [{2}]
lifecycleBase.setState=Setting state for [{0}] to [{1}]
lifecycleBase.startFail=Failed to start component [{0}]
lifecycleBase.stopFail=Failed to stop component [{0}]
lifecycleMBeanBase.registerFail=Failed to register object [{0}] with name [{1}] during component initialisation
lifecycleMBeanBase.unregisterFail=Failed to unregister MBean with name [{0}] during component destruction
lifecycleMBeanBase.unregisterNoServer=No MBean server was available to unregister the MBean [{0}]
netmask.cidrNegative=The CIDR [{0}] is negative
netmask.cidrNotNumeric=The CIDR [{0}] is not numeric
netmask.cidrTooBig=The CIDR [{0}] is greater than the address length [{1}]
netmask.invalidAddress=The address [{0}] is not valid
parameterMap.locked=No modifications are allowed to a locked ParameterMap
resourceSet.locked=No modifications are allowed to a locked ResourceSet
sessionIdGeneratorBase.createRandom=Creation of SecureRandom instance for session ID generation using [{0}] took [{1}] milliseconds.
sessionIdGeneratorBase.random=Exception initializing random number generator of class [{0}]. Falling back to java.secure.SecureRandom
sessionIdGeneratorBase.randomAlgorithm=Exception initializing random number generator using algorithm [{0}]
sessionIdGeneratorBase.randomProvider=Exception initializing random number generator using provider [{0}]

View File

@@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
customObjectInputStream.logRequired=Ein gültiger Logger ist für Klassennamenfilterung mit Loggen nötig
customObjectInputStream.nomatch=Die Klasse [{0}] wird nicht mit dem regulären Ausdruck [{1}] gefunden, der erlaubte deserialisierte Klassen bestimmt.
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Benötigte Erweiterung [{2}] nicht gefunden
introspection.classLoadFailed=Konnte Klasse [{0}] nicht laden
lifecycleBase.initFail=Konnte Komponente [{0}] nicht initialisieren
lifecycleBase.setState=Setze Status für [{0}] auf [{1}]
netmask.cidrNegative=Die CIDR [{0}] ist negativ
netmask.invalidAddress=Die Adresse [{0}] ist nicht gültig
sessionIdGeneratorBase.randomProvider=Während der Zufallsgenerator mit Hilfe des Providers [{0}] initialisiert wurde, trat eine Exception auf

View File

@@ -0,0 +1,39 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=Una excepción se ha producido durante la ejecución del bloque PrivilegedExceptionAction.
customObjectInputStream.logRequired=Se requiere un logeador váliso para el nombre de la clase filtrado con logeo
customObjectInputStream.nomatch=La clase [{0}] no concuerda con la expresión regular [{1}] para clases que tienen permitido el deserializamiento
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: La extensión no encuentra el [{2}] requerido.
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Imposible de hallar la(s) extension(es) [{1}] requerida(s).
extensionValidator.failload=No pude cargar la extensión [{0}]
extensionValidator.web-application-manifest=Manifiesto de Aplicación Web
hexUtil.bad=Dígito hexadecimal incorrecto
hexUtil.odd=Número de dígitos hexadecimales impar
introspection.classLoadFailed=Fallo al cargar la clase [{0}]
lifecycleBase.initFail=Fallo al iniciar el componente [{0}]
netmask.cidrNegative=El CIDR [{0}] es negativo
parameterMap.locked=No se permiten modificaciones en un ParameterMap bloqueado
resourceSet.locked=No se permiten modificaciones en un ResourceSet bloqueado
sessionIdGeneratorBase.random=Excepción inicializando generador de números aleatorios de clase [{0}]

View File

@@ -0,0 +1,56 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=Une exception s'est produite lors de l'execution du bloc PrivilegedExceptionAction.
customObjectInputStream.logRequired=Un enregistreur ("logger") valide est requis pour filtrer par nom de classe
customObjectInputStream.nomatch=La classe [{0}] n''est pas acceptée par l''expression régulière [{1}] qui autorise la désérialisation
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise [{2}] est introuvable.
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver [{1}] extension(s) requise(s).
extensionValidator.failload=Erreur de chargement de l''extension [{0}]
extensionValidator.web-application-manifest=Web Application Manifest
hexUtil.bad=Mauvais digit hexadecimal
hexUtil.odd=Nombre impair de digits hexadecimaux
introspection.classLoadFailed=Echec du chargement de la classe [{0}]
lifecycleBase.alreadyDestroyed=La méthode destroy() a été appelée sur le composant [{0}] après que destroy() ait déjà été appelé, le deuxième appel sera ignoré
lifecycleBase.alreadyStarted=La méthode start() a été appelée sur le composant [{0}] après que start() ait déjà été appelé, le deuxième appel sera ignoré
lifecycleBase.alreadyStopped=La méthode stop() a été appelée sur le composant [{0}] après que stop() ait déjà été appelé, le deuxième appel sera ignoré
lifecycleBase.destroyFail=Echec de la destruction du composant [{0}]
lifecycleBase.destroyStopFail=L''appel de stop() sur le composant en échec [{0}] pour causer un nettoyage a échoué
lifecycleBase.initFail=Echec d''initialisation du composant [{0}]
lifecycleBase.invalidTransition=Un transition de Lifecycle invalide a été tentée ([{0}]) pour le composant [{1}] dans l''état [{2}]
lifecycleBase.setState=Fixe l''état pour [{0}] à [{1}]
lifecycleBase.startFail=Echec de démarrage du composant [{0}]
lifecycleBase.stopFail=Echec de l''arrêt du composant [{0}]
lifecycleMBeanBase.registerFail=Echec de l''enregistrement de l''objet [{0}] avec le nom [{1}] pendant l''initialisation du composant
netmask.cidrNegative=Le CIDR [{0}] est négatif
netmask.cidrNotNumeric=Le CIDR [{0}] n''est pas un nombre
netmask.cidrTooBig=Le CIDR [{0}] est plus grand que la longueur de l''adresse [{1}]
netmask.invalidAddress=L''adresse [{0}] est invalide
parameterMap.locked=Aucune modification n'est autorisée sur un ParameterMap verrouillé
resourceSet.locked=Aucune modification n'est autorisée sur un ResourceSet verrouillé
sessionIdGeneratorBase.createRandom=La création de l''instance de SecureRandom pour le générateur d''id de session en utilisant [{0}] a pris [{1}] millisecondes
sessionIdGeneratorBase.random=Exception durant l''initialisation de la classe du générateur de nombre aléatoire [{0}]
sessionIdGeneratorBase.randomAlgorithm=Erreur lors de l''initialisation du générateur de nombres aléatoires en utilisant l''algorithme [{0}]
sessionIdGeneratorBase.randomProvider=Exception lors de l''initialisation du générateur de nombres aléatoires utilisant le fournisseur [{0}]

View File

@@ -0,0 +1,56 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=PrivilegedExceptionActionブロックを実行中に例外が発生しました。
customObjectInputStream.logRequired=ロギングによるクラス名のフィルタリングには有効なロガーが必要です
customObjectInputStream.nomatch=クラス [{0}] はデシリアライズの許可されたクラス名の正規表現 [{1}] にマッチしません。
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: 必要な拡張 [{2}] が見つかりません。
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: 必要な拡張 [{1}] が見つかりません。
extensionValidator.failload=拡張 [{0}] のロードに失敗しました
extensionValidator.web-application-manifest=Webアプリケーションマニフェスト
hexUtil.bad=無効な16進数値です
hexUtil.odd=奇数桁の16進数値です
introspection.classLoadFailed=クラス [{0}] の読み込みに失敗しました。
lifecycleBase.alreadyDestroyed=destroy()メソッドが既に呼び出された後で、コンポーネント[{0}]に対して呼び出されました。 2番目の呼び出しは無視されます。
lifecycleBase.alreadyStarted=以前に start() を呼び出したコンポーネント [{0}] の start() を呼び出しました。二度目の呼び出しは無視します。
lifecycleBase.alreadyStopped=stop()メソッドが既にコールされた後、コンポーネント[{0}]に対して呼び出されました。 2番目の呼び出しは無視されます。
lifecycleBase.destroyFail=コンポーネント [{0}] を破棄できません。
lifecycleBase.destroyStopFail=失敗したコンポーネント[{0}]に対してstop()を呼び出してクリーンアップをトリガーしましたが、失敗しました。
lifecycleBase.initFail=コンポーネント[{0}] の初期化に失敗しました。
lifecycleBase.invalidTransition=状態[{2}]のコンポーネント[{1}]の無効なライフサイクル遷移が試みられました([{0}])。
lifecycleBase.setState=[{0}]の状態を[{1}]に設定します
lifecycleBase.startFail=コンポーネント[{0}]の開始に失敗しました。
lifecycleBase.stopFail=コンポーネント [{0}] を停止できません。
lifecycleMBeanBase.registerFail=コンポーネントの初期化時にオブジェクト [{0}] を名前 [{1}] で登録できませんでした。
netmask.cidrNegative=CIDR [{0}] に負の値が指定されています。
netmask.cidrNotNumeric=CIDR [{0}]は数値ではありません
netmask.cidrTooBig=CIDR [{0}] はアドレス範囲 [{1}] を越えています。
netmask.invalidAddress=アドレス[{0}]は無効です
parameterMap.locked=ロックされたParameterMapは変更が許されません
resourceSet.locked=ロックされたResourceSetは変更が許されません
sessionIdGeneratorBase.createRandom=セッション ID を生成するための SecureRandom インスタンスの作成に [{1}] ミリ秒かかりました。アルゴリズムは [{1}] です。
sessionIdGeneratorBase.random=クラス [{0}] の乱数発生器の初期化の例外です
sessionIdGeneratorBase.randomAlgorithm=アルゴリズム[{0}]を使用して乱数ジェネレータを初期化する際の例外
sessionIdGeneratorBase.randomProvider=プロバイダ[{0}]を使用して乱数ジェネレータを初期化中に例外が発生しました

View File

@@ -0,0 +1,53 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=PrivilegedExceptionAction 블록을 실행하는 동안 예외가 발생했습니다.
customObjectInputStream.logRequired=로그를 남기면서 클래스 이름을 필터링 하기 위해서는 유효한 Logger가 필요합니다.
customObjectInputStream.nomatch=클래스 [{0}]은(는), 역직렬화 되도록 허용된 클래스들의 정규식 패턴 [{1}]과(와) 부합되지 않습니다.
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}] : 필수 extension [{2}]을(를) 찾을 수 없습니다.
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: 필수 extension(들)을 찾는 과정에서 [{1}]번의 실패 발생
extensionValidator.failload=Extension [{0}]을(를) 로드하는 중 실패
extensionValidator.web-application-manifest=웹 애플리케이션 Manifest
introspection.classLoadFailed=클래스 [{0}]을(를) 로드하지 못했습니다.
lifecycleBase.alreadyDestroyed=이미 destroy() 메소드가 호출되었던 구성요소 [{0}]에서, 다시 destroy()가 호출되었습니다. 두번째 호출은 무시될 것입니다.
lifecycleBase.alreadyStarted=start()가 이미 호출된 후에, 구성요소 [{0}]에 start() 메소드가 호출되었습니다. 두번째 호출은 무시될 것입니다.
lifecycleBase.alreadyStopped=stop()이 이미 호출된 후에, 구성요소 [{0}]에 대해 stop() 메소드가 호출되었습니다. 두번째 호출은 무시될 것입니다.
lifecycleBase.destroyFail=구성요소 [{0}]을(를) 소멸시키지 못했습니다.
lifecycleBase.destroyStopFail=실패한 구성요소 [{0}]에 대해, clean-up을 개시하기 위해 stop()을 호출했으나, 이 호출 또한 실패했습니다.
lifecycleBase.initFail=구성요소 [{0}]을(를) 초기화하지 못했습니다.
lifecycleBase.invalidTransition=상태 [{2}]에 있는 구성 요소 [{1}]에 대해, 유효하지 않은 Lifecycle 전환이 시도되었습니다 ([{0}]).
lifecycleBase.setState=[{0}]을(를) 위한 상태를 [{1}](으)로 설정합니다.
lifecycleBase.startFail=구성요소 [{0}]을(를) 시작하지 못했습니다.
lifecycleBase.stopFail=구성요소 [{0}]을(를) 중지시키지 못했습니다.
lifecycleMBeanBase.registerFail=구성요소 초기화 중, [{1}](이)라는 이름을 가진 객체 [{0}]을(를) 등록하지 못했습니다.
netmask.cidrNegative=CIDR [{0}]이(가) 음수입니다.
netmask.cidrNotNumeric=CIDR [{0}]이(가) 숫자가 아닙니다.
netmask.cidrTooBig=CIDR [{0}]이(가) 주소 길이 [{1}]보다 큽니다.
netmask.invalidAddress=주소 [{0}]은(는) 유효하지 않습니다.
parameterMap.locked=잠금 상태인 ParameterMap에 대한 변경이 허용되지 않습니다.
resourceSet.locked=잠금 상태인 ResourceSet에 대한 변경은 허용되지 않습니다.
sessionIdGeneratorBase.createRandom=[{0}] 알고리즘을 사용하여, 세션 ID를 생성하기 위한 SecureRandom 객체를 생성하는데, [{1}] 밀리초가 소요됐습니다.
sessionIdGeneratorBase.random=클래스 [{0}]의 난수 발생기를 초기화하는 중 예외 발생. java.secure.SecureRandom으로 대체합니다.
sessionIdGeneratorBase.randomAlgorithm=알고리즘 [{0}]을(를) 사용하여 난수 발생기를 초기화하는 중 오류 발생
sessionIdGeneratorBase.randomProvider=Provider [{0}]을(를) 사용하여, 난수 발생기를 초기화하는 중 예외 발생

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
introspection.classLoadFailed=Не возможно закрузить класс [{0}]

View File

@@ -0,0 +1,37 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
SecurityUtil.doAsPrivilege=运行PrivilegedExceptionAction块时发生异常。
customObjectInputStream.logRequired=使用日志记录进行类名过滤需要一个有效的日志记录器
customObjectInputStream.nomatch=类不能匹配合适的表达式,因为类被允许反序列化
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: 请求的拓展[{2}]未找到。
extensionValidator.web-application-manifest=web 应用程序清单
introspection.classLoadFailed=加载 class [{0}] 失败
lifecycleBase.alreadyStarted=在调用start()之后,在组件[{0}]上调用start()方法。第二个电话将被忽略。
lifecycleBase.destroyStopFail=在失败组件[{0}]上调用Stop()以触发清理,但也失败了
lifecycleBase.initFail=初始化组件[{0}]失败。
lifecycleBase.setState=设置状态从[{0}]到[{1}]
lifecycleMBeanBase.registerFail=在组件初始化期间,无法注册名为{1}的对象{0}]
netmask.cidrNegative=CIDR [{0}]为负数。
netmask.invalidAddress=地址 [{0}] 无效
sessionIdGeneratorBase.randomAlgorithm=使用算法[{0}]初始化随机数生成器时发生异常
sessionIdGeneratorBase.randomProvider=使用程序提供的初始化随机数生成器异常[{0}]

View File

@@ -0,0 +1,607 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* MIME2Java is a convenience class which handles conversions between MIME charset names
* and Java encoding names.
* <p>The supported XML encodings are the intersection of XML-supported code sets and those
* supported in JDK 1.1.
* <p>MIME charset names are used on <var>xmlEncoding</var> parameters to methods such
* as <code>TXDocument#setEncoding</code> and <code>DTD#setEncoding</code>.
* <p>Java encoding names are used on <var>encoding</var> parameters to
* methods such as <code>TXDocument#printWithFormat</code> and <code>DTD#printExternal</code>.
* <TABLE>
* <caption>MIME charset name to Java encoding name mapping</caption>
* <TR>
* <TD>
* <P><B>Common Name</B>
* </TD>
* <TD>
* <P><B>Use this name in XML files</B>
* </TD>
* <TD>
* <P><B>Name Type</B>
* </TD>
* <TD>
* <P><B>Xerces converts to this Java Encoder Name</B>
* </TD>
* </TR>
* <TR>
* <TD>8 bit Unicode</TD>
* <TD>
* <P>UTF-8
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>UTF8
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin 1</TD>
* <TD>
* <P>ISO-8859-1
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-1
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin 2</TD>
* <TD>
* <P>ISO-8859-2
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-2
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin 3</TD>
* <TD>
* <P>ISO-8859-3
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-3
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin 4</TD>
* <TD>
* <P>ISO-8859-4
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-4
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin Cyrillic</TD>
* <TD>
* <P>ISO-8859-5
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-5
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin Arabic</TD>
* <TD>
* <P>ISO-8859-6
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-6
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin Greek</TD>
* <TD>
* <P>ISO-8859-7
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-7
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin Hebrew</TD>
* <TD>
* <P>ISO-8859-8
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-8
* </TD>
* </TR>
* <TR>
* <TD>ISO Latin 5</TD>
* <TD>
* <P>ISO-8859-9
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>ISO-8859-9
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: US</TD>
* <TD>
* <P>ebcdic-cp-us
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp037
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Canada</TD>
* <TD>
* <P>ebcdic-cp-ca
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp037
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Netherlands</TD>
* <TD>
* <P>ebcdic-cp-nl
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp037
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Denmark</TD>
* <TD>
* <P>ebcdic-cp-dk
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp277
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Norway</TD>
* <TD>
* <P>ebcdic-cp-no
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp277
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Finland</TD>
* <TD>
* <P>ebcdic-cp-fi
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp278
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Sweden</TD>
* <TD>
* <P>ebcdic-cp-se
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp278
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Italy</TD>
* <TD>
* <P>ebcdic-cp-it
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp280
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Spain, Latin America</TD>
* <TD>
* <P>ebcdic-cp-es
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp284
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Great Britain</TD>
* <TD>
* <P>ebcdic-cp-gb
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp285
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: France</TD>
* <TD>
* <P>ebcdic-cp-fr
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp297
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Arabic</TD>
* <TD>
* <P>ebcdic-cp-ar1
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp420
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Hebrew</TD>
* <TD>
* <P>ebcdic-cp-he
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp424
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Switzerland</TD>
* <TD>
* <P>ebcdic-cp-ch
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp500
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Roece</TD>
* <TD>
* <P>ebcdic-cp-roece
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp870
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Yogoslavia</TD>
* <TD>
* <P>ebcdic-cp-yu
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp870
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Iceland</TD>
* <TD>
* <P>ebcdic-cp-is
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp871
* </TD>
* </TR>
* <TR>
* <TD>EBCDIC: Urdu</TD>
* <TD>
* <P>ebcdic-cp-ar2
* </TD>
* <TD>
* <P>IANA
* </TD>
* <TD>
* <P>cp918
* </TD>
* </TR>
* <TR>
* <TD>Chinese for PRC, mixed 1/2 byte</TD>
* <TD>
* <P>gb2312
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>GB2312
* </TD>
* </TR>
* <TR>
* <TD>Extended Unix Code, packed for Japanese</TD>
* <TD>
* <P>euc-jp
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>eucjis
* </TD>
* </TR>
* <TR>
* <TD>Japanese: iso-2022-jp</TD>
* <TD>
* <P>iso-2020-jp
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>JIS
* </TD>
* </TR>
* <TR>
* <TD>Japanese: Shift JIS</TD>
* <TD>
* <P>Shift_JIS
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>SJIS
* </TD>
* </TR>
* <TR>
* <TD>Chinese: Big5</TD>
* <TD>
* <P>Big5
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>Big5
* </TD>
* </TR>
* <TR>
* <TD>Extended Unix Code, packed for Korean</TD>
* <TD>
* <P>euc-kr
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>iso2022kr
* </TD>
* </TR>
* <TR>
* <TD>Cyrillic</TD>
* <TD>
* <P>koi8-r
* </TD>
* <TD>
* <P>MIME
* </TD>
* <TD>
* <P>koi8-r
* </TD>
* </TR>
* </TABLE>
*
* @author TAMURA Kent &lt;kent@trl.ibm.co.jp&gt;
*
* @deprecated Unused. Will be removed in Tomcat 9.
*/
@Deprecated
public class MIME2Java {
private static final Map<String,String> s_enchash;
private static final Map<String,String> s_revhash;
static {
s_enchash = new HashMap<>();
// <preferred MIME name>, <Java encoding name>
s_enchash.put("UTF-8", "UTF8");
s_enchash.put("US-ASCII", "8859_1"); // ?
s_enchash.put("ISO-8859-1", "8859_1");
s_enchash.put("ISO-8859-2", "8859_2");
s_enchash.put("ISO-8859-3", "8859_3");
s_enchash.put("ISO-8859-4", "8859_4");
s_enchash.put("ISO-8859-5", "8859_5");
s_enchash.put("ISO-8859-6", "8859_6");
s_enchash.put("ISO-8859-7", "8859_7");
s_enchash.put("ISO-8859-8", "8859_8");
s_enchash.put("ISO-8859-9", "8859_9");
s_enchash.put("ISO-2022-JP", "JIS");
s_enchash.put("SHIFT_JIS", "SJIS");
s_enchash.put("EUC-JP", "EUCJIS");
s_enchash.put("GB2312", "GB2312");
s_enchash.put("BIG5", "Big5");
s_enchash.put("EUC-KR", "KSC5601");
s_enchash.put("ISO-2022-KR", "ISO2022KR");
s_enchash.put("KOI8-R", "KOI8_R");
s_enchash.put("EBCDIC-CP-US", "CP037");
s_enchash.put("EBCDIC-CP-CA", "CP037");
s_enchash.put("EBCDIC-CP-NL", "CP037");
s_enchash.put("EBCDIC-CP-DK", "CP277");
s_enchash.put("EBCDIC-CP-NO", "CP277");
s_enchash.put("EBCDIC-CP-FI", "CP278");
s_enchash.put("EBCDIC-CP-SE", "CP278");
s_enchash.put("EBCDIC-CP-IT", "CP280");
s_enchash.put("EBCDIC-CP-ES", "CP284");
s_enchash.put("EBCDIC-CP-GB", "CP285");
s_enchash.put("EBCDIC-CP-FR", "CP297");
s_enchash.put("EBCDIC-CP-AR1", "CP420");
s_enchash.put("EBCDIC-CP-HE", "CP424");
s_enchash.put("EBCDIC-CP-CH", "CP500");
s_enchash.put("EBCDIC-CP-ROECE", "CP870");
s_enchash.put("EBCDIC-CP-YU", "CP870");
s_enchash.put("EBCDIC-CP-IS", "CP871");
s_enchash.put("EBCDIC-CP-AR2", "CP918");
// j:CNS11643 -> EUC-TW?
// ISO-2022-CN? ISO-2022-CN-EXT?
s_revhash = new HashMap<>();
// <Java encoding name>, <preferred MIME name>
s_revhash.put("UTF8", "UTF-8");
//s_revhash.put("8859_1", "US-ASCII"); // ?
s_revhash.put("8859_1", "ISO-8859-1");
s_revhash.put("8859_2", "ISO-8859-2");
s_revhash.put("8859_3", "ISO-8859-3");
s_revhash.put("8859_4", "ISO-8859-4");
s_revhash.put("8859_5", "ISO-8859-5");
s_revhash.put("8859_6", "ISO-8859-6");
s_revhash.put("8859_7", "ISO-8859-7");
s_revhash.put("8859_8", "ISO-8859-8");
s_revhash.put("8859_9", "ISO-8859-9");
s_revhash.put("JIS", "ISO-2022-JP");
s_revhash.put("SJIS", "Shift_JIS");
s_revhash.put("EUCJIS", "EUC-JP");
s_revhash.put("GB2312", "GB2312");
s_revhash.put("BIG5", "Big5");
s_revhash.put("KSC5601", "EUC-KR");
s_revhash.put("ISO2022KR", "ISO-2022-KR");
s_revhash.put("KOI8_R", "KOI8-R");
s_revhash.put("CP037", "EBCDIC-CP-US");
s_revhash.put("CP037", "EBCDIC-CP-CA");
s_revhash.put("CP037", "EBCDIC-CP-NL");
s_revhash.put("CP277", "EBCDIC-CP-DK");
s_revhash.put("CP277", "EBCDIC-CP-NO");
s_revhash.put("CP278", "EBCDIC-CP-FI");
s_revhash.put("CP278", "EBCDIC-CP-SE");
s_revhash.put("CP280", "EBCDIC-CP-IT");
s_revhash.put("CP284", "EBCDIC-CP-ES");
s_revhash.put("CP285", "EBCDIC-CP-GB");
s_revhash.put("CP297", "EBCDIC-CP-FR");
s_revhash.put("CP420", "EBCDIC-CP-AR1");
s_revhash.put("CP424", "EBCDIC-CP-HE");
s_revhash.put("CP500", "EBCDIC-CP-CH");
s_revhash.put("CP870", "EBCDIC-CP-ROECE");
s_revhash.put("CP870", "EBCDIC-CP-YU");
s_revhash.put("CP871", "EBCDIC-CP-IS");
s_revhash.put("CP918", "EBCDIC-CP-AR2");
}
private MIME2Java() {
}
/**
* Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name.
* @param mimeCharsetName Case insensitive MIME charset name: <code>UTF-8, US-ASCII, ISO-8859-1,
* ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
* ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS,
* EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R,
* EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK,
* EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT,
* EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1,
* EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU,
* EBCDIC-CP-IS and EBCDIC-CP-AR2</code>.
* @return Java encoding name, or <var>null</var> if <var>mimeCharsetName</var>
* is unknown.
* @see #reverse
*/
public static String convert(String mimeCharsetName) {
return s_enchash.get(mimeCharsetName.toUpperCase(Locale.ENGLISH));
}
/**
* Convert a Java encoding name to MIME charset name.
* Available values of <i>encoding</i> are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4",
* "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS",
* "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278",
* "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918".
* @param encoding Case insensitive Java encoding name: <code>UTF8, 8859_1, 8859_2, 8859_3,
* 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS,
* GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278,
* CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871
* and CP918</code>.
* @return MIME charset name, or <var>null</var> if <var>encoding</var> is unknown.
* @see #convert
*/
public static String reverse(String encoding) {
return s_revhash.get(encoding.toUpperCase(Locale.ENGLISH));
}
}

View File

@@ -0,0 +1,227 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.ArrayList;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Representation of a Manifest file and its available extensions and
* required extensions
*
* @author Greg Murray
* @author Justyna Horwat
*/
public class ManifestResource {
// ------------------------------------------------------------- Properties
// These are the resource types for determining effect error messages
public static final int SYSTEM = 1;
public static final int WAR = 2;
public static final int APPLICATION = 3;
private ArrayList<Extension> availableExtensions = null;
private ArrayList<Extension> requiredExtensions = null;
private final String resourceName;
private final int resourceType;
public ManifestResource(String resourceName, Manifest manifest,
int resourceType) {
this.resourceName = resourceName;
this.resourceType = resourceType;
processManifest(manifest);
}
/**
* Gets the name of the resource
*
* @return The name of the resource
*/
public String getResourceName() {
return resourceName;
}
/**
* Gets the list of available extensions
*
* @return List of available extensions
*/
public ArrayList<Extension> getAvailableExtensions() {
return availableExtensions;
}
/**
* Gets the list of required extensions
*
* @return List of required extensions
*/
public ArrayList<Extension> getRequiredExtensions() {
return requiredExtensions;
}
// --------------------------------------------------------- Public Methods
/**
* Gets the number of available extensions
*
* @return The number of available extensions
*/
public int getAvailableExtensionCount() {
return (availableExtensions != null) ? availableExtensions.size() : 0;
}
/**
* Gets the number of required extensions
*
* @return The number of required extensions
*/
public int getRequiredExtensionCount() {
return (requiredExtensions != null) ? requiredExtensions.size() : 0;
}
/**
* Returns <code>true</code> if all required extension dependencies
* have been meet for this <code>ManifestResource</code> object.
*
* @return boolean true if all extension dependencies have been satisfied
*/
public boolean isFulfilled() {
if (requiredExtensions == null) {
return true;
}
for (Extension ext : requiredExtensions) {
if (!ext.isFulfilled()) return false;
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ManifestResource[");
sb.append(resourceName);
sb.append(", isFulfilled=");
sb.append(isFulfilled() +"");
sb.append(", requiredExtensionCount =");
sb.append(getRequiredExtensionCount());
sb.append(", availableExtensionCount=");
sb.append(getAvailableExtensionCount());
switch (resourceType) {
case SYSTEM : sb.append(", resourceType=SYSTEM"); break;
case WAR : sb.append(", resourceType=WAR"); break;
case APPLICATION : sb.append(", resourceType=APPLICATION"); break;
}
sb.append("]");
return sb.toString();
}
// -------------------------------------------------------- Private Methods
private void processManifest(Manifest manifest) {
availableExtensions = getAvailableExtensions(manifest);
requiredExtensions = getRequiredExtensions(manifest);
}
/**
* Return the set of <code>Extension</code> objects representing optional
* packages that are required by the application associated with the
* specified <code>Manifest</code>.
*
* @param manifest Manifest to be parsed
*
* @return List of required extensions, or null if the application
* does not require any extensions
*/
private ArrayList<Extension> getRequiredExtensions(Manifest manifest) {
Attributes attributes = manifest.getMainAttributes();
String names = attributes.getValue("Extension-List");
if (names == null)
return null;
ArrayList<Extension> extensionList = new ArrayList<>();
names += " ";
while (true) {
int space = names.indexOf(' ');
if (space < 0)
break;
String name = names.substring(0, space).trim();
names = names.substring(space + 1);
String value =
attributes.getValue(name + "-Extension-Name");
if (value == null)
continue;
Extension extension = new Extension();
extension.setExtensionName(value);
extension.setImplementationURL
(attributes.getValue(name + "-Implementation-URL"));
extension.setImplementationVendorId
(attributes.getValue(name + "-Implementation-Vendor-Id"));
String version = attributes.getValue(name + "-Implementation-Version");
extension.setImplementationVersion(version);
extension.setSpecificationVersion
(attributes.getValue(name + "-Specification-Version"));
extensionList.add(extension);
}
return extensionList;
}
/**
* Return the set of <code>Extension</code> objects representing optional
* packages that are bundled with the application associated with the
* specified <code>Manifest</code>.
*
* @param manifest Manifest to be parsed
*
* @return List of available extensions, or null if the web application
* does not bundle any extensions
*/
private ArrayList<Extension> getAvailableExtensions(Manifest manifest) {
Attributes attributes = manifest.getMainAttributes();
String name = attributes.getValue("Extension-Name");
if (name == null)
return null;
ArrayList<Extension> extensionList = new ArrayList<>();
Extension extension = new Extension();
extension.setExtensionName(name);
extension.setImplementationURL(
attributes.getValue("Implementation-URL"));
extension.setImplementationVendor(
attributes.getValue("Implementation-Vendor"));
extension.setImplementationVendorId(
attributes.getValue("Implementation-Vendor-Id"));
extension.setImplementationVersion(
attributes.getValue("Implementation-Version"));
extension.setSpecificationVersion(
attributes.getValue("Specification-Version"));
extensionList.add(extension);
return extensionList;
}
}

View File

@@ -0,0 +1,241 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.tomcat.util.res.StringManager;
/**
* A class representing a CIDR netmask.
*
* <p>
* The constructor takes a string as an argument which represents a netmask, as
* per the CIDR notation -- whether this netmask be IPv4 or IPv6. It then
* extracts the network address (before the /) and the CIDR prefix (after the
* /), and tells through the #matches() method whether a candidate
* {@link InetAddress} object fits in the recorded range.
* </p>
*
* <p>
* As byte arrays as returned by <code>InetAddress.getByName()</code> are always
* in network byte order, finding a match is therefore as simple as testing
* whether the n first bits (where n is the CIDR) are the same in both byte
* arrays (the one of the network address and the one of the candidate address).
* We do that by first doing byte comparisons, then testing the last bits if any
* (that is, if the remainder of the integer division of the CIDR by 8 is not
* 0).
* </p>
*
* <p>
* As a bonus, if no '/' is found in the input, it is assumed that an exact
* address match is required.
* </p>
*/
public final class NetMask {
private static final StringManager sm = StringManager.getManager(NetMask.class);
/**
* The argument to the constructor, used for .toString()
*/
private final String expression;
/**
* The byte array representing the address extracted from the expression
*/
private final byte[] netaddr;
/**
* The number of bytes to test for equality (CIDR / 8)
*/
private final int nrBytes;
/**
* The right shift to apply to the last byte if CIDR % 8 is not 0; if it is
* 0, this variable is set to 0
*/
private final int lastByteShift;
/**
* Constructor
*
* @param input the CIDR netmask
* @throws IllegalArgumentException if the netmask is not correct (invalid
* address specification, malformed CIDR prefix, etc)
*/
public NetMask(final String input) {
expression = input;
final int idx = input.indexOf("/");
/*
* Handle the "IP only" case first
*/
if (idx == -1) {
try {
netaddr = InetAddress.getByName(input).getAddress();
} catch (UnknownHostException e) {
throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", input));
}
nrBytes = netaddr.length;
lastByteShift = 0;
return;
}
/*
* OK, we do have a netmask specified, so let's extract both the address
* and the CIDR.
*/
final String addressPart = input.substring(0, idx), cidrPart = input.substring(idx + 1);
try {
/*
* The address first...
*/
netaddr = InetAddress.getByName(addressPart).getAddress();
} catch (UnknownHostException e) {
throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", addressPart));
}
final int addrlen = netaddr.length * 8;
final int cidr;
try {
/*
* And then the CIDR.
*/
cidr = Integer.parseInt(cidrPart);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(sm.getString("netmask.cidrNotNumeric", cidrPart));
}
/*
* We don't want a negative CIDR, nor do we want a CIDR which is greater
* than the address length (consider 0.0.0.0/33, or ::/129)
*/
if (cidr < 0) {
throw new IllegalArgumentException(sm.getString("netmask.cidrNegative", cidrPart));
}
if (cidr > addrlen) {
throw new IllegalArgumentException(
sm.getString("netmask.cidrTooBig", cidrPart, Integer.valueOf(addrlen)));
}
nrBytes = cidr / 8;
/*
* These last two lines could be shortened to:
*
* lastByteShift = (8 - (cidr % 8)) & 7;
*
* But... It's not worth it. In fact, explaining why it could work would
* be too long to be worth the trouble, so let's do it the simple way...
*/
final int remainder = cidr % 8;
lastByteShift = (remainder == 0) ? 0 : 8 - remainder;
}
/**
* Test if a given address matches this netmask.
*
* @param addr The {@link java.net.InetAddress} to test
* @return true on match, false otherwise
*/
public boolean matches(final InetAddress addr) {
final byte[] candidate = addr.getAddress();
/*
* OK, remember that a CIDR prefix tells the number of BITS which should
* be equal between this NetMask's recorded address (netaddr) and the
* candidate address. One byte is 8 bits, no matter what, and IP
* addresses, whether they be IPv4 or IPv6, are big endian, aka MSB,
* Most Significant Byte (first).
*
* We therefore need to get the byte array of the candidate address,
* compare as many bytes of the candidate address with the recorded
* address as the CIDR prefix tells us to (that is, CIDR / 8), and then
* deal with the remaining bits -- if any.
*
* But prior to that, a simple test can be done: we deal with IP
* addresses here, which means IPv4 and IPv6. IPv4 addresses are encoded
* on 4 bytes, IPv6 addresses are encoded on 16 bytes. If the candidate
* address length is different than this NetMask's address, we don't
* have a match.
*/
if (candidate.length != netaddr.length) {
return false;
}
/*
* Now do the byte-compare. The constructor has recorded the number of
* bytes to compare in nrBytes, use that. If any of the byte we have to
* compare is different than what we expect, we don't have a match.
*
* If, on the opposite, after this loop, all bytes have been deemed
* equal, then the loop variable i will point to the byte right after
* that -- which we will need...
*/
int i = 0;
for (; i < nrBytes; i++) {
if (netaddr[i] != candidate[i]) {
return false;
}
}
/*
* ... if there are bits left to test. There aren't any if lastByteShift
* is set to 0.
*/
if (lastByteShift == 0) {
return true;
}
/*
* If it is not 0, however, we must test for the relevant bits in the
* next byte (whatever is in the bytes after that doesn't matter). We do
* it this way (remember that lastByteShift contains the amount of bits
* we should _right_ shift the last byte):
*
* - grab both bytes at index i, both from the netmask address and the
* candidate address; - xor them both.
*
* After the xor, it means that all the remaining bits of the CIDR
* should be set to 0...
*/
final int lastByte = netaddr[i] ^ candidate[i];
/*
* ... Which means that right shifting by lastByteShift should be 0.
*/
return lastByte >> lastByteShift == 0;
}
@Override
public String toString() {
return expression;
}
}

View File

@@ -0,0 +1,256 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.tomcat.util.res.StringManager;
/**
* Implementation of <strong>java.util.Map</strong> that includes a
* <code>locked</code> property. This class can be used to safely expose
* Catalina internal parameter map objects to user classes without having
* to clone them in order to avoid modifications. When first created, a
* <code>ParmaeterMap</code> instance is not locked.
*
* @param <K> The type of Key
* @param <V> The type of Value
*
* @author Craig R. McClanahan
*/
public final class ParameterMap<K,V> implements Map<K,V>, Serializable {
private static final long serialVersionUID = 2L;
private final Map<K,V> delegatedMap;
private final Map<K,V> unmodifiableDelegatedMap;
/**
* Construct a new, empty map with the default initial capacity and
* load factor.
*/
public ParameterMap() {
delegatedMap = new LinkedHashMap<>();
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new, empty map with the specified initial capacity and
* default load factor.
*
* @param initialCapacity The initial capacity of this map
*/
public ParameterMap(int initialCapacity) {
delegatedMap = new LinkedHashMap<>(initialCapacity);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new, empty map with the specified initial capacity and
* load factor.
*
* @param initialCapacity The initial capacity of this map
* @param loadFactor The load factor of this map
*/
public ParameterMap(int initialCapacity, float loadFactor) {
delegatedMap = new LinkedHashMap<>(initialCapacity, loadFactor);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* Construct a new map with the same mappings as the given map.
*
* @param map Map whose contents are duplicated in the new map
*/
public ParameterMap(Map<K,V> map) {
delegatedMap = new LinkedHashMap<>(map);
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
}
/**
* The current lock state of this parameter map.
*/
private boolean locked = false;
/**
* @return the locked state of this parameter map.
*/
public boolean isLocked() {
return locked;
}
/**
* Set the locked state of this parameter map.
*
* @param locked The new locked state
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* The string manager for this package.
*/
private static final StringManager sm = StringManager.getManager("org.apache.catalina.util");
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public void clear() {
checkLocked();
delegatedMap.clear();
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public V put(K key, V value) {
checkLocked();
return delegatedMap.put(key, value);
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public void putAll(Map<? extends K,? extends V> map) {
checkLocked();
delegatedMap.putAll(map);
}
/**
* {@inheritDoc}
*
* @exception IllegalStateException if this map is currently locked
*/
@Override
public V remove(Object key) {
checkLocked();
return delegatedMap.remove(key);
}
private void checkLocked() {
if (locked) {
throw new IllegalStateException(sm.getString("parameterMap.locked"));
}
}
@Override
public int size() {
return delegatedMap.size();
}
@Override
public boolean isEmpty() {
return delegatedMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegatedMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegatedMap.containsValue(value);
}
@Override
public V get(Object key) {
return delegatedMap.get(key);
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Set} view of the keys
* contained in this map if it is locked.
*/
@Override
public Set<K> keySet() {
if (locked) {
return unmodifiableDelegatedMap.keySet();
}
return delegatedMap.keySet();
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Collection} view of the
* values contained in this map if it is locked.
*/
@Override
public Collection<V> values() {
if (locked) {
return unmodifiableDelegatedMap.values();
}
return delegatedMap.values();
}
/**
* {@inheritDoc}
* <p>
* Returns an <strong>unmodifiable</strong> {@link Set} view of the mappings
* contained in this map if it is locked.
*/
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
if (locked) {
return unmodifiableDelegatedMap.entrySet();
}
return delegatedMap.entrySet();
}
}

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
/**
* General purpose request parsing and encoding utility methods.
*
* @author Craig R. McClanahan
* @author Tim Tye
*/
public final class RequestUtil {
/**
* Filter the specified message string for characters that are sensitive
* in HTML. This avoids potential attacks caused by including JavaScript
* codes in the request URL that is often reported in error messages.
*
* @param message The message string to be filtered
*
* @return the filtered message
*
* @deprecated This method will be removed in Tomcat 9
*/
@Deprecated
public static String filter(String message) {
if (message == null) {
return null;
}
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("&lt;");
break;
case '>':
result.append("&gt;");
break;
case '&':
result.append("&amp;");
break;
case '"':
result.append("&quot;");
break;
default:
result.append(content[i]);
}
}
return result.toString();
}
}

View File

@@ -0,0 +1,181 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.util.Collection;
import java.util.HashSet;
import org.apache.tomcat.util.res.StringManager;
/**
* Extended implementation of <strong>HashSet</strong> that includes a
* <code>locked</code> property. This class can be used to safely expose
* resource path sets to user classes without having to clone them in order
* to avoid modifications. When first created, a <code>ResourceMap</code>
* is not locked.
*
* @param <T> The type of elements in the Set
*
* @author Craig R. McClanahan
*/
public final class ResourceSet<T> extends HashSet<T> {
private static final long serialVersionUID = 1L;
// ----------------------------------------------------------- Constructors
/**
* Construct a new, empty set with the default initial capacity and
* load factor.
*/
public ResourceSet() {
super();
}
/**
* Construct a new, empty set with the specified initial capacity and
* default load factor.
*
* @param initialCapacity The initial capacity of this set
*/
public ResourceSet(int initialCapacity) {
super(initialCapacity);
}
/**
* Construct a new, empty set with the specified initial capacity and
* load factor.
*
* @param initialCapacity The initial capacity of this set
* @param loadFactor The load factor of this set
*/
public ResourceSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
/**
* Construct a new set with the same contents as the existing collection.
*
* @param coll The collection whose contents we should copy
*/
public ResourceSet(Collection<T> coll) {
super(coll);
}
// ------------------------------------------------------------- Properties
/**
* The current lock state of this parameter map.
*/
private boolean locked = false;
/**
* @return the locked state of this parameter map.
*/
public boolean isLocked() {
return this.locked;
}
/**
* Set the locked state of this parameter map.
*
* @param locked The new locked state
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* The string manager for this package.
*/
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
// --------------------------------------------------------- Public Methods
/**
* Add the specified element to this set if it is not already present.
* Return <code>true</code> if the element was added.
*
* @param o The object to be added
*
* @exception IllegalStateException if this ResourceSet is locked
*/
@Override
public boolean add(T o) {
if (locked)
throw new IllegalStateException
(sm.getString("resourceSet.locked"));
return super.add(o);
}
/**
* Remove all of the elements from this set.
*
* @exception IllegalStateException if this ResourceSet is locked
*/
@Override
public void clear() {
if (locked)
throw new IllegalStateException
(sm.getString("resourceSet.locked"));
super.clear();
}
/**
* Remove the given element from this set if it is present.
* Return <code>true</code> if the element was removed.
*
* @param o The object to be removed
*
* @exception IllegalStateException if this ResourceSet is locked
*/
@Override
public boolean remove(Object o) {
if (locked)
throw new IllegalStateException
(sm.getString("resourceSet.locked"));
return super.remove(o);
}
}

View File

@@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.InputStream;
import java.util.Properties;
import org.apache.tomcat.util.ExceptionUtils;
/**
* Simple utility module to make it easy to plug in the server identifier
* when integrating Tomcat.
*
* @author Craig R. McClanahan
*/
public class ServerInfo {
// ------------------------------------------------------- Static Variables
/**
* The server information String with which we identify ourselves.
*/
private static final String serverInfo;
/**
* The server built String.
*/
private static final String serverBuilt;
/**
* The server's version number String.
*/
private static final String serverNumber;
static {
String info = null;
String built = null;
String number = null;
Properties props = new Properties();
try (InputStream is = ServerInfo.class.getResourceAsStream
("/org/apache/catalina/util/ServerInfo.properties")) {
props.load(is);
info = props.getProperty("server.info");
built = props.getProperty("server.built");
number = props.getProperty("server.number");
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
}
if (info == null)
info = "Apache Tomcat 8.5.x-dev";
if (built == null)
built = "unknown";
if (number == null)
number = "8.5.x";
serverInfo = info;
serverBuilt = built;
serverNumber = number;
}
// --------------------------------------------------------- Public Methods
/**
* @return the server identification for this version of Tomcat.
*/
public static String getServerInfo() {
return serverInfo;
}
/**
* @return the server built time for this version of Tomcat.
*/
public static String getServerBuilt() {
return serverBuilt;
}
/**
* @return the server's version number.
*/
public static String getServerNumber() {
return serverNumber;
}
public static void main(String args[]) {
System.out.println("Server version: " + getServerInfo());
System.out.println("Server built: " + getServerBuilt());
System.out.println("Server number: " + getServerNumber());
System.out.println("OS Name: " +
System.getProperty("os.name"));
System.out.println("OS Version: " +
System.getProperty("os.version"));
System.out.println("Architecture: " +
System.getProperty("os.arch"));
System.out.println("JVM Version: " +
System.getProperty("java.runtime.version"));
System.out.println("JVM Vendor: " +
System.getProperty("java.vm.vendor"));
}
}

View File

@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
server.info=Apache Tomcat/@VERSION@
server.number=@VERSION_NUMBER@
server.built=@VERSION_BUILT@

View File

@@ -0,0 +1,128 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import javax.servlet.SessionCookieConfig;
import org.apache.catalina.Context;
public class SessionConfig {
private static final String DEFAULT_SESSION_COOKIE_NAME = "JSESSIONID";
private static final String DEFAULT_SESSION_PARAMETER_NAME = "jsessionid";
/**
* Determine the name to use for the session cookie for the provided
* context.
* @param context The context
* @return the cookie name for the context
*/
public static String getSessionCookieName(Context context) {
String result = getConfiguredSessionCookieName(context);
if (result == null) {
result = DEFAULT_SESSION_COOKIE_NAME;
}
return result;
}
/**
* Determine the name to use for the session path parameter for the provided
* context.
* @param context The context
* @return the parameter name for the session
*/
public static String getSessionUriParamName(Context context) {
String result = getConfiguredSessionCookieName(context);
if (result == null) {
result = DEFAULT_SESSION_PARAMETER_NAME;
}
return result;
}
private static String getConfiguredSessionCookieName(Context context) {
// Priority is:
// 1. Cookie name defined in context
// 2. Cookie name configured for app
// 3. Default defined by spec
if (context != null) {
String cookieName = context.getSessionCookieName();
if (cookieName != null && cookieName.length() > 0) {
return cookieName;
}
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
cookieName = scc.getName();
if (cookieName != null && cookieName.length() > 0) {
return cookieName;
}
}
return null;
}
/**
* Determine the value to use for the session cookie path for the provided
* context.
*
* @param context The context
* @return the parameter name for the session
*/
public static String getSessionCookiePath(Context context) {
SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig();
String contextPath = context.getSessionCookiePath();
if (contextPath == null || contextPath.length() == 0) {
contextPath = scc.getPath();
}
if (contextPath == null || contextPath.length() == 0) {
contextPath = context.getEncodedPath();
}
if (context.getSessionCookiePathUsesTrailingSlash()) {
// Handle special case of ROOT context where cookies require a path of
// '/' but the servlet spec uses an empty string
// Also ensure the cookies for a context with a path of /foo don't get
// sent for requests with a path of /foobar
if (!contextPath.endsWith("/")) {
contextPath = contextPath + "/";
}
} else {
// Only handle special case of ROOT context where cookies require a
// path of '/' but the servlet spec uses an empty string
if (contextPath.length() == 0) {
contextPath = "/";
}
}
return contextPath;
}
private SessionConfig() {
// Utility class. Hide default constructor.
}
}

View File

@@ -0,0 +1,306 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.SessionIdGenerator;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;
public abstract class SessionIdGeneratorBase extends LifecycleBase
implements SessionIdGenerator {
private final Log log = LogFactory.getLog(SessionIdGeneratorBase.class); // must not be static
private static final StringManager sm =
StringManager.getManager("org.apache.catalina.util");
/**
* Queue of random number generator objects to be used when creating session
* identifiers. If the queue is empty when a random number generator is
* required, a new random number generator object is created. This is
* designed this way since random number generators use a sync to make them
* thread-safe and the sync makes using a single object slow(er).
*/
private final Queue<SecureRandom> randoms = new ConcurrentLinkedQueue<>();
private String secureRandomClass = null;
private String secureRandomAlgorithm = "SHA1PRNG";
private String secureRandomProvider = null;
/** Node identifier when in a cluster. Defaults to the empty string. */
private String jvmRoute = "";
/** Number of bytes in a session ID. Defaults to 16. */
private int sessionIdLength = 16;
/**
* Get the class name of the {@link SecureRandom} implementation used to
* generate session IDs.
*
* @return The fully qualified class name. {@code null} indicates that the
* JRE provided {@link SecureRandom} implementation will be used
*/
public String getSecureRandomClass() {
return secureRandomClass;
}
/**
* Specify a non-default {@link SecureRandom} implementation to use. The
* implementation must be self-seeding and have a zero-argument constructor.
* If not specified, an instance of {@link SecureRandom} will be generated.
*
* @param secureRandomClass The fully-qualified class name
*/
public void setSecureRandomClass(String secureRandomClass) {
this.secureRandomClass = secureRandomClass;
}
/**
* Get the name of the algorithm used to create the {@link SecureRandom}
* instances which generate new session IDs.
*
* @return The name of the algorithm. {@code null} or the empty string means
* that platform default will be used
*/
public String getSecureRandomAlgorithm() {
return secureRandomAlgorithm;
}
/**
* Specify a non-default algorithm to use to create instances of
* {@link SecureRandom} which are used to generate session IDs. If no
* algorithm is specified, SHA1PRNG is used. To use the platform default
* (which may be SHA1PRNG), specify {@code null} or the empty string. If an
* invalid algorithm and/or provider is specified the {@link SecureRandom}
* instances will be created using the defaults for this
* {@link SessionIdGenerator} implementation. If that fails, the
* {@link SecureRandom} instances will be created using platform defaults.
*
* @param secureRandomAlgorithm The name of the algorithm
*/
public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
this.secureRandomAlgorithm = secureRandomAlgorithm;
}
/**
* Get the name of the provider used to create the {@link SecureRandom}
* instances which generate new session IDs.
*
* @return The name of the provider. {@code null} or the empty string means
* that platform default will be used
*/
public String getSecureRandomProvider() {
return secureRandomProvider;
}
/**
* Specify a non-default provider to use to create instances of
* {@link SecureRandom} which are used to generate session IDs. If no
* provider is specified, the platform default is used. To use the platform
* default specify {@code null} or the empty string. If an invalid algorithm
* and/or provider is specified the {@link SecureRandom} instances will be
* created using the defaults for this {@link SessionIdGenerator}
* implementation. If that fails, the {@link SecureRandom} instances will be
* created using platform defaults.
*
* @param secureRandomProvider The name of the provider
*/
public void setSecureRandomProvider(String secureRandomProvider) {
this.secureRandomProvider = secureRandomProvider;
}
/**
* Return the node identifier associated with this node which will be
* included in the generated session ID.
*/
@Override
public String getJvmRoute() {
return jvmRoute;
}
/**
* Specify the node identifier associated with this node which will be
* included in the generated session ID.
*
* @param jvmRoute The node identifier
*/
@Override
public void setJvmRoute(String jvmRoute) {
this.jvmRoute = jvmRoute;
}
/**
* Return the number of bytes for a session ID
*/
@Override
public int getSessionIdLength() {
return sessionIdLength;
}
/**
* Specify the number of bytes for a session ID
*
* @param sessionIdLength Number of bytes
*/
@Override
public void setSessionIdLength(int sessionIdLength) {
this.sessionIdLength = sessionIdLength;
}
/**
* Generate and return a new session identifier.
*/
@Override
public String generateSessionId() {
return generateSessionId(jvmRoute);
}
protected void getRandomBytes(byte bytes[]) {
SecureRandom random = randoms.poll();
if (random == null) {
random = createSecureRandom();
}
random.nextBytes(bytes);
randoms.add(random);
}
/**
* Create a new random number generator instance we should use for
* generating session identifiers.
*/
private SecureRandom createSecureRandom() {
SecureRandom result = null;
long t1 = System.currentTimeMillis();
if (secureRandomClass != null) {
try {
// Construct and seed a new random number generator
Class<?> clazz = Class.forName(secureRandomClass);
result = (SecureRandom) clazz.getConstructor().newInstance();
} catch (Exception e) {
log.error(sm.getString("sessionIdGeneratorBase.random",
secureRandomClass), e);
}
}
boolean error = false;
if (result == null) {
// No secureRandomClass or creation failed. Use SecureRandom.
try {
if (secureRandomProvider != null &&
secureRandomProvider.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm,
secureRandomProvider);
} else if (secureRandomAlgorithm != null &&
secureRandomAlgorithm.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm);
}
} catch (NoSuchAlgorithmException e) {
error = true;
log.error(sm.getString("sessionIdGeneratorBase.randomAlgorithm",
secureRandomAlgorithm), e);
} catch (NoSuchProviderException e) {
error = true;
log.error(sm.getString("sessionIdGeneratorBase.randomProvider",
secureRandomProvider), e);
}
}
if (result == null && error) {
// Invalid provider / algorithm
try {
result = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(sm.getString("sessionIdGeneratorBase.randomAlgorithm",
secureRandomAlgorithm), e);
}
}
if (result == null) {
// Nothing works - use platform default
result = new SecureRandom();
}
// Force seeding to take place
result.nextInt();
long t2 = System.currentTimeMillis();
if ((t2 - t1) > 100) {
log.warn(sm.getString("sessionIdGeneratorBase.createRandom",
result.getAlgorithm(), Long.valueOf(t2 - t1)));
}
return result;
}
@Override
protected void initInternal() throws LifecycleException {
// NO-OP
}
@Override
protected void startInternal() throws LifecycleException {
// Ensure SecureRandom has been initialised
generateSessionId();
setState(LifecycleState.STARTING);
}
@Override
protected void stopInternal() throws LifecycleException {
setState(LifecycleState.STOPPING);
randoms.clear();
}
@Override
protected void destroyInternal() throws LifecycleException {
// NO-OP
}
}

View File

@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
public class StandardSessionIdGenerator extends SessionIdGeneratorBase {
@Override
public String generateSessionId(String route) {
byte random[] = new byte[16];
int sessionIdLength = getSessionIdLength();
// Render the result as a String of hexadecimal digits
// Start with enough space for sessionIdLength and medium route size
StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);
int resultLenBytes = 0;
while (resultLenBytes < sessionIdLength) {
getRandomBytes(random);
for (int j = 0;
j < random.length && resultLenBytes < sessionIdLength;
j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
if (route != null && route.length() > 0) {
buffer.append('.').append(route);
} else {
String jvmRoute = getJvmRoute();
if (jvmRoute != null && jvmRoute.length() > 0) {
buffer.append('.').append(jvmRoute);
}
}
return buffer.toString();
}
}

View File

@@ -0,0 +1,253 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
/**
* Converts dates to strings using the same format specifiers as strftime
*
* Note: This does not mimic strftime perfectly. Certain strftime commands,
* are not supported, and will convert as if they were literals.
*
* Certain complicated commands, like those dealing with the week of the year
* probably don't have exactly the same behavior as strftime.
*
* These limitations are due to use SimpleDateTime. If the conversion was done
* manually, all these limitations could be eliminated.
*
* The interface looks like a subset of DateFormat. Maybe someday someone will make this class
* extend DateFormat.
*
* @author Bip Thelin
* @author Dan Sandberg
*/
public class Strftime {
protected static final Properties translate;
protected final SimpleDateFormat simpleDateFormat;
/**
* Initialize our pattern translation
*/
static {
translate = new Properties();
translate.put("a","EEE");
translate.put("A","EEEE");
translate.put("b","MMM");
translate.put("B","MMMM");
translate.put("c","EEE MMM d HH:mm:ss yyyy");
//There's no way to specify the century in SimpleDateFormat. We don't want to hard-code
//20 since this could be wrong for the pre-2000 files.
//translate.put("C", "20");
translate.put("d","dd");
translate.put("D","MM/dd/yy");
translate.put("e","dd"); //will show as '03' instead of ' 3'
translate.put("F","yyyy-MM-dd");
translate.put("g","yy");
translate.put("G","yyyy");
translate.put("H","HH");
translate.put("h","MMM");
translate.put("I","hh");
translate.put("j","DDD");
translate.put("k","HH"); //will show as '07' instead of ' 7'
translate.put("l","hh"); //will show as '07' instead of ' 7'
translate.put("m","MM");
translate.put("M","mm");
translate.put("n","\n");
translate.put("p","a");
translate.put("P","a"); //will show as pm instead of PM
translate.put("r","hh:mm:ss a");
translate.put("R","HH:mm");
//There's no way to specify this with SimpleDateFormat
//translate.put("s","seconds since epoch");
translate.put("S","ss");
translate.put("t","\t");
translate.put("T","HH:mm:ss");
//There's no way to specify this with SimpleDateFormat
//translate.put("u","day of week ( 1-7 )");
//There's no way to specify this with SimpleDateFormat
//translate.put("U","week in year with first Sunday as first day...");
translate.put("V","ww"); //I'm not sure this is always exactly the same
//There's no way to specify this with SimpleDateFormat
//translate.put("W","week in year with first Monday as first day...");
//There's no way to specify this with SimpleDateFormat
//translate.put("w","E");
translate.put("X","HH:mm:ss");
translate.put("x","MM/dd/yy");
translate.put("y","yy");
translate.put("Y","yyyy");
translate.put("Z","z");
translate.put("z","Z");
translate.put("%","%");
}
/**
* Create an instance of this date formatting class
*
* @param origFormat the strftime-style formatting string
* @param locale the locale to use for locale-specific conversions
*/
public Strftime( String origFormat, Locale locale ) {
String convertedFormat = convertDateFormat( origFormat );
simpleDateFormat = new SimpleDateFormat( convertedFormat, locale );
}
/**
* Format the date according to the strftime-style string given in the constructor.
*
* @param date the date to format
* @return the formatted date
*/
public String format( Date date ) {
return simpleDateFormat.format( date );
}
/**
* Get the timezone used for formatting conversions
*
* @return the timezone
*/
public TimeZone getTimeZone() {
return simpleDateFormat.getTimeZone();
}
/**
* Change the timezone used to format dates
*
* @param timeZone The new time zone
* @see SimpleDateFormat#setTimeZone
*/
public void setTimeZone( TimeZone timeZone ) {
simpleDateFormat.setTimeZone( timeZone );
}
/**
* Search the provided pattern and get the C standard
* Date/Time formatting rules and convert them to the
* Java equivalent.
*
* @param pattern The pattern to search
* @return The modified pattern
*/
protected String convertDateFormat( String pattern ) {
boolean inside = false;
boolean mark = false;
boolean modifiedCommand = false;
StringBuilder buf = new StringBuilder();
for(int i = 0; i < pattern.length(); i++) {
char c = pattern.charAt(i);
if ( c=='%' && !mark ) {
mark=true;
} else {
if ( mark ) {
if ( modifiedCommand ) {
//don't do anything--we just wanted to skip a char
modifiedCommand = false;
mark = false;
} else {
inside = translateCommand( buf, pattern, i, inside );
//It's a modifier code
if ( c=='O' || c=='E' ) {
modifiedCommand = true;
} else {
mark=false;
}
}
} else {
if ( !inside && c != ' ' ) {
//We start a literal, which we need to quote
buf.append("'");
inside = true;
}
buf.append(c);
}
}
}
if ( buf.length() > 0 ) {
char lastChar = buf.charAt( buf.length() - 1 );
if( lastChar!='\'' && inside ) {
buf.append('\'');
}
}
return buf.toString();
}
protected String quote( String str, boolean insideQuotes ) {
String retVal = str;
if ( !insideQuotes ) {
retVal = '\'' + retVal + '\'';
}
return retVal;
}
/**
* Try to get the Java Date/Time formatting associated with
* the C standard provided.
*
* @param buf The buffer
* @param pattern The date/time pattern
* @param index The char index
* @param oldInside Flag value
* @return True if new is inside buffer
*/
protected boolean translateCommand( StringBuilder buf, String pattern, int index, boolean oldInside ) {
char firstChar = pattern.charAt( index );
boolean newInside = oldInside;
//O and E are modifiers, they mean to present an alternative representation of the next char
//we just handle the next char as if the O or E wasn't there
if ( firstChar == 'O' || firstChar == 'E' ) {
if ( index + 1 < pattern.length() ) {
newInside = translateCommand( buf, pattern, index + 1, oldInside );
} else {
buf.append( quote("%" + firstChar, oldInside ) );
}
} else {
String command = translate.getProperty( String.valueOf( firstChar ) );
//If we don't find a format, treat it as a literal--That's what apache does
if ( command == null ) {
buf.append( quote( "%" + firstChar, oldInside ) );
} else {
//If we were inside quotes, close the quotes
if ( oldInside ) {
buf.append( '\'' );
}
buf.append( command );
newInside = false;
}
}
return newInside;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.tomcat.util.digester.Digester;
/**
* Helper class used to do property replacement on system properties.
* @deprecated No longer used. Will be removed in Tomcat 9.
*/
@Deprecated
public class SystemPropertyReplacerListener
implements LifecycleListener {
// ---------------------------------------------- LifecycleListener Methods
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
Digester.replaceSystemProperties();
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import org.apache.catalina.Globals;
import org.apache.tomcat.util.net.SSLSupport;
public class TLSUtil {
/**
* Determines if the named request attribute is used to pass information
* about the TLS configuration of the connection to the application. Both
* the standard request attributes defined by the Servlet specification and
* Tomcat specific attributes are supported.
*
* @param name The attribute name to test
*
* @return {@code true} if the attribute is used to pass TLS configuration
* information, otherwise {@code false}
*/
public static boolean isTLSRequestAttribute(String name) {
return Globals.CERTIFICATES_ATTR.equals(name) ||
Globals.CIPHER_SUITE_ATTR.equals(name) ||
Globals.KEY_SIZE_ATTR.equals(name) ||
Globals.SSL_SESSION_ID_ATTR.equals(name) ||
Globals.SSL_SESSION_MGR_ATTR.equals(name) ||
SSLSupport.PROTOCOL_VERSION_KEY.equals(name);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
public class TomcatCSS {
public static final String TOMCAT_CSS =
"body {font-family:Tahoma,Arial,sans-serif;} " +
"h1, h2, h3, b {color:white;background-color:#525D76;} " +
"h1 {font-size:22px;} " +
"h2 {font-size:16px;} " +
"h3 {font-size:14px;} " +
"p {font-size:12px;} " +
"a {color:black;} " +
".line {height:1px;background-color:#525D76;border:none;}";
}

View File

@@ -0,0 +1,235 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.BitSet;
import org.apache.tomcat.util.buf.B2CConverter;
/**
*
* This class is very similar to the java.net.URLEncoder class.
*
* Unfortunately, with java.net.URLEncoder there is no way to specify to the
* java.net.URLEncoder which characters should NOT be encoded.
*
* This code was moved from DefaultServlet.java
*
* @author Craig R. McClanahan
* @author Remy Maucherat
*/
public final class URLEncoder implements Cloneable {
private static final char[] hexadecimal =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static final URLEncoder DEFAULT = new URLEncoder();
public static final URLEncoder QUERY = new URLEncoder();
static {
/*
* Encoder for URI paths, so from the spec:
*
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
*
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*/
// ALPHA and DIGIT are always treated as safe characters
// Add the remaining unreserved characters
DEFAULT.addSafeCharacter('-');
DEFAULT.addSafeCharacter('.');
DEFAULT.addSafeCharacter('_');
DEFAULT.addSafeCharacter('~');
// Add the sub-delims
DEFAULT.addSafeCharacter('!');
DEFAULT.addSafeCharacter('$');
DEFAULT.addSafeCharacter('&');
DEFAULT.addSafeCharacter('\'');
DEFAULT.addSafeCharacter('(');
DEFAULT.addSafeCharacter(')');
DEFAULT.addSafeCharacter('*');
DEFAULT.addSafeCharacter('+');
DEFAULT.addSafeCharacter(',');
DEFAULT.addSafeCharacter(';');
DEFAULT.addSafeCharacter('=');
// Add the remaining literals
DEFAULT.addSafeCharacter(':');
DEFAULT.addSafeCharacter('@');
// Add '/' so it isn't encoded when we encode a path
DEFAULT.addSafeCharacter('/');
/*
* Encoder for query strings
* https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
* 0x20 ' ' -> '+'
* 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
* '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z'
* Also '=' and '&' are not encoded
* Everything else %nn encoded
*/
// Special encoding for space
QUERY.setEncodeSpaceAsPlus(true);
// Alpha and digit are safe by default
// Add the other permitted characters
QUERY.addSafeCharacter('*');
QUERY.addSafeCharacter('-');
QUERY.addSafeCharacter('.');
QUERY.addSafeCharacter('_');
QUERY.addSafeCharacter('=');
QUERY.addSafeCharacter('&');
}
//Array containing the safe characters set.
private final BitSet safeCharacters;
private boolean encodeSpaceAsPlus = false;
public URLEncoder() {
this(new BitSet(256));
for (char i = 'a'; i <= 'z'; i++) {
addSafeCharacter(i);
}
for (char i = 'A'; i <= 'Z'; i++) {
addSafeCharacter(i);
}
for (char i = '0'; i <= '9'; i++) {
addSafeCharacter(i);
}
}
private URLEncoder(BitSet safeCharacters) {
this.safeCharacters = safeCharacters;
}
public void addSafeCharacter(char c) {
safeCharacters.set(c);
}
public void removeSafeCharacter(char c) {
safeCharacters.clear(c);
}
public void setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) {
this.encodeSpaceAsPlus = encodeSpaceAsPlus;
}
/**
* URL encodes the provided path using UTF-8.
*
* @param path The path to encode
*
* @return The encoded path
*
* @deprecated Use {@link #encode(String, String)}
*/
@Deprecated
public String encode(String path) {
return encode(path, "UTF-8");
}
/**
* URL encodes the provided path using the given encoding.
*
* @param path The path to encode
* @param encoding The encoding to use to convert the path to bytes
*
* @return The encoded path
*
* @deprecated This will be removed in Tomcat 9.0.x
*/
@Deprecated
public String encode(String path, String encoding) {
Charset charset;
try {
charset = B2CConverter.getCharset(encoding);
} catch (UnsupportedEncodingException e) {
charset = Charset.defaultCharset();
}
return encode(path, charset);
}
/**
* URL encodes the provided path using the given character set.
*
* @param path The path to encode
* @param charset The character set to use to convert the path to bytes
*
* @return The encoded path
*/
public String encode(String path, Charset charset) {
int maxBytesPerChar = 10;
StringBuilder rewrittenPath = new StringBuilder(path.length());
ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
OutputStreamWriter writer = new OutputStreamWriter(buf, charset);
for (int i = 0; i < path.length(); i++) {
int c = path.charAt(i);
if (safeCharacters.get(c)) {
rewrittenPath.append((char)c);
} else if (encodeSpaceAsPlus && c == ' ') {
rewrittenPath.append('+');
} else {
// convert to external encoding before hex conversion
try {
writer.write((char)c);
writer.flush();
} catch(IOException e) {
buf.reset();
continue;
}
byte[] ba = buf.toByteArray();
for (int j = 0; j < ba.length; j++) {
// Converting each byte in the buffer
byte toEncode = ba[j];
rewrittenPath.append('%');
int low = toEncode & 0x0f;
int high = (toEncode & 0xf0) >> 4;
rewrittenPath.append(hexadecimal[high]);
rewrittenPath.append(hexadecimal[low]);
}
buf.reset();
}
}
return rewrittenPath.toString();
}
@Override
public Object clone() {
URLEncoder result = new URLEncoder((BitSet) safeCharacters.clone());
result.setEncodeSpaceAsPlus(encodeSpaceAsPlus);
return result;
}
}

View File

@@ -0,0 +1,222 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.catalina.util;
import java.io.IOException;
import java.io.Writer;
/**
* XMLWriter helper class.
*/
public class XMLWriter {
// -------------------------------------------------------------- Constants
/**
* Opening tag.
*/
public static final int OPENING = 0;
/**
* Closing tag.
*/
public static final int CLOSING = 1;
/**
* Element with no content.
*/
public static final int NO_CONTENT = 2;
// ----------------------------------------------------- Instance Variables
/**
* Buffer.
*/
protected StringBuilder buffer = new StringBuilder();
/**
* Writer.
*/
protected final Writer writer;
// ----------------------------------------------------------- Constructors
/**
* New XML writer utility that will store its data in an internal buffer.
*/
public XMLWriter() {
this(null);
}
/**
* New XML writer utility that will store its data in an internal buffer
* and can write it to the specified writer.
* <p>
* See {@link #sendData()}
*
* @param writer The writer to use
*/
public XMLWriter(Writer writer) {
this.writer = writer;
}
// --------------------------------------------------------- Public Methods
/**
* Retrieve generated XML.
*
* @return String containing the generated XML
*/
@Override
public String toString() {
return buffer.toString();
}
/**
* Write property to the XML.
*
* @param namespace Namespace
* @param name Property name
* @param value Property value
*/
public void writeProperty(String namespace, String name, String value) {
writeElement(namespace, name, OPENING);
buffer.append(value);
writeElement(namespace, name, CLOSING);
}
/**
* Write an element.
*
* @param name Element name
* @param namespace Namespace abbreviation
* @param type Element type
*/
public void writeElement(String namespace, String name, int type) {
writeElement(namespace, null, name, type);
}
/**
* Write an element.
*
* @param namespace Namespace abbreviation
* @param namespaceInfo Namespace info
* @param name Element name
* @param type Element type
*/
public void writeElement(String namespace, String namespaceInfo,
String name, int type) {
if ((namespace != null) && (namespace.length() > 0)) {
switch (type) {
case OPENING:
if (namespaceInfo != null) {
buffer.append("<" + namespace + ":" + name + " xmlns:"
+ namespace + "=\""
+ namespaceInfo + "\">");
} else {
buffer.append("<" + namespace + ":" + name + ">");
}
break;
case CLOSING:
buffer.append("</" + namespace + ":" + name + ">\n");
break;
case NO_CONTENT:
default:
if (namespaceInfo != null) {
buffer.append("<" + namespace + ":" + name + " xmlns:"
+ namespace + "=\""
+ namespaceInfo + "\"/>");
} else {
buffer.append("<" + namespace + ":" + name + "/>");
}
break;
}
} else {
switch (type) {
case OPENING:
buffer.append("<" + name + ">");
break;
case CLOSING:
buffer.append("</" + name + ">\n");
break;
case NO_CONTENT:
default:
buffer.append("<" + name + "/>");
break;
}
}
}
/**
* Write text.
*
* @param text Text to append
*/
public void writeText(String text) {
buffer.append(text);
}
/**
* Write data.
*
* @param data Data to append
*/
public void writeData(String data) {
buffer.append("<![CDATA[" + data + "]]>");
}
/**
* Write XML Header.
*/
public void writeXMLHeader() {
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
}
/**
* Send data and reinitializes buffer, if a writer has been specified.
* @throws IOException Error writing XML data
*/
public void sendData()
throws IOException {
if (writer != null) {
writer.write(buffer.toString());
buffer = new StringBuilder();
}
}
}