Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15828

Parameter values are null when making a PUT request

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 4.3.10, 5.0 RC3
    • Fix Version/s: 4.3.11, 5.0 RC4
    • Component/s: Web
    • Labels:
    • Last commented by a User:
      false

      Description

      Hello,

      here's the setup. I have a controller which is mapped to PUT request method. Spring-boot configures HttpPutFormContentFilter and in 4.3.8 the method in HttpPutFormContentRequestWrapper:getParameterValues looks like this:

      			String[] queryStringValues = super.getParameterValues(name);
      			List<String> formValues = this.formParameters.get(name);
      			if (formValues == null) {
      				return queryStringValues;
      			}
                             //more
      

      So because super.getParameterValues(name) returns correct value and the formParameters.get(name) returns null, the the correct value from queryStringValues is returned.

      Now in 4.3.9 this method looks like this:

      			String[] queryParam = (super.getQueryString() != null ? super.getParameterValues(name) : null);
      			List<String> formParam = this.formParameters.get(name);
      			if (formParam == null) {
      				return queryParam;
      			}
                             // more 
      

      Now because the super.getQueryString() is null and the formParam is null too then null is returned.

      Why has this been changed? Do I need to change my forms too? I was assuming my code should work in both 4.3.8 and 4.3.9

        Issue Links

          Activity

          Hide
          rstoya05-aop Rossen Stoyanchev added a comment -

          Request parameters are a Servlet API concept (no such thing in HTTP). The are sourced from URI query parameters, from form data in the request body, or parts in the body of a multipart form request. So I am first of all wondering what is the source of correct value, i.e. what does it correspond to in the actual HTTP request that came in? Or does it not correspond to anything and it was added later, e.g. possibly by decorating the request?

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - Request parameters are a Servlet API concept (no such thing in HTTP). The are sourced from URI query parameters, from form data in the request body, or parts in the body of a multipart form request. So I am first of all wondering what is the source of correct value, i.e. what does it correspond to in the actual HTTP request that came in? Or does it not correspond to anything and it was added later, e.g. possibly by decorating the request?
          Hide
          JonasHavers Jonas Havers added a comment - - edited

          The values are contained in the request parameters, just like defined in javax.servlet.ServletRequest#getParameterMap(), and can be used, like for normal POST requests.

          In the HttpPutFormContentFilter, the HttpInputMessage is a ServletServerHttpRequest with an overridden getBody method which is then passed to the FormHttpMessageConverter. The converter does not convert any values because the inputMessage body is empty and it tries to extract the parameters from the body.

          I do not know the reason why the "getBody" method is overridden. In the ServletServerHttpRequest, there is the following conditional implementation:

                  @Override
          	public InputStream getBody() throws IOException {
          		if (isFormPost(this.servletRequest)) {
          			return getBodyFromServletRequestParameters(this.servletRequest);
          		}
          		else {
          			return this.servletRequest.getInputStream();
          		}
          	}
          

          ServletServerHttpRequest.getBodyFromServletRequestParameters(request)) would work just fine for our PUT requests if the implementation above was not restricted to POST requests. Because the request already passed the HiddenHttpMethodFilter, it is currently wrapped as a "PUT request".

          The request wrappers at HttpPutFormContentRequestWrapper#getParameterValues are as follows:

          • org.springframework.web.filter.HiddenHttpMethodFilter.HttpMethodRequestWrapper
          • org.apache.catalina.connector.RequestFacade
          • org.apache.catalina.connector.Request
          Show
          JonasHavers Jonas Havers added a comment - - edited The values are contained in the request parameters, just like defined in javax.servlet.ServletRequest#getParameterMap() , and can be used, like for normal POST requests. In the HttpPutFormContentFilter , the HttpInputMessage is a ServletServerHttpRequest with an overridden getBody method which is then passed to the FormHttpMessageConverter . The converter does not convert any values because the inputMessage body is empty and it tries to extract the parameters from the body. I do not know the reason why the "getBody" method is overridden. In the ServletServerHttpRequest , there is the following conditional implementation: @Override public InputStream getBody() throws IOException { if (isFormPost(this.servletRequest)) { return getBodyFromServletRequestParameters(this.servletRequest); } else { return this.servletRequest.getInputStream(); } } ServletServerHttpRequest.getBodyFromServletRequestParameters(request)) would work just fine for our PUT requests if the implementation above was not restricted to POST requests. Because the request already passed the HiddenHttpMethodFilter , it is currently wrapped as a "PUT request". The request wrappers at HttpPutFormContentRequestWrapper#getParameterValues are as follows: org.springframework.web.filter.HiddenHttpMethodFilter.HttpMethodRequestWrapper org.apache.catalina.connector.RequestFacade org.apache.catalina.connector.Request
          Hide
          rstoya05-aop Rossen Stoyanchev added a comment - - edited

          Yes based on SPR-15835 one possible explanation for this ticket here is that actual underlying request method is HTTP POST and the body would have already been parsed by the Servlet container. So the assumption that super.getParameterValues() has to return query parameters isn't always true.

          Petar Tahchiev can you confirm that your case is a request coming from a browser where the form has the <input type="hidden" name="_method" value="PUT"> and server runs with HiddenHttpMethodFilter and HttpPutFormContentFilter?

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - - edited Yes based on SPR-15835 one possible explanation for this ticket here is that actual underlying request method is HTTP POST and the body would have already been parsed by the Servlet container. So the assumption that super.getParameterValues() has to return query parameters isn't always true. Petar Tahchiev can you confirm that your case is a request coming from a browser where the form has the <input type="hidden" name="_method" value="PUT"> and server runs with HiddenHttpMethodFilter and HttpPutFormContentFilter ?
          Hide
          vpavic Vedran Pavic added a comment -

          We were also affected by this, however while updating from 5.0.0.RC2 to 5.0.0.RC3.

          can you confirm that your case is a request coming from a browser where the form has the <input type="hidden" name="_method" value="PUT"> and server runs with HiddenHttpMethodFilter and HttpPutFormContentFilter?

          This has been our case - it's a Spring Boot application so both HiddenHttpMethodFilter and HttpPutFormContentFilter are automatically registered while hidden method input is rendered by Thymeleaf.

          I've tested the 5.0.0.BUILD-SNAPSHOT and can confirm that it restores the original/expected behavior.

          Show
          vpavic Vedran Pavic added a comment - We were also affected by this, however while updating from 5.0.0.RC2 to 5.0.0.RC3 . can you confirm that your case is a request coming from a browser where the form has the <input type="hidden" name="_method" value="PUT"> and server runs with HiddenHttpMethodFilter and HttpPutFormContentFilter ? This has been our case - it's a Spring Boot application so both HiddenHttpMethodFilter and HttpPutFormContentFilter are automatically registered while hidden method input is rendered by Thymeleaf. I've tested the 5.0.0.BUILD-SNAPSHOT and can confirm that it restores the original/expected behavior.
          Hide
          rstoya05-aop Rossen Stoyanchev added a comment -

          Thanks for checking.

          Show
          rstoya05-aop Rossen Stoyanchev added a comment - Thanks for checking.

            People

            • Assignee:
              rstoya05-aop Rossen Stoyanchev
              Reporter:
              ptahchiev Petar Tahchiev
              Last updater:
              St├ęphane Nicoll
            • Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                14 weeks, 3 days ago