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

MockMvc needs to accept prepared URI with encoded URI path variables

    XMLWordPrintable

    Details

    • Last commented by a User:
      true

      Description

      Good Afternoon,

      I have a controller with the following mapping

      @RequestMapping(value = "/circuit/{id}/view", method = RequestMethod.GET)
      public String getCircuit(@PathVariable String id,
                  @ModelAttribute("search") CircuitSearchController.SearchParams search, Model model, Principal principal) {...}
      

      The id value can contain reserved characters so I URL encode when rendering the view. For an id of "ja-ran-17 gigabitethernet 10/0.5790740:579-747" the browser request thus looks like

      http://localhost/myapp/circuit/ja-ran-17%20gigabitethernet%2010%2F0.5790740:579-747/view
      

      This is working ok.

      When i try to write a test for it however, the URL is getting double encoded

              ResultActions result = mockMvc.perform(get("/circuit/{id}/view", "ja-ran-17%20gigabitethernet%2010%2F0.5790740:579-747").principal(p));
      
              // THEN - circuit should be in the model
                          
      result.andExpect(status().isOk()).andExpect(model().attribute("circuit", hasProperty("circuitId", is(id))));
      
      

      log from real request in tomcat

      DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/circuit-id-manager/circuit/ja-ran-17 gigabitethernet 10/0.5790740:579-747/view] 
      DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /circuit/ja-ran-17%20gigabitethernet%2010%2F0.5790740:579-747/view 
      DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.String [...]
      

      log from mockmvc request

      DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing GET request for [/circuit/ja-ran-47%20gigabitethernet%2010%2F0.5790740:579-747/view] 
      DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /circuit/ja-ran-47%2520gigabitethernet%252010%252F0.5790740:579-747/view 
      

      With a real request my controller gets passed id="ja-ran-17 gigabitethernet 10/0.5790740:579-747"
      With a mock request my controller is passed id="ja-ran-47%20gigabitethernet%2010%2F0.5790740:579-747"

      Perhaps it is a feature of MockMvc that it automatically does URI encoding of path variables? If so it is inconsistent with other parts of the Web-Mvc framework see SPR-11401

      So i remove the encoding of my path variable and let MockMvc encode it. Now it doesn't find the handler

      DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing GET request for [/circuit/ja-ran-47 gigabitethernet 10/0.5790740:579-747/view] 
      DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /circuit/ja-ran-47%20gigabitethernet%2010/0.5790740:579-747/view 
      DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Did not find handler method for [/circuit/ja-ran-47%20gigabitethernet%2010/0.5790740:579-747/view] 
      

      I had a similar problem where the framework was treating %2F as / in contravention of RFC3986[1]. That is solved by a BeanPostProcessor calling

                  // URL decode after request mapping, not before.
                  requestMappingHandlerMapping.setUrlDecode(false);
      
                  // Workaround to make the previous fix work. See https://jira.springsource.org/browse/SPR-11101.
                  requestMappingHandlerMapping.setAlwaysUseFullPath(true);
      

      My guess is that the MockMvc Framework is not using the normal request mapping handler mapping, and so calling setUrlDecode on the normal one has no effect?

      [1]"When a URI is dereferenced, the components and subcomponents
      significant to the scheme-specific dereferencing process (if any)
      must be parsed and separated before the percent-encoded octets within
      those components can be safely decoded, as otherwise the data may be
      mistaken for component delimiters."

      and again in 7.3
      "Percent-encoded octets must be decoded at some point during the
      dereference process. Applications must split the URI into its
      components and subcomponents prior to decoding the octets, as
      otherwise the decoded octets might be mistaken for delimiters."

      That is clearly what is happening here, %2F is being mistaken for a path delimiter. Path delimitation must take place before decoding.

        Attachments

          Activity

            People

            Assignee:
            sdeleuze S├ębastien Deleuze
            Reporter:
            dantheperson daniel carter
            Last updater:
            Spring Issues Spring Issues
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Days since last comment:
              3 years, 24 weeks, 5 days ago