Apache Tomcat: Security constraint bypass for CGI scripts
Description
Improper Handling of Case Sensitivity vulnerability in Apache Tomcat's GCI servlet allows security constraint bypass of security constraints that apply to the pathInfo component of a URI mapped to the CGI servlet.
This issue affects Apache Tomcat: from 11.0.0-M1 through 11.0.6, from 10.1.0-M1 through 10.1.40, from 9.0.0.M1 through 9.0.104. The following versions were EOL at the time the CVE was created but are known to be affected: 8.5.0 though 8.5.100. Other, older, EOL versions may also be affected.
Users are recommended to upgrade to version 11.0.7, 10.1.41 or 9.0.105, which fixes the issue.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2025-46701 describes a case-sensitivity bypass in Apache Tomcat's CGI servlet that lets attackers circumvent security constraints on pathInfo.
Root
Cause
CVE-2025-46701 is an Improper Handling of Case Sensitivity vulnerability within Apache Tomcat's CGI servlet. The bug allows a security constraint bypass specifically when constraints are applied to the pathInfo component of a URI that is mapped to the CGI servlet. [1][2][3]
Exploitation
An attacker can exploit this by crafting a URI where the path is case-altered but still resolves to the same resource, causing the servlet to not properly evaluate the path against the defined security constraints. This does not require authentication but requires the CGI servlet to be configured and accessible. The attack surface is the web server's URI handling logic. [1][4]
Impact
Successful exploitation allows an attacker to bypass the intended access controls on CGI resources, potentially gaining unauthorized access to protected CGI scripts or data. This undermines the security posture of the application. [1][2][3]
Mitigation
Apache Tomcat has released fixed versions: 11.0.7, 10.1.41, and 9.0.105. Users should upgrade immediately. Older EOL branches (e.g., 8.5.x) are also affected but unsupported. No workarounds are provided. [1][2][3]
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.tomcat:tomcat-catalinaMaven | >= 9.0.0.M1, < 9.0.105 | 9.0.105 |
org.apache.tomcat:tomcat-catalinaMaven | >= 10.1.0-M1, < 10.1.41 | 10.1.41 |
org.apache.tomcat:tomcat-catalinaMaven | >= 11.0.0-M1, < 11.0.7 | 11.0.7 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 9.0.0.M1, < 9.0.105 | 9.0.105 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 10.1.0-M1, < 10.1.41 | 10.1.41 |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 11.0.0-M1, < 11.0.7 | 11.0.7 |
org.apache.tomcat:tomcat-catalinaMaven | >= 8.5.0, <= 8.5.100 | — |
org.apache.tomcat.embed:tomcat-embed-coreMaven | >= 8.5.0, <= 8.5.100 | — |
Affected products
42- osv-coords40 versionspkg:apk/chainguard/camunda-zeebe-8.6pkg:apk/chainguard/camunda-zeebe-8.6-compatpkg:apk/chainguard/thingsboardpkg:apk/chainguard/thingsboard-tb-js-executorpkg:apk/chainguard/thingsboard-tb-mqtt-transportpkg:apk/chainguard/thingsboard-tb-nodepkg:apk/chainguard/thingsboard-tb-web-uipkg:apk/wolfi/thingsboardpkg:apk/wolfi/thingsboard-tb-js-executorpkg:apk/wolfi/thingsboard-tb-mqtt-transportpkg:apk/wolfi/thingsboard-tb-nodepkg:apk/wolfi/thingsboard-tb-web-uipkg:bitnami/tomcatpkg:maven/org.apache.tomcat.embed/tomcat-embed-corepkg:maven/org.apache.tomcat/tomcat-catalinapkg:rpm/opensuse/tomcat10&distro=openSUSE%20Leap%2015.6pkg:rpm/opensuse/tomcat&distro=openSUSE%20Leap%2015.6pkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-ESPOSpkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-LTSSpkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP6pkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP7pkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP5-LTSSpkg:rpm/suse/tomcat10&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Enterprise%20Storage%207.1pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP3-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP4-ESPOSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP4-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-ESPOSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20High%20Performance%20Computing%2015%20SP5-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP6pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Module%20for%20Web%20and%20Scripting%2015%20SP7pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2012%20SP5-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP3-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP4-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%2015%20SP5-LTSSpkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP3pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP4pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20for%20SAP%20Applications%2015%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Linux%20Enterprise%20Server%20LTSS%20Extended%20Security%2012%20SP5pkg:rpm/suse/tomcat&distro=SUSE%20Manager%20Server%204.3
< 8.6.30-r0+ 39 more
- (no CPE)range: < 8.6.30-r0
- (no CPE)range: < 8.6.30-r0
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 4.0.1-r4
- (no CPE)range: < 9.0.105
- (no CPE)range: >= 9.0.0.M1, < 9.0.105
- (no CPE)range: >= 9.0.0.M1, < 9.0.105
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 10.1.42-150200.5.45.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.36-3.145.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.106-150200.86.1
- (no CPE)range: < 9.0.36-3.145.1
- (no CPE)range: < 9.0.106-150200.86.1
- Apache Software Foundation/Apache Tomcatv5Range: 11.0.0-M1
Patches
6238d2aa54b99Use WebResource API to differentiate files and directories
2 files changed · +23 −15
java/org/apache/catalina/servlets/CGIServlet.java+22 −15 modified@@ -24,8 +24,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -45,12 +43,16 @@ import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; +import jakarta.servlet.UnavailableException; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; +import org.apache.catalina.Globals; +import org.apache.catalina.WebResource; +import org.apache.catalina.WebResourceRoot; import org.apache.catalina.util.IOTools; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -245,6 +247,8 @@ public final class CGIServlet extends HttpServlet { private final Set<String> cgiMethods = new HashSet<>(); private boolean cgiMethodsAll = false; + private transient WebResourceRoot resources = null; + /** * The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process. @@ -380,6 +384,13 @@ public void init(ServletConfig config) throws ServletException { } else if (value != null) { cmdLineArgumentsDecodedPattern = Pattern.compile(value); } + + // Load the web resources + resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR); + + if (resources == null) { + throw new UnavailableException(sm.getString("cgiServlet.noResources")); + } } @@ -803,7 +814,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringBuilder cgiPath = new StringBuilder(); StringBuilder urlPath = new StringBuilder(); - URL cgiScriptURL = null; + WebResource cgiScript = null; if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { cgiPath.append(servletPath); @@ -815,7 +826,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) { String urlSegment = pathWalker.nextToken(); cgiPath.append('/'); cgiPath.append(urlSegment); @@ -824,15 +835,11 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn if (log.isTraceEnabled()) { log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); } - try { - cgiScriptURL = context.getResource(cgiPath.toString()); - } catch (MalformedURLException e) { - // Ignore - should never happen - } + cgiScript = resources.getResource(cgiPath.toString()); } // No script was found - if (cgiScriptURL == null) { + if (cgiScript == null || !cgiScript.isFile()) { return new String[] { null, null, null, null }; } @@ -842,7 +849,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn String cgiName = null; String name = null; - path = context.getRealPath(cgiPath.toString()); + path = cgiScript.getCanonicalPath(); if (path == null) { /* * The script doesn't exist directly on the file system. It might be located in an archive or similar. @@ -858,14 +865,14 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } - try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + try (InputStream is = cgiScript.getInputStream()) { synchronized (expandFileLock) { // Check if file was created by concurrent request if (!tmpCgiFile.exists()) { try { Files.copy(is, tmpCgiFile.toPath()); } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(), tmpCgiFile.getAbsolutePath()), ioe); if (tmpCgiFile.exists()) { if (!tmpCgiFile.delete()) { @@ -876,13 +883,13 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(), tmpCgiFile.getAbsolutePath())); } } } } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe); } } path = tmpCgiFile.getAbsolutePath();
java/org/apache/catalina/servlets/LocalStrings.properties+1 −0 modified@@ -29,6 +29,7 @@ cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did no cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}] cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}] cgiServlet.notReady=CGI Servlet is not ready to run +cgiServlet.noResources=No static resources were found cgiServlet.runBadHeader=Bad header line [{0}] cgiServlet.runFail=I/O problems processing CGI cgiServlet.runHeaderReaderFail=I/O problems closing header reader
0f01966eb600Use WebResource API to differentiate files and directories
2 files changed · +23 −15
java/org/apache/catalina/servlets/CGIServlet.java+22 −15 modified@@ -25,8 +25,6 @@ import java.io.OutputStream; import java.io.Serial; import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -46,12 +44,16 @@ import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; +import jakarta.servlet.UnavailableException; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; +import org.apache.catalina.Globals; +import org.apache.catalina.WebResource; +import org.apache.catalina.WebResourceRoot; import org.apache.catalina.util.IOTools; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -247,6 +249,8 @@ public final class CGIServlet extends HttpServlet { private final Set<String> cgiMethods = new HashSet<>(); private boolean cgiMethodsAll = false; + private transient WebResourceRoot resources = null; + /** * The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process. @@ -382,6 +386,13 @@ public void init(ServletConfig config) throws ServletException { } else if (value != null) { cmdLineArgumentsDecodedPattern = Pattern.compile(value); } + + // Load the web resources + resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR); + + if (resources == null) { + throw new UnavailableException(sm.getString("cgiServlet.noResources")); + } } @@ -810,7 +821,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringBuilder cgiPath = new StringBuilder(); StringBuilder urlPath = new StringBuilder(); - URL cgiScriptURL = null; + WebResource cgiScript = null; if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { cgiPath.append(servletPath); @@ -822,7 +833,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) { String urlSegment = pathWalker.nextToken(); cgiPath.append('/'); cgiPath.append(urlSegment); @@ -831,15 +842,11 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn if (log.isTraceEnabled()) { log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); } - try { - cgiScriptURL = context.getResource(cgiPath.toString()); - } catch (MalformedURLException e) { - // Ignore - should never happen - } + cgiScript = resources.getResource(cgiPath.toString()); } // No script was found - if (cgiScriptURL == null) { + if (cgiScript == null || !cgiScript.isFile()) { return new String[] { null, null, null, null }; } @@ -849,7 +856,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn String cgiName = null; String name = null; - path = context.getRealPath(cgiPath.toString()); + path = cgiScript.getCanonicalPath(); if (path == null) { /* * The script doesn't exist directly on the file system. It might be located in an archive or similar. @@ -865,14 +872,14 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } - try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + try (InputStream is = cgiScript.getInputStream()) { synchronized (expandFileLock) { // Check if file was created by concurrent request if (!tmpCgiFile.exists()) { try { Files.copy(is, tmpCgiFile.toPath()); } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(), tmpCgiFile.getAbsolutePath()), ioe); if (tmpCgiFile.exists()) { if (!tmpCgiFile.delete()) { @@ -883,13 +890,13 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(), tmpCgiFile.getAbsolutePath())); } } } } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe); } } path = tmpCgiFile.getAbsolutePath();
java/org/apache/catalina/servlets/LocalStrings.properties+1 −0 modified@@ -29,6 +29,7 @@ cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did no cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}] cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}] cgiServlet.notReady=CGI Servlet is not ready to run +cgiServlet.noResources=No static resources were found cgiServlet.runBadHeader=Bad header line [{0}] cgiServlet.runFail=I/O problems processing CGI cgiServlet.runHeaderReaderFail=I/O problems closing header reader
8cb95ff03221Use WebResource API to differentiate files and directories
2 files changed · +23 −15
java/org/apache/catalina/servlets/CGIServlet.java+22 −15 modified@@ -24,8 +24,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -44,12 +42,16 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.UnavailableException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.catalina.Globals; +import org.apache.catalina.WebResource; +import org.apache.catalina.WebResourceRoot; import org.apache.catalina.util.IOTools; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -244,6 +246,8 @@ public final class CGIServlet extends HttpServlet { private final Set<String> cgiMethods = new HashSet<>(); private boolean cgiMethodsAll = false; + private transient WebResourceRoot resources = null; + /** * The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process. @@ -379,6 +383,13 @@ public void init(ServletConfig config) throws ServletException { } else if (value != null) { cmdLineArgumentsDecodedPattern = Pattern.compile(value); } + + // Load the web resources + resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR); + + if (resources == null) { + throw new UnavailableException(sm.getString("cgiServlet.noResources")); + } } @@ -802,7 +813,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringBuilder cgiPath = new StringBuilder(); StringBuilder urlPath = new StringBuilder(); - URL cgiScriptURL = null; + WebResource cgiScript = null; if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { cgiPath.append(servletPath); @@ -814,7 +825,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) { String urlSegment = pathWalker.nextToken(); cgiPath.append('/'); cgiPath.append(urlSegment); @@ -823,15 +834,11 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn if (log.isTraceEnabled()) { log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); } - try { - cgiScriptURL = context.getResource(cgiPath.toString()); - } catch (MalformedURLException e) { - // Ignore - should never happen - } + cgiScript = resources.getResource(cgiPath.toString()); } // No script was found - if (cgiScriptURL == null) { + if (cgiScript == null || !cgiScript.isFile()) { return new String[] { null, null, null, null }; } @@ -841,7 +848,7 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn String cgiName = null; String name = null; - path = context.getRealPath(cgiPath.toString()); + path = cgiScript.getCanonicalPath(); if (path == null) { /* * The script doesn't exist directly on the file system. It might be located in an archive or similar. @@ -857,14 +864,14 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } - try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + try (InputStream is = cgiScript.getInputStream()) { synchronized (expandFileLock) { // Check if file was created by concurrent request if (!tmpCgiFile.exists()) { try { Files.copy(is, tmpCgiFile.toPath()); } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(), tmpCgiFile.getAbsolutePath()), ioe); if (tmpCgiFile.exists()) { if (!tmpCgiFile.delete()) { @@ -875,13 +882,13 @@ protected String[] findCGI(String contextPath, String servletPath, String pathIn return new String[] { null, null, null, null }; } if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(), tmpCgiFile.getAbsolutePath())); } } } } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe); } } path = tmpCgiFile.getAbsolutePath();
java/org/apache/catalina/servlets/LocalStrings.properties+1 −0 modified@@ -29,6 +29,7 @@ cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did no cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}] cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}] cgiServlet.notReady=CGI Servlet is not ready to run +cgiServlet.noResources=No static resources were found cgiServlet.runBadHeader=Bad header line [{0}] cgiServlet.runFail=I/O problems processing CGI cgiServlet.runHeaderReaderFail=I/O problems closing header reader
fab7247d2f0eRefactor CGI servlet to access resources via WebResources
7 files changed · +97 −145
java/org/apache/catalina/servlets/CGIServlet.java+93 −140 modified@@ -25,6 +25,8 @@ import java.io.OutputStream; import java.io.Serial; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -628,9 +630,6 @@ protected class CGIEnvironment { /** pathInfo for the current request */ private String pathInfo = null; - /** real file system directory of the enclosing servlet's web app */ - private String webAppRootDir = null; - /** tempdir for context - used to expand scripts in unexpanded wars */ private File tmpDir = null; @@ -684,7 +683,6 @@ protected CGIEnvironment(HttpServletRequest req, ServletContext context) throws */ protected void setupFromContext(ServletContext context) { this.context = context; - this.webAppRootDir = context.getRealPath("/"); this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); } @@ -788,10 +786,9 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter * </p> * - * @param pathInfo String from HttpServletRequest.getPathInfo() - * @param webAppRootDir String from context.getRealPath("/") * @param contextPath String as from HttpServletRequest.getContextPath() * @param servletPath String as from HttpServletRequest.getServletPath() + * @param pathInfo String from HttpServletRequest.getPathInfo() * @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null. * The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or * webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting @@ -808,59 +805,108 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * found * </ul> */ - protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath, - String cgiPathPrefix) { - String path; - String name; - String scriptname; - - if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) { - // strip the trailing "/" from the webAppRootDir - webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1)); - } + protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) { - if (cgiPathPrefix != null) { - webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix; - } + StringBuilder cgiPath = new StringBuilder(); + StringBuilder urlPath = new StringBuilder(); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir)); - } + URL cgiScriptURL = null; - File currentLocation = new File(webAppRootDir); - StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/"); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { + cgiPath.append(servletPath); + } else { + cgiPath.append('/'); + cgiPath.append(cgiPathPrefix); } - StringBuilder cginameBuilder = new StringBuilder(); - while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { - String nextElement = (String) dirWalker.nextElement(); - currentLocation = new File(currentLocation, nextElement); - cginameBuilder.append('/').append(nextElement); + urlPath.append(servletPath); + + StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); + + while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + String urlSegment = pathWalker.nextToken(); + cgiPath.append('/'); + cgiPath.append(urlSegment); + urlPath.append('/'); + urlPath.append(urlSegment); if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); + } + try { + cgiScriptURL = context.getResource(cgiPath.toString()); + } catch (MalformedURLException e) { + // Ignore - should never happen } } - String cginame = cginameBuilder.toString(); - if (!currentLocation.isFile()) { + + // No script was found + if (cgiScriptURL == null) { return new String[] { null, null, null, null }; } - path = currentLocation.getAbsolutePath(); - name = currentLocation.getName(); + // Set-up return values + String path = null; + String scriptName = null; + String cgiName = null; + String name = null; - if (servletPath.startsWith(cginame)) { - scriptname = contextPath + cginame; - } else { - scriptname = contextPath + servletPath + cginame; + path = context.getRealPath(cgiPath.toString()); + if (path == null) { + /* + * The script doesn't exist directly on the file system. It might be located in an archive or similar. + * Such scripts are extracted to the web application's temporary file location. + */ + File tmpCgiFile = new File(tmpDir + cgiPath.toString()); + if (!tmpCgiFile.exists()) { + + // Create directories + File parent = tmpCgiFile.getParentFile(); + if (!parent.mkdirs() && !parent.isDirectory()) { + log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath())); + return new String[] { null, null, null, null }; + } + + try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + synchronized (expandFileLock) { + // Check if file was created by concurrent request + if (!tmpCgiFile.exists()) { + try { + Files.copy(is, tmpCgiFile.toPath()); + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + tmpCgiFile.getAbsolutePath()), ioe); + if (tmpCgiFile.exists()) { + if (!tmpCgiFile.delete()) { + log.warn(sm.getString("cgiServlet.expandDeleteFail", + tmpCgiFile.getAbsolutePath())); + } + } + return new String[] { null, null, null, null }; + } + if (log.isDebugEnabled()) { + log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + tmpCgiFile.getAbsolutePath())); + } + } + } + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + } + } + path = tmpCgiFile.getAbsolutePath(); } + scriptName = urlPath.toString(); + cgiName = scriptName.substring(servletPath.length()); + name = scriptName.substring(scriptName.lastIndexOf('/') + 1); + if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame)); + log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName)); } - return new String[] { path, scriptname, cginame, name }; + + return new String[] { path, scriptName, cgiName, name }; } + /** * Constructs the CGI environment to be supplied to the invoked CGI script; relies heavily on Servlet API * methods and findCGI @@ -895,13 +941,7 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { sPathInfoOrig = this.pathInfo; sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; - if (webAppRootDir == null) { - // The app has not been deployed in exploded form - webAppRootDir = tmpDir.toString(); - expandCGIScript(); - } - - sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix); + sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix); sCGIFullPath = sCGINames[0]; sCGIScriptName = sCGINames[1]; @@ -1027,93 +1067,6 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { return true; } - /** - * Extracts requested resource from web app archive to context work directory to enable CGI script to be - * executed. - */ - protected void expandCGIScript() { - StringBuilder srcPath = new StringBuilder(); - StringBuilder destPath = new StringBuilder(); - InputStream is = null; - - // paths depend on mapping - if (cgiPathPrefix == null) { - srcPath.append(pathInfo); - is = context.getResourceAsStream(srcPath.toString()); - destPath.append(tmpDir); - destPath.append(pathInfo); - } else { - // essentially same search algorithm as findCGI() - srcPath.append(cgiPathPrefix); - StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - // start with first element - while (pathWalker.hasMoreElements() && (is == null)) { - srcPath.append('/'); - srcPath.append(pathWalker.nextElement()); - is = context.getResourceAsStream(srcPath.toString()); - } - destPath.append(tmpDir); - destPath.append('/'); - destPath.append(srcPath); - } - - if (is == null) { - // didn't find anything, give up now - log.warn(sm.getString("cgiServlet.expandNotFound", srcPath)); - return; - } - - try { - File f = new File(destPath.toString()); - if (f.exists()) { - // Don't need to expand if it already exists - return; - } - - // create directories - File dir = f.getParentFile(); - if (!dir.mkdirs() && !dir.isDirectory()) { - log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath())); - return; - } - - try { - synchronized (expandFileLock) { - // make sure file doesn't exist - if (f.exists()) { - return; - } - - // create file - if (!f.createNewFile()) { - return; - } - - Files.copy(is, f.toPath()); - - if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath)); - } - } - } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe); - // delete in case file is corrupted - if (f.exists()) { - if (!f.delete()) { - log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath())); - } - } - } - } finally { - try { - is.close(); - } catch (IOException e) { - log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e); - } - } - } - - /** * Returns important CGI environment information in a multi-line text format. * @@ -1409,9 +1362,9 @@ protected String[] mapToStringArray(Map<String,?> map) throws NullPointerExcepti * <LI><u>Allowed characters in path segments</u>: This implementation does not allow non-terminal NULL segments * in the path -- IOExceptions may be thrown; * <LI><u>"<code>.</code>" and "<code>..</code>" path segments</u>: This implementation does not allow - * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException - * being thrown (this should never happen since Tomcat normalises the requestURI before determining the - * contextPath, servletPath and pathInfo); + * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException being + * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath, + * servletPath and pathInfo); * <LI><u>Implementation limitations</u>: This implementation does not impose any limitations except as * documented above. This implementation may be limited by the servlet container used to house this * implementation. In particular, all the primary CGI variable values are derived either directly or indirectly @@ -1449,7 +1402,7 @@ protected void run() throws IOException { Runtime rt; BufferedReader cgiHeaderReader = null; InputStream cgiOutput = null; - BufferedReader commandsStdErr ; + BufferedReader commandsStdErr; Thread errReaderThread = null; BufferedOutputStream commandsStdIn; Process proc = null;
java/org/apache/catalina/servlets/LocalStrings_fr.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Impossible de fermer le flux d''entrée du script ave cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}] -cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}] cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}] cgiServlet.find.location=Recherche d''un fichier en [{0}]
java/org/apache/catalina/servlets/LocalStrings_ja.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=パス [{0}] のスクリプトの入力ストリー cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。 cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした -cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}] cgiServlet.find.location=ファイル [{0}] を探しています。
java/org/apache/catalina/servlets/LocalStrings_ko.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=경로 [{0}]에 위치한 스크립트를 위한, 입 cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다. cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다. cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다. -cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다. cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다. cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}] cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중
java/org/apache/catalina/servlets/LocalStrings.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Failed to close input stream for script at path [{0}] cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}] -cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found cgiServlet.expandOk=Expanded script at path [{0}] to [{1}] cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}] cgiServlet.find.location=Looking for a file at [{0}]
java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=无法关闭路径[{0}]处脚本的输入流 cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}] cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败 cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败. -cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。 cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本 cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}] cgiServlet.find.location=在 [{0}] 查找文件
webapps/docs/changelog.xml+4 −0 modified@@ -129,6 +129,10 @@ <pr>843</pr>: Fix off by one validation logic for partial PUT ranges and associated test case. Submitted by Chenjp. (remm) </fix> + <scode> + Refactor GCI servlet to access resources via the + <code>WebResource</code> API. (markt) + </scode> </changelog> </subsection> <subsection name="Jasper">
2c6800111e7dRefactor CGI servlet to access resources via WebResources
7 files changed · +97 −145
java/org/apache/catalina/servlets/CGIServlet.java+93 −140 modified@@ -24,6 +24,8 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -621,9 +623,6 @@ protected class CGIEnvironment { /** pathInfo for the current request */ private String pathInfo = null; - /** real file system directory of the enclosing servlet's web app */ - private String webAppRootDir = null; - /** tempdir for context - used to expand scripts in unexpanded wars */ private File tmpDir = null; @@ -677,7 +676,6 @@ protected CGIEnvironment(HttpServletRequest req, ServletContext context) throws */ protected void setupFromContext(ServletContext context) { this.context = context; - this.webAppRootDir = context.getRealPath("/"); this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); } @@ -781,10 +779,9 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter * </p> * - * @param pathInfo String from HttpServletRequest.getPathInfo() - * @param webAppRootDir String from context.getRealPath("/") * @param contextPath String as from HttpServletRequest.getContextPath() * @param servletPath String as from HttpServletRequest.getServletPath() + * @param pathInfo String from HttpServletRequest.getPathInfo() * @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null. * The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or * webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting @@ -801,59 +798,108 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * found * </ul> */ - protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath, - String cgiPathPrefix) { - String path; - String name; - String scriptname; - - if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) { - // strip the trailing "/" from the webAppRootDir - webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1)); - } + protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) { - if (cgiPathPrefix != null) { - webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix; - } + StringBuilder cgiPath = new StringBuilder(); + StringBuilder urlPath = new StringBuilder(); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir)); - } + URL cgiScriptURL = null; - File currentLocation = new File(webAppRootDir); - StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/"); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { + cgiPath.append(servletPath); + } else { + cgiPath.append('/'); + cgiPath.append(cgiPathPrefix); } - StringBuilder cginameBuilder = new StringBuilder(); - while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { - String nextElement = (String) dirWalker.nextElement(); - currentLocation = new File(currentLocation, nextElement); - cginameBuilder.append('/').append(nextElement); + urlPath.append(servletPath); + + StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); + + while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + String urlSegment = pathWalker.nextToken(); + cgiPath.append('/'); + cgiPath.append(urlSegment); + urlPath.append('/'); + urlPath.append(urlSegment); if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); + } + try { + cgiScriptURL = context.getResource(cgiPath.toString()); + } catch (MalformedURLException e) { + // Ignore - should never happen } } - String cginame = cginameBuilder.toString(); - if (!currentLocation.isFile()) { + + // No script was found + if (cgiScriptURL == null) { return new String[] { null, null, null, null }; } - path = currentLocation.getAbsolutePath(); - name = currentLocation.getName(); + // Set-up return values + String path = null; + String scriptName = null; + String cgiName = null; + String name = null; - if (servletPath.startsWith(cginame)) { - scriptname = contextPath + cginame; - } else { - scriptname = contextPath + servletPath + cginame; + path = context.getRealPath(cgiPath.toString()); + if (path == null) { + /* + * The script doesn't exist directly on the file system. It might be located in an archive or similar. + * Such scripts are extracted to the web application's temporary file location. + */ + File tmpCgiFile = new File(tmpDir + cgiPath.toString()); + if (!tmpCgiFile.exists()) { + + // Create directories + File parent = tmpCgiFile.getParentFile(); + if (!parent.mkdirs() && !parent.isDirectory()) { + log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath())); + return new String[] { null, null, null, null }; + } + + try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + synchronized (expandFileLock) { + // Check if file was created by concurrent request + if (!tmpCgiFile.exists()) { + try { + Files.copy(is, tmpCgiFile.toPath()); + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + tmpCgiFile.getAbsolutePath()), ioe); + if (tmpCgiFile.exists()) { + if (!tmpCgiFile.delete()) { + log.warn(sm.getString("cgiServlet.expandDeleteFail", + tmpCgiFile.getAbsolutePath())); + } + } + return new String[] { null, null, null, null }; + } + if (log.isDebugEnabled()) { + log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + tmpCgiFile.getAbsolutePath())); + } + } + } + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + } + } + path = tmpCgiFile.getAbsolutePath(); } + scriptName = urlPath.toString(); + cgiName = scriptName.substring(servletPath.length()); + name = scriptName.substring(scriptName.lastIndexOf('/') + 1); + if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame)); + log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName)); } - return new String[] { path, scriptname, cginame, name }; + + return new String[] { path, scriptName, cgiName, name }; } + /** * Constructs the CGI environment to be supplied to the invoked CGI script; relies heavily on Servlet API * methods and findCGI @@ -888,13 +934,7 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { sPathInfoOrig = this.pathInfo; sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; - if (webAppRootDir == null) { - // The app has not been deployed in exploded form - webAppRootDir = tmpDir.toString(); - expandCGIScript(); - } - - sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix); + sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix); sCGIFullPath = sCGINames[0]; sCGIScriptName = sCGINames[1]; @@ -1020,93 +1060,6 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { return true; } - /** - * Extracts requested resource from web app archive to context work directory to enable CGI script to be - * executed. - */ - protected void expandCGIScript() { - StringBuilder srcPath = new StringBuilder(); - StringBuilder destPath = new StringBuilder(); - InputStream is = null; - - // paths depend on mapping - if (cgiPathPrefix == null) { - srcPath.append(pathInfo); - is = context.getResourceAsStream(srcPath.toString()); - destPath.append(tmpDir); - destPath.append(pathInfo); - } else { - // essentially same search algorithm as findCGI() - srcPath.append(cgiPathPrefix); - StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - // start with first element - while (pathWalker.hasMoreElements() && (is == null)) { - srcPath.append('/'); - srcPath.append(pathWalker.nextElement()); - is = context.getResourceAsStream(srcPath.toString()); - } - destPath.append(tmpDir); - destPath.append('/'); - destPath.append(srcPath); - } - - if (is == null) { - // didn't find anything, give up now - log.warn(sm.getString("cgiServlet.expandNotFound", srcPath)); - return; - } - - try { - File f = new File(destPath.toString()); - if (f.exists()) { - // Don't need to expand if it already exists - return; - } - - // create directories - File dir = f.getParentFile(); - if (!dir.mkdirs() && !dir.isDirectory()) { - log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath())); - return; - } - - try { - synchronized (expandFileLock) { - // make sure file doesn't exist - if (f.exists()) { - return; - } - - // create file - if (!f.createNewFile()) { - return; - } - - Files.copy(is, f.toPath()); - - if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath)); - } - } - } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe); - // delete in case file is corrupted - if (f.exists()) { - if (!f.delete()) { - log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath())); - } - } - } - } finally { - try { - is.close(); - } catch (IOException e) { - log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e); - } - } - } - - /** * Returns important CGI environment information in a multi-line text format. * @@ -1402,9 +1355,9 @@ protected String[] mapToStringArray(Map<String,?> map) throws NullPointerExcepti * <LI><u>Allowed characters in path segments</u>: This implementation does not allow non-terminal NULL segments * in the path -- IOExceptions may be thrown; * <LI><u>"<code>.</code>" and "<code>..</code>" path segments</u>: This implementation does not allow - * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException - * being thrown (this should never happen since Tomcat normalises the requestURI before determining the - * contextPath, servletPath and pathInfo); + * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException being + * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath, + * servletPath and pathInfo); * <LI><u>Implementation limitations</u>: This implementation does not impose any limitations except as * documented above. This implementation may be limited by the servlet container used to house this * implementation. In particular, all the primary CGI variable values are derived either directly or indirectly @@ -1442,7 +1395,7 @@ protected void run() throws IOException { Runtime rt; BufferedReader cgiHeaderReader = null; InputStream cgiOutput = null; - BufferedReader commandsStdErr ; + BufferedReader commandsStdErr; Thread errReaderThread = null; BufferedOutputStream commandsStdIn; Process proc = null;
java/org/apache/catalina/servlets/LocalStrings_fr.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Impossible de fermer le flux d''entrée du script ave cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}] -cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}] cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}] cgiServlet.find.location=Recherche d''un fichier en [{0}]
java/org/apache/catalina/servlets/LocalStrings_ja.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=パス [{0}] のスクリプトの入力ストリー cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。 cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした -cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}] cgiServlet.find.location=ファイル [{0}] を探しています。
java/org/apache/catalina/servlets/LocalStrings_ko.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=경로 [{0}]에 위치한 스크립트를 위한, 입 cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다. cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다. cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다. -cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다. cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다. cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}] cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중
java/org/apache/catalina/servlets/LocalStrings.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Failed to close input stream for script at path [{0}] cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}] -cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found cgiServlet.expandOk=Expanded script at path [{0}] to [{1}] cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}] cgiServlet.find.location=Looking for a file at [{0}]
java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=无法关闭路径[{0}]处脚本的输入流 cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}] cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败 cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败. -cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。 cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本 cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}] cgiServlet.find.location=在 [{0}] 查找文件
webapps/docs/changelog.xml+4 −0 modified@@ -138,6 +138,10 @@ <code>org.apache.catalina.connector.InputBuffer</code> with a static, zero length buffer. (markt) </scode> + <scode> + Refactor GCI servlet to access resources via the + <code>WebResource</code> API. (markt) + </scode> </changelog> </subsection> <subsection name="Coyote">
8df00018a252Refactor CGI servlet to access resources via WebResources
7 files changed · +97 −145
java/org/apache/catalina/servlets/CGIServlet.java+93 −140 modified@@ -24,6 +24,8 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLDecoder; import java.nio.file.Files; import java.util.ArrayList; @@ -620,9 +622,6 @@ protected class CGIEnvironment { /** pathInfo for the current request */ private String pathInfo = null; - /** real file system directory of the enclosing servlet's web app */ - private String webAppRootDir = null; - /** tempdir for context - used to expand scripts in unexpanded wars */ private File tmpDir = null; @@ -676,7 +675,6 @@ protected CGIEnvironment(HttpServletRequest req, ServletContext context) throws */ protected void setupFromContext(ServletContext context) { this.context = context; - this.webAppRootDir = context.getRealPath("/"); this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); } @@ -780,10 +778,9 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter * </p> * - * @param pathInfo String from HttpServletRequest.getPathInfo() - * @param webAppRootDir String from context.getRealPath("/") * @param contextPath String as from HttpServletRequest.getContextPath() * @param servletPath String as from HttpServletRequest.getServletPath() + * @param pathInfo String from HttpServletRequest.getPathInfo() * @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null. * The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or * webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting @@ -800,59 +797,108 @@ protected boolean setupFromRequest(HttpServletRequest req) throws UnsupportedEnc * found * </ul> */ - protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath, - String cgiPathPrefix) { - String path; - String name; - String scriptname; - - if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) { - // strip the trailing "/" from the webAppRootDir - webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1)); - } + protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) { - if (cgiPathPrefix != null) { - webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix; - } + StringBuilder cgiPath = new StringBuilder(); + StringBuilder urlPath = new StringBuilder(); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir)); - } + URL cgiScriptURL = null; - File currentLocation = new File(webAppRootDir); - StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/"); - if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { + cgiPath.append(servletPath); + } else { + cgiPath.append('/'); + cgiPath.append(cgiPathPrefix); } - StringBuilder cginameBuilder = new StringBuilder(); - while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { - String nextElement = (String) dirWalker.nextElement(); - currentLocation = new File(currentLocation, nextElement); - cginameBuilder.append('/').append(nextElement); + urlPath.append(servletPath); + + StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); + + while (pathWalker.hasMoreElements() && cgiScriptURL == null) { + String urlSegment = pathWalker.nextToken(); + cgiPath.append('/'); + cgiPath.append(urlSegment); + urlPath.append('/'); + urlPath.append(urlSegment); if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); + log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); + } + try { + cgiScriptURL = context.getResource(cgiPath.toString()); + } catch (MalformedURLException e) { + // Ignore - should never happen } } - String cginame = cginameBuilder.toString(); - if (!currentLocation.isFile()) { + + // No script was found + if (cgiScriptURL == null) { return new String[] { null, null, null, null }; } - path = currentLocation.getAbsolutePath(); - name = currentLocation.getName(); + // Set-up return values + String path = null; + String scriptName = null; + String cgiName = null; + String name = null; - if (servletPath.startsWith(cginame)) { - scriptname = contextPath + cginame; - } else { - scriptname = contextPath + servletPath + cginame; + path = context.getRealPath(cgiPath.toString()); + if (path == null) { + /* + * The script doesn't exist directly on the file system. It might be located in an archive or similar. + * Such scripts are extracted to the web application's temporary file location. + */ + File tmpCgiFile = new File(tmpDir + cgiPath.toString()); + if (!tmpCgiFile.exists()) { + + // Create directories + File parent = tmpCgiFile.getParentFile(); + if (!parent.mkdirs() && !parent.isDirectory()) { + log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath())); + return new String[] { null, null, null, null }; + } + + try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { + synchronized (expandFileLock) { + // Check if file was created by concurrent request + if (!tmpCgiFile.exists()) { + try { + Files.copy(is, tmpCgiFile.toPath()); + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, + tmpCgiFile.getAbsolutePath()), ioe); + if (tmpCgiFile.exists()) { + if (!tmpCgiFile.delete()) { + log.warn(sm.getString("cgiServlet.expandDeleteFail", + tmpCgiFile.getAbsolutePath())); + } + } + return new String[] { null, null, null, null }; + } + if (log.isDebugEnabled()) { + log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, + tmpCgiFile.getAbsolutePath())); + } + } + } + } catch (IOException ioe) { + log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); + } + } + path = tmpCgiFile.getAbsolutePath(); } + scriptName = urlPath.toString(); + cgiName = scriptName.substring(servletPath.length()); + name = scriptName.substring(scriptName.lastIndexOf('/') + 1); + if (log.isTraceEnabled()) { - log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame)); + log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName)); } - return new String[] { path, scriptname, cginame, name }; + + return new String[] { path, scriptName, cgiName, name }; } + /** * Constructs the CGI environment to be supplied to the invoked CGI script; relies heavily on Servlet API * methods and findCGI @@ -887,13 +933,7 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { sPathInfoOrig = this.pathInfo; sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; - if (webAppRootDir == null) { - // The app has not been deployed in exploded form - webAppRootDir = tmpDir.toString(); - expandCGIScript(); - } - - sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix); + sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix); sCGIFullPath = sCGINames[0]; sCGIScriptName = sCGINames[1]; @@ -1019,93 +1059,6 @@ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { return true; } - /** - * Extracts requested resource from web app archive to context work directory to enable CGI script to be - * executed. - */ - protected void expandCGIScript() { - StringBuilder srcPath = new StringBuilder(); - StringBuilder destPath = new StringBuilder(); - InputStream is = null; - - // paths depend on mapping - if (cgiPathPrefix == null) { - srcPath.append(pathInfo); - is = context.getResourceAsStream(srcPath.toString()); - destPath.append(tmpDir); - destPath.append(pathInfo); - } else { - // essentially same search algorithm as findCGI() - srcPath.append(cgiPathPrefix); - StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); - // start with first element - while (pathWalker.hasMoreElements() && (is == null)) { - srcPath.append('/'); - srcPath.append(pathWalker.nextElement()); - is = context.getResourceAsStream(srcPath.toString()); - } - destPath.append(tmpDir); - destPath.append('/'); - destPath.append(srcPath); - } - - if (is == null) { - // didn't find anything, give up now - log.warn(sm.getString("cgiServlet.expandNotFound", srcPath)); - return; - } - - try { - File f = new File(destPath.toString()); - if (f.exists()) { - // Don't need to expand if it already exists - return; - } - - // create directories - File dir = f.getParentFile(); - if (!dir.mkdirs() && !dir.isDirectory()) { - log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath())); - return; - } - - try { - synchronized (expandFileLock) { - // make sure file doesn't exist - if (f.exists()) { - return; - } - - // create file - if (!f.createNewFile()) { - return; - } - - Files.copy(is, f.toPath()); - - if (log.isDebugEnabled()) { - log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath)); - } - } - } catch (IOException ioe) { - log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe); - // delete in case file is corrupted - if (f.exists()) { - if (!f.delete()) { - log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath())); - } - } - } - } finally { - try { - is.close(); - } catch (IOException e) { - log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e); - } - } - } - - /** * Returns important CGI environment information in a multi-line text format. * @@ -1403,9 +1356,9 @@ protected String[] hashToStringArray(Hashtable<String,?> h) throws NullPointerEx * <LI><u>Allowed characters in path segments</u>: This implementation does not allow non-terminal NULL segments * in the path -- IOExceptions may be thrown; * <LI><u>"<code>.</code>" and "<code>..</code>" path segments</u>: This implementation does not allow - * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException - * being thrown (this should never happen since Tomcat normalises the requestURI before determining the - * contextPath, servletPath and pathInfo); + * "<code>.</code>" and "<code>..</code>" in the path, and such characters will result in an IOException being + * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath, + * servletPath and pathInfo); * <LI><u>Implementation limitations</u>: This implementation does not impose any limitations except as * documented above. This implementation may be limited by the servlet container used to house this * implementation. In particular, all the primary CGI variable values are derived either directly or indirectly @@ -1443,7 +1396,7 @@ protected void run() throws IOException { Runtime rt; BufferedReader cgiHeaderReader = null; InputStream cgiOutput = null; - BufferedReader commandsStdErr ; + BufferedReader commandsStdErr; Thread errReaderThread = null; BufferedOutputStream commandsStdIn; Process proc = null;
java/org/apache/catalina/servlets/LocalStrings_fr.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Impossible de fermer le flux d''entrée du script ave cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}] -cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}] cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}] cgiServlet.find.location=Recherche d''un fichier en [{0}]
java/org/apache/catalina/servlets/LocalStrings_ja.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=パス [{0}] のスクリプトの入力ストリー cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。 cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした -cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}] cgiServlet.find.location=ファイル [{0}] を探しています。
java/org/apache/catalina/servlets/LocalStrings_ko.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=경로 [{0}]에 위치한 스크립트를 위한, 입 cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다. cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다. cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다. -cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다. cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다. cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}] cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중
java/org/apache/catalina/servlets/LocalStrings.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Failed to close input stream for script at path [{0}] cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}] -cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found cgiServlet.expandOk=Expanded script at path [{0}] to [{1}] cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}] cgiServlet.find.location=Looking for a file at [{0}]
java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties+0 −1 modified@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=无法关闭路径[{0}]处脚本的输入流 cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}] cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败 cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败. -cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。 cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本 cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}] cgiServlet.find.location=在 [{0}] 查找文件
webapps/docs/changelog.xml+4 −0 modified@@ -126,6 +126,10 @@ <code>org.apache.catalina.connector.InputBuffer</code> with a static, zero length buffer. (markt) </scode> + <scode> + Refactor GCI servlet to access resources via the + <code>WebResource</code> API. (markt) + </scode> </changelog> </subsection> <subsection name="Coyote">
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
14- github.com/advisories/GHSA-h2fw-rfh5-95r3ghsaADVISORY
- lists.apache.org/thread/xhqqk9w5q45srcdqhogdk04lhdscv30jghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2025-46701ghsaADVISORY
- www.openwall.com/lists/oss-security/2025/05/29/4ghsaWEB
- github.com/apache/tomcat/commit/0f01966eb60015d975525019e12a087f05ebf01aghsaWEB
- github.com/apache/tomcat/commit/238d2aa54b99f91d1111467e2237d2244c64e558ghsaWEB
- github.com/apache/tomcat/commit/2c6800111e7d8d8d5403c07978ea9bff3db5a5a5ghsaWEB
- github.com/apache/tomcat/commit/8cb95ff03221067c511b3fa66d4f745bc4b0a605ghsaWEB
- github.com/apache/tomcat/commit/8df00018a252baa9497615d6420fb6c10466fa74ghsaWEB
- github.com/apache/tomcat/commit/fab7247d2f0e3a29d5daef565f829f383e10e5e2ghsaWEB
- lists.debian.org/debian-lts-announce/2025/07/msg00009.htmlghsaWEB
- tomcat.apache.org/security-10.htmlghsaWEB
- tomcat.apache.org/security-11.htmlghsaWEB
- tomcat.apache.org/security-9.htmlghsaWEB
News mentions
0No linked articles in our index yet.