Skip to content

RequestCache optimization drains input buffer for POSTed forms #13818

Closed
@dc-oe

Description

@dc-oe

Describe the bug
The RequestCache was optimized by adding a query string parameter by default with the value of continue. Every request that comes in is checked for this parameter by calling the Request.getParameter() Jakarta API. Tomcat's implementation of this while drain the input buffer to get parameters posted in a form. As the Tomcat documentation for this API says:

https://tomcat.apache.org/tomcat-10.0-doc/servletapi/jakarta/servlet/ServletRequest.html#getParameter(java.lang.String)
If the parameter data was sent in the request body, such as occurs with an HTTP POST request, then reading the body directly via getInputStream() or getReader() can interfere with the execution of this method.

The optimization should only be checking the query string for this parameter. There is no need to read the form data input stream. I have created a private method to parse the query string instead of calling getParameter that has addressed the issue and is working for us. I can provide a pull request if desired. Just provide information on what branch it should be against.

To Reproduce
We use XML to configure our Spring Stack, but any simple form handler should show the issue. Create a Tomcat 10 instance with Spring Security that takes the defaults for the RequestCache. POST a form with form data in the body. See that the input stream is empty when it gets to the Servlet.

Expected behavior
The input stream contains the HTTP message body.

Sample

Will work on getting a sample. In the meantime, here is the fix. I'm sure it can be optimized. We have some workarounds, but this is critical for us to ship our product before the end of the year.

@Override
public HttpServletRequest getMatchingRequest(HttpServletRequest request, HttpServletResponse response) {
	if (this.matchingRequestParameterName != null
			&& this.getQueryParameter(request.getQueryString(), this.matchingRequestParameterName) == null) {
		this.logger.trace(
				"matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided");
		return null;
	}

...

/**
 * Do not drain the input buffer looking for a query parameter when posting a form.
 */
private String getQueryParameter(String query, String matchingRequestParameterName) {
	if (query != null) {
		String[] params = query.split("&");
		for (String param : params) {
			String name = param.split("=")[0];
			if ((name.length() > 0) && (name.compareTo(matchingRequestParameterName) == 0)) {
				return "";
			}
		}
	}
	return null;
}

David Cleary
Progress
[email protected]

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions