Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 3.0 M3
    • Fix Version/s: 3.1 RC1
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      In RESTful services scenario it is not uncommon to accept the incoming data (as service input) in the form-encoded format (Content-type: application/x-www-form-urlencoded). This format is well-known, popular, implemented in every language. See the RESTful Web Service book from O'Reilly for longer discussion of such choice.
      Obviously, REST service will accept form-endoded data in POST and PUT request. The problem is that servlet spec (or implementations) seems to be broken in this area. HttpServletRequest.getParameter("foo") method for form-encoded data returns the parameter value only for POST requests, not for PUT. I've tested it on Tomcat and Glassfish.
      This also means that all Spring's autobinding features (with command object) will fail for PUT requests. This is really serious problem, as for PUT requests, one have to manually parse and decode the request body.
      The solution would be I think to add some filter, which wraps the request when the method is PUT and content type is "application/x-www-form-urlencoded", and override the getParameter() and related methods.
      It would be probably also helpful to check the servlet spec for explanation of this behavior, and how it is implemented in Tomcat (or other containers).

      To reproduce, simply create servlet or JSP like this:
      <%=request.getParameter("foo")%>
      and send POST and then PUT request to it, with content-type set to "application/x-www-form-urlencoded" and body equal to "foo=bar"

        Issue Links

          Activity

          Hide
          Grzegorz Borkowski added a comment -

          See also this: http://osdir.com/ml/web.services.rest/2006-08/msg00091.html
          They claim Restlet supports this feature, so this can be also interesting point of reference.

          Show
          Grzegorz Borkowski added a comment - See also this: http://osdir.com/ml/web.services.rest/2006-08/msg00091.html They claim Restlet supports this feature, so this can be also interesting point of reference.
          Hide
          Grzegorz Borkowski added a comment -

          With Spring 3.0 M3, there is a FormHttpMessageConverter which works with PUT and retrieves all body parameters; so the need for calling getParameter() directly in controller is reduced. This means that this task's priority is much lower now (I have no permission to change it on my own).
          However, I haven't checked how it relates to Spring's autobinding features (with command object).

          Show
          Grzegorz Borkowski added a comment - With Spring 3.0 M3, there is a FormHttpMessageConverter which works with PUT and retrieves all body parameters; so the need for calling getParameter() directly in controller is reduced. This means that this task's priority is much lower now (I have no permission to change it on my own). However, I haven't checked how it relates to Spring's autobinding features (with command object).
          Hide
          Mike Yin added a comment -

          I think this is related, but please let me know if it is not, and I can make a new issue. I have a couple of @RequestMapping(value="/blah", method=RequestMethod.PUT) annotated methods. using @RequestParam("someParam") on them works but only if the parameter is in the querystring. if it's in the body, it doesn't get parsed and used as a request parameter, but it does if the method is RequestMethod.POST. Is the only workaround to have a message converter registered that handles x-www-form-urlencoded and use a @RequestBody annotation to have a form parameter map? the reason i need it to be in the body and not the query string is because one of my parameters is a list, and I don't want to hit any URL length issues.

          Show
          Mike Yin added a comment - I think this is related, but please let me know if it is not, and I can make a new issue. I have a couple of @RequestMapping(value="/blah", method=RequestMethod.PUT) annotated methods. using @RequestParam("someParam") on them works but only if the parameter is in the querystring. if it's in the body, it doesn't get parsed and used as a request parameter, but it does if the method is RequestMethod.POST. Is the only workaround to have a message converter registered that handles x-www-form-urlencoded and use a @RequestBody annotation to have a form parameter map? the reason i need it to be in the body and not the query string is because one of my parameters is a list, and I don't want to hit any URL length issues.
          Hide
          Rossen Stoyanchev added a comment -

          Sample code for this issue is available at (in the SPR-5628 sub-directory):
          https://github.com/SpringSource/spring-framework-issues

          Show
          Rossen Stoyanchev added a comment - Sample code for this issue is available at (in the SPR-5628 sub-directory): https://github.com/SpringSource/spring-framework-issues
          Hide
          Rossen Stoyanchev added a comment -

          An HttpPutFormContentFilter is available and can be configured if needed. It intercepts HTTP PUT requests where Content-Type:x-www-form-urlencoded, reads the form data from the body of the request, and wraps the ServletRequest to make the form data available as request parameters.

          Show
          Rossen Stoyanchev added a comment - An HttpPutFormContentFilter is available and can be configured if needed. It intercepts HTTP PUT requests where Content-Type:x-www-form-urlencoded, reads the form data from the body of the request, and wraps the ServletRequest to make the form data available as request parameters.
          Hide
          Arjan van B. added a comment -

          See the documentation in Working with "application/x-www-form-urlencoded" data.

          And beware that both HttpPutFormContentFilter (FishEye) and converters such as FormHttpMessageConverter (FishEye) consume the request's input stream. This seems to imply one cannot use HttpPutFormContentFilter in an application that also uses PUT with @RequestBody MultiValueMap<String, String> and/or HttpEntity<MultiValueMap<String, String>>. (Unless the filter is only configured for very specific URLs in <filter-mapping>.)

          Like both of the following will throw IOException: Stream closed when HttpPutFormContentFilter has been configured for use elsewhere in the application:

          @RequestMapping(..., method = RequestMethod.PUT)
          public ... doUpdate(final @RequestBody MultiValueMap<String, String> data, ...) {
            ...
          }
          
          @RequestMapping(..., method = RequestMethod.PUT)
          public ... doUpdate(final HttpEntity<MultiValueMap<String, String>> data, ...) {
            ...
          }
          
          Show
          Arjan van B. added a comment - See the documentation in Working with "application/x-www-form-urlencoded" data . And beware that both HttpPutFormContentFilter ( FishEye ) and converters such as FormHttpMessageConverter ( FishEye ) consume the request's input stream. This seems to imply one cannot use HttpPutFormContentFilter in an application that also uses PUT with @RequestBody MultiValueMap<String, String> and/or HttpEntity<MultiValueMap<String, String>> . (Unless the filter is only configured for very specific URLs in <filter-mapping> .) Like both of the following will throw IOException: Stream closed when HttpPutFormContentFilter has been configured for use elsewhere in the application: @RequestMapping(..., method = RequestMethod.PUT) public ... doUpdate( final @RequestBody MultiValueMap< String , String > data, ...) { ... } @RequestMapping(..., method = RequestMethod.PUT) public ... doUpdate( final HttpEntity<MultiValueMap< String , String >> data, ...) { ... }
          Hide
          Rossen Stoyanchev added a comment -

          As I mentioned under SPR-8415, feel free to improve the documentation.

          Show
          Rossen Stoyanchev added a comment - As I mentioned under SPR-8415 , feel free to improve the documentation.
          Hide
          Stevo Slavić added a comment -

          Created http://java.net/jira/browse/SERVLET_SPEC-58 to have this properly supported in servlet spec.

          Show
          Stevo Slavić added a comment - Created http://java.net/jira/browse/SERVLET_SPEC-58 to have this properly supported in servlet spec.
          Hide
          Rossen Stoyanchev added a comment -

          Thanks Stevo, that makes sense.

          Show
          Rossen Stoyanchev added a comment - Thanks Stevo, that makes sense.

            People

            • Assignee:
              Rossen Stoyanchev
              Reporter:
              Grzegorz Borkowski
              Last updater:
              Rossen Stoyanchev
            • Votes:
              4 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                1 year, 8 weeks, 5 days ago