if (usingInputStream) { thrownew IllegalStateException(sm.getString("coyoteRequest.getReader.ise"));
}
// InputBuffer has no easily accessible reference chain to the Context // to check for a default request character encoding at the Context. // Therefore, if a Context default should be used, it is set explicitly // here. Need to do this before setting usingReader. if (coyoteRequest.getCharacterEncoding() == null) { // Nothing currently set explicitly. // Check the context
Context context = getContext(); if (context != null) {
String enc = context.getRequestCharacterEncoding(); if (enc != null) { // Explicitly set the context default so it is visible to // InputBuffer when creating the Reader.
setCharacterEncoding(enc);
}
}
}
usingReader = true;
inputBuffer.checkConverter(); if (reader == null) {
reader = new CoyoteReader(inputBuffer);
} return reader;
}
int fragmentPos = path.indexOf('#'); if (fragmentPos > -1) {
log.warn(sm.getString("request.fragmentInDispatchPath", path));
path = path.substring(0, fragmentPos);
}
// If the path is already context-relative, just pass it through if (path.startsWith("/")) { return context.getServletContext().getRequestDispatcher(path);
}
// Convert a request-relative path to a context-relative one
String servletPath = (String) getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); if (servletPath == null) {
servletPath = getServletPath();
}
// Add the path info, if there is any
String pathInfo = getPathInfo();
String requestPath = null;
// Name cannot be null if (name == null) { thrownew IllegalArgumentException(sm.getString("coyoteRequest.setAttribute.namenull"));
}
// Null value is the same as removeAttribute() if (value == null) {
removeAttribute(name); return;
}
// Special attributes
SpecialAttributeAdapter adapter = specialAttributes.get(name); if (adapter != null) {
adapter.set(this, name, value); return;
}
// Add or replace the specified attribute // Do the security check before any updates are made if (Globals.IS_SECURITY_ENABLED && name.equals(Globals.SENDFILE_FILENAME_ATTR)) { // Use the canonical file name to avoid any possible symlink and // relative path issues
String canonicalPath; try {
canonicalPath = new File(value.toString()).getCanonicalPath();
} catch (IOException e) { thrownew SecurityException(sm.getString("coyoteRequest.sendfileNotCanonical", value), e);
} // Sendfile is performed in Tomcat's security context so need to // check if the web app is permitted to access the file while still // in the web app's security context
System.getSecurityManager().checkRead(canonicalPath); // Update the value so the canonical path is used
value = canonicalPath;
}
Object oldValue = attributes.put(name, value);
// Pass special attributes to the native layer if (name.startsWith("org.apache.tomcat.")) {
coyoteRequest.setAttribute(name, value);
}
for (Object o : listeners) { if (!(o instanceof ServletRequestAttributeListener)) { continue;
}
ServletRequestAttributeListener listener = (ServletRequestAttributeListener) o; try { if (replaced) {
listener.attributeReplaced(event);
} else {
listener.attributeAdded(event);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t); // Error valve will pick this exception up and display it to user
attributes.put(RequestDispatcher.ERROR_EXCEPTION, t);
context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
}
}
}
/** *Notifyinterestedlistenersthatattributehasbeenremoved. * *@paramnameAttributename *@paramvalueAttributevalue
*/ privatevoid notifyAttributeRemoved(String name, Object value) {
Context context = getContext();
Object listeners[] = context.getApplicationEventListeners(); if (listeners == null || listeners.length == 0) { return;
}
ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(context.getServletContext(), getRequest(), name, value); for (Object o : listeners) { if (!(o instanceof ServletRequestAttributeListener)) { continue;
}
ServletRequestAttributeListener listener = (ServletRequestAttributeListener) o; try {
listener.attributeRemoved(event);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t); // Error valve will pick this exception up and display it to user
attributes.put(RequestDispatcher.ERROR_EXCEPTION, t);
context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
}
}
}
@Override public Map<String,String> getTrailerFields() { if (!isTrailerFieldsReady()) { thrownew IllegalStateException(sm.getString("coyoteRequest.trailersNotReady"));
}
Map<String,String> result = new HashMap<>(coyoteRequest.getTrailerFields()); return result;
}
@Override public PushBuilder newPushBuilder() { return newPushBuilder(this);
}
public PushBuilder newPushBuilder(HttpServletRequest request) {
AtomicBoolean result = new AtomicBoolean();
coyoteRequest.action(ActionCode.IS_PUSH_SUPPORTED, result); if (result.get()) { returnnew ApplicationPushBuilder(this, request);
} else { returnnull;
}
}
@SuppressWarnings("unchecked")
@Override public <T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass) throws IOException, ServletException {
T handler;
InstanceManager instanceManager = null; try { // Do not go through the instance manager for internal Tomcat classes since they don't // need injection if (InternalHttpUpgradeHandler.class.isAssignableFrom(httpUpgradeHandlerClass)) {
handler = httpUpgradeHandlerClass.getConstructor().newInstance();
} else {
instanceManager = getContext().getInstanceManager();
handler = (T) instanceManager.newInstance(httpUpgradeHandlerClass);
}
} catch (ReflectiveOperationException | NamingException | IllegalArgumentException | SecurityException e) { thrownew ServletException(e);
}
UpgradeToken upgradeToken = new UpgradeToken(handler, getContext(), instanceManager,
getUpgradeProtocolName(httpUpgradeHandlerClass));
// Output required by RFC2616. Protocol specific headers should have // already been set.
response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
return handler;
}
private String getUpgradeProtocolName(Class<? extends HttpUpgradeHandler> httpUpgradeHandlerClass) { // Ideal - the caller has already explicitly set the selected protocol // on the response
String result = response.getHeader(HTTP_UPGRADE_HEADER_NAME);
if (result == null) { // If the request's upgrade header contains a single protocol that // is the protocol that must have been selected
List<Upgrade> upgradeProtocols = Upgrade.parse(getHeaders(HTTP_UPGRADE_HEADER_NAME)); if (upgradeProtocols != null && upgradeProtocols.size() == 1) {
result = upgradeProtocols.get(0).toString();
}
}
if (result == null) { // Ugly but use the class name - it is better than nothing
result = httpUpgradeHandlerClass.getName();
} return result;
}
/** *ReturntheportionoftherequestURIusedtoselecttheContextoftheRequest.Thevaluereturnedisnot *decodedwhichalsoimpliesitisnotnormalised.
*/
@Override public String getContextPath() { int lastSlash = mappingData.contextSlashCount; // Special case handling for the root context if (lastSlash == 0) { return"";
}
String uri = getRequestURI(); int pos = 0; if (!getContext().getAllowMultipleLeadingForwardSlashInPath()) { // Ensure that the returned value only starts with a single '/'. // This prevents the value being misinterpreted as a protocol- // relative URI if used with sendRedirect(). do {
pos++;
} while (pos < uri.length() && uri.charAt(pos) == '/');
pos--;
uri = uri.substring(pos);
}
char[] uriChars = uri.toCharArray(); // Need at least the number of slashes in the context path while (lastSlash > 0) {
pos = nextSlash(uriChars, pos + 1); if (pos == -1) { break;
}
lastSlash--;
} // Now allow for path parameters, normalization and/or encoding. // Essentially, keep extending the candidate path up to the next slash // until the decoded and normalized candidate path (with the path // parameters removed) is the same as the canonical path.
String candidate; if (pos == -1) {
candidate = uri;
} else {
candidate = uri.substring(0, pos);
}
candidate = removePathParameters(candidate);
candidate = UDecoder.URLDecode(candidate, connector.getURICharset());
candidate = org.apache.tomcat.util.http.RequestUtil.normalize(candidate); boolean match = canonicalContextPath.equals(candidate); while (!match && pos != -1) {
pos = nextSlash(uriChars, pos + 1); if (pos == -1) {
candidate = uri;
} else {
candidate = uri.substring(0, pos);
}
candidate = removePathParameters(candidate);
candidate = UDecoder.URLDecode(candidate, connector.getURICharset());
candidate = org.apache.tomcat.util.http.RequestUtil.normalize(candidate);
match = canonicalContextPath.equals(candidate);
} if (match) { if (pos == -1) { return uri;
} else { return uri.substring(0, pos);
}
} else { // Should never happen thrownew IllegalStateException(
sm.getString("coyoteRequest.getContextPath.ise", canonicalContextPath, uri));
}
}
private String removePathParameters(String input) { int nextSemiColon = input.indexOf(';'); // Shortcut if (nextSemiColon == -1) { return input;
}
StringBuilder result = new StringBuilder(input.length());
result.append(input.substring(0, nextSemiColon)); while (true) { int nextSlash = input.indexOf('/', nextSemiColon); if (nextSlash == -1) { break;
}
nextSemiColon = input.indexOf(';', nextSlash); if (nextSemiColon == -1) {
result.append(input.substring(nextSlash)); break;
} else {
result.append(input.substring(nextSlash, nextSemiColon));
}
}
return result.toString();
}
privateint nextSlash(char[] uri, int startPos) { int len = uri.length; int pos = startPos; while (pos < len) { if (uri[pos] == '/') { return pos;
} elseif (connector.getEncodedSolidusHandlingInternal() == EncodedSolidusHandling.DECODE &&
uri[pos] == '%' && pos + 2 < len && uri[pos + 1] == '2' &&
(uri[pos + 2] == 'f' || uri[pos + 2] == 'F')) { return pos;
}
pos++;
} return -1;
}
/** *ReturnthesetofCookiesreceivedwiththisRequest.TriggersparsingoftheCookieHTTPheadersfollowedby *conversiontoCookieobjectsifthishasnotalreadybeenperformed. * *@returnthearrayofcookies
*/
@Override public Cookie[] getCookies() { if (!cookiesConverted) {
convertCookies();
} return cookies;
}
String value = getHeader(name); if (value == null) { return -1L;
}
// Attempt to convert the date header in a variety of formats long result = FastHttpDateFormat.parseDate(value); if (result != (-1L)) { return result;
} thrownew IllegalArgumentException(value);
// Have we got an authenticated principal at all? if (userPrincipal == null) { returnfalse;
}
// Identify the Realm we will use for checking role assignments
Context context = getContext(); if (context == null) { returnfalse;
}
// If the role is "*" then the return value must be false // Servlet 31, section 13.3 if ("*".equals(role)) { returnfalse;
}
// If the role is "**" then, unless the application defines a role with // that name, only check if the user is authenticated if ("**".equals(role) && !context.findSecurityRole("**")) { return userPrincipal != null;
}
// Check for a role defined directly as a <security-role> return realm.hasRole(getWrapper(), userPrincipal, role);
}
/** *@returntheprincipalthathasbeenauthenticatedforthisRequest.
*/ public Principal getPrincipal() { return userPrincipal;
}
/** *@returntheprincipalthathasbeenauthenticatedforthisRequest.
*/
@Override public Principal getUserPrincipal() { if (userPrincipal instanceof TomcatPrincipal) {
GSSCredential gssCredential = ((TomcatPrincipal) userPrincipal).getGssCredential(); if (gssCredential != null) { int left = -1; try { // Concurrent calls to this method from an expired session // can trigger an ISE. If one thread calls logout() below // before another thread calls getRemainingLifetime() then // then since logout() eventually calls // GSSCredential.dispose(), the subsequent call to // GSSCredential.getRemainingLifetime() will throw an ISE. // Avoiding the ISE would require locking in this method to // protect against concurrent access to the GSSCredential. // That would have a small performance impact. The ISE is // rare so it is caught and handled rather than avoided.
left = gssCredential.getRemainingLifetime();
} catch (GSSException | IllegalStateException e) {
log.warn(sm.getString("coyoteRequest.gssLifetimeFail", userPrincipal.getName()), e);
} // zero is expired. Exception above will mean left == -1 // Treat both as expired. if (left <= 0) { // GSS credential has expired. Need to re-authenticate. try {
logout();
} catch (ServletException e) { // Should never happen (no code called by logout() // throws a ServletException
} returnnull;
}
} return ((TomcatPrincipal) userPrincipal).getUserPrincipal();
}
return userPrincipal;
}
/** *@returnthesessionassociatedwiththisRequest,creatingoneifnecessary.
*/ public Session getSessionInternal() { return doGetSession(true);
}
/** *ChangetheIDofthesessionthatthisrequestisassociatedwith.Thereareseveralthingsthatmaytriggeran *IDchange.Theseincludemovingbetweennodesinaclusterandsessionfixationpreventionduringthe *authenticationprocess. * *@paramnewSessionIdThesessiontochangethesessionIDfor
*/ publicvoid changeSessionId(String newSessionId) { // This should only ever be called if there was an old session ID but // double check to be sure if (requestedSessionId != null && requestedSessionId.length() > 0) {
requestedSessionId = newSessionId;
}
if (mce == null) { if (context.getAllowCasualMultipartParsing()) {
mce = new MultipartConfigElement(null, connector.getMaxPostSize(), connector.getMaxPostSize(),
connector.getMaxPostSize());
} else { if (explicit) {
partsParseException = new IllegalStateException(sm.getString("coyoteRequest.noMultipartConfig")); return;
} else {
parts = Collections.emptyList(); return;
}
}
}
int maxParameterCount = getConnector().getMaxParameterCount();
Parameters parameters = coyoteRequest.getParameters();
parameters.setLimit(maxParameterCount);
boolean success = false; try {
File location;
String locationStr = mce.getLocation(); if (locationStr == null || locationStr.length() == 0) {
location = ((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR));
} else { // If relative, it is relative to TEMPDIR
location = new File(locationStr); if (!location.isAbsolute()) {
location = new File((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR),
locationStr).getAbsoluteFile();
}
}
if (!location.exists() && context.getCreateUploadTargets()) {
log.warn(sm.getString("coyoteRequest.uploadCreate", location.getAbsolutePath(),
getMappingData().wrapper.getName())); if (!location.mkdirs()) {
log.warn(sm.getString("coyoteRequest.uploadCreateFail", location.getAbsolutePath()));
}
}
if (!location.isDirectory()) {
parameters.setParseFailedReason(FailReason.MULTIPART_CONFIG_INVALID);
partsParseException = new IOException(sm.getString("coyoteRequest.uploadLocationInvalid", location)); return;
}
// Create a new file upload handler
DiskFileItemFactory factory = new DiskFileItemFactory(); try {
factory.setRepository(location.getCanonicalFile());
} catch (IOException ioe) {
parameters.setParseFailedReason(FailReason.IO_ERROR);
partsParseException = ioe; return;
}
factory.setSizeThreshold(mce.getFileSizeThreshold());
FileUpload upload = new FileUpload();
upload.setFileItemFactory(factory);
upload.setFileSizeMax(mce.getMaxFileSize());
upload.setSizeMax(mce.getMaxRequestSize()); if (maxParameterCount > -1) { // There is a limit. The limit for parts needs to be reduced by // the number of parameters we have already parsed. // Must be under the limit else parsing parameters would have // triggered an exception.
upload.setFileCountMax(maxParameterCount - parameters.size());
}
parts = new ArrayList<>(); try {
List<FileItem> items = upload.parseRequest(new ServletRequestContext(this)); int maxPostSize = getConnector().getMaxPostSize(); int postSize = 0;
Charset charset = getCharset(); for (FileItem item : items) {
ApplicationPart part = new ApplicationPart(item, location);
parts.add(part); if (part.getSubmittedFileName() == null) {
String name = part.getName(); if (maxPostSize >= 0) { // Have to calculate equivalent size. Not completely // accurate but close enough.
postSize += name.getBytes(charset).length; // Equals sign
postSize++; // Value length
postSize += part.getSize(); // Value separator
postSize++; if (postSize > maxPostSize) {
parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); thrownew IllegalStateException(sm.getString("coyoteRequest.maxPostSizeExceeded"));
}
}
String value = null; try {
value = part.getString(charset.name());
} catch (UnsupportedEncodingException uee) { // Not possible
}
parameters.addParameter(name, value);
}
}
success = true;
} catch (InvalidContentTypeException e) {
parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE);
partsParseException = new ServletException(e);
} catch (SizeException e) {
parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
checkSwallowInput();
partsParseException = new IllegalStateException(e);
} catch (IOException e) {
parameters.setParseFailedReason(FailReason.IO_ERROR);
partsParseException = e;
} catch (IllegalStateException e) { // addParameters() will set parseFailedReason
checkSwallowInput();
partsParseException = e;
}
} finally { // This might look odd but is correct. setParseFailedReason() only // sets the failure reason if none is currently set. This code could // be more efficient but it is written this way to be robust with // respect to changes in the remainder of the method. if (partsParseException != null || !success) {
parameters.setParseFailedReason(FailReason.UNKNOWN);
}
}
}
@Override public Part getPart(String name) throws IOException, IllegalStateException, ServletException { for (Part part : getParts()) { if (name.equals(part.getName())) { return part;
}
} returnnull;
}
// There cannot be a session if no context has been assigned yet
Context context = getContext(); if (context == null) { returnnull;
}
// Return the current session if it exists and is valid if ((session != null) && !session.isValid()) {
session = null;
} if (session != null) { return session;
}
// Return the requested session if it exists and is valid
Manager manager = context.getManager(); if (manager == null) { returnnull; // Sessions are not supported
} if (requestedSessionId != null) { try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) { if (log.isDebugEnabled()) {
log.debug(sm.getString("request.session.failed", requestedSessionId, e.getMessage()), e);
} else {
log.info(sm.getString("request.session.failed", requestedSessionId, e.getMessage()));
}
session = null;
} if ((session != null) && !session.isValid()) {
session = null;
} if (session != null) {
session.access(); return session;
}
}
// Create a new session if requested and the response is not committed if (!create) { returnnull;
} boolean trackModesIncludesCookie =
context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE); if (trackModesIncludesCookie && response.getResponse().isCommitted()) { thrownew IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));
}
// Re-use session IDs provided by the client in very limited // circumstances.
String sessionId = getRequestedSessionId(); if (requestedSessionSSL) { // If the session ID has been obtained from the SSL handshake then // use it.
} elseif (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie())) { /* *Thisisthecommon(ish)usecase:usingthesamesessionIDwithmultiplewebapplicationsonthesame *host.TypicallythisisusedbyPortletimplementations.Itonlyworksifsessionsaretrackedvia *cookies.Thecookiemusthaveapathof"/"elseitwon'tbeprovidedforrequeststoallweb *applications. * *AnysessionIDprovidedbytheclientshouldbeforasessionthatalreadyexistssomewhereonthehost. *Checkifthecontextisconfiguredforthistobeconfirmed.
*/ if (context.getValidateClientProvidedNewSessionId()) { boolean found = false; for (Container container : getHost().findChildren()) {
Manager m = ((Context) container).getManager(); if (m != null) { try { if (m.findSession(sessionId) != null) {
found = true; break;
}
} catch (IOException e) { // Ignore. Problems with this manager will be // handled elsewhere.
}
}
} if (!found) {
sessionId = null;
}
}
} else {
sessionId = null;
}
session = manager.createSession(sessionId);
// Creating a new session cookie based on that session if (session != null && trackModesIncludesCookie) {
Cookie cookie =
ApplicationSessionCookieConfig.createSessionCookie(context, session.getIdInternal(), isSecure());
response.addSessionCookieInternal(cookie);
}
if (session == null) { returnnull;
}
session.access(); return session;
}
protected String unescape(String s) { if (s == null) { returnnull;
} if (s.indexOf('\\') == -1) { return s;
}
StringBuilder buf = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c != '\\') {
buf.append(c);
} else { if (++i >= s.length()) { thrownew IllegalArgumentException();// invalid escape, hence invalid cookie
}
c = s.charAt(i);
buf.append(c);
}
} return buf.toString();
}
private CookieProcessor getCookieProcessor() {
Context context = getContext(); if (context == null) { // No context. Possible call from Valve before a Host level // context rewrite when no ROOT content is configured. Use the // default CookieProcessor. returnnew Rfc6265CookieProcessor();
} else { return context.getCookieProcessor();
}
}
Parameters parameters = coyoteRequest.getParameters(); boolean success = false; try { // Set this every time in case limit has been changed via JMX int maxParameterCount = getConnector().getMaxParameterCount(); if (parts != null && maxParameterCount > 0) {
maxParameterCount -= parts.size();
}
parameters.setLimit(maxParameterCount);
// getCharacterEncoding() may have been overridden to search for // hidden form field containing request encoding
Charset charset = getCharset();
boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
parameters.setCharset(charset); if (useBodyEncodingForURI) {
parameters.setQueryStringCharset(charset);
} // Note: If !useBodyEncodingForURI, the query string encoding is // that set towards the start of CoyoteAdapter.service()
parameters.handleQueryParameters();
if (usingInputStream || usingReader) {
success = true; return;
}
// Store the accumulated languages that have been requested in // a local collection, sorted by the quality value (so we can // add Locales in descending order). The values will be ArrayLists // containing the corresponding Locales to be added
TreeMap<Double,ArrayList<Locale>> locales = new TreeMap<>();
while (values.hasMoreElements()) {
String value = values.nextElement();
parseLocalesHeader(value, locales);
}
// Process the quality values in highest->lowest order (due to // negating the Double value when creating the key) for (ArrayList<Locale> list : locales.values()) { for (Locale locale : list) {
addLocale(locale);
}
}
}
List<AcceptLanguage> acceptLanguages; try {
acceptLanguages = AcceptLanguage.parse(new StringReader(value));
} catch (IOException e) { // Mal-formed headers are ignore. Do the same in the unlikely event // of an IOException. return;
}
for (AcceptLanguage acceptLanguage : acceptLanguages) { // Add a new Locale to the list of Locales for this quality level Double key = Double.valueOf(-acceptLanguage.getQuality()); // Reverse the order
locales.computeIfAbsent(key, k -> new ArrayList<>()).add(acceptLanguage.getLocale());
}
}
// ----------------------------------------------------- Special attributes handling
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.92Bemerkung:
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.