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

Incorrect resolution of handler mappings - the Allow header has wrong values

    Details

    • Type: Bug
    • Status: Open
    • Priority: Minor
    • Resolution: Unresolved
    • Affects Version/s: 3.1.2
    • Fix Version/s: Waiting for Triage
    • Component/s: None
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      Sending an OPTIONS request to:

      /api/myobject/count

      The controller defines the following methods:

      @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
      @ResponseStatus(HttpStatus.NO_CONTENT)
      public Privilege deleteOneById{...}
       
      @RequestMapping(method = RequestMethod.GET, value = "/count")
      @ResponseBody
      @ResponseStatus(value = HttpStatus.OK)
      public long count() {...}
      

      The DispatcherServlet - getHandler logic will fail to find a match (since OPTIONS is not mapped) but when calculating the Allow header - both of these 2 methods will be considered a match, and the value of that header will be:

      Allow: GET, DELETE

      When it should just be:

      Allow: GET

      This leads to additional and incorrect values for the Allow header.

        Activity

        Hide
        michael-o Michael Osipov added a comment - - edited

        I have hit the same issue but even worse.

        1. Create a stub project from: https://github.com/SpringSource/spring-framework-issues
        2. Start it with mvn tomcat:run.

        3. Perform a simple GET first with cURL:

        mosipov@v325:~$ curl --verbose http://v325.vanager.de:8080/11111/
        * About to connect() to v325.vanager.de port 8080 (#0)
        *   Trying 85.119.155.135... connected
        * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0)
        > GET /11111/ HTTP/1.1
        > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1
        > Host: v325.vanager.de:8080
        > Accept: */*
        >
        < HTTP/1.1 200 OK
        < Server: Apache-Coyote/1.1
        < Set-Cookie: JSESSIONID=1DC2480618B760639F75A4D50C5A1D5F; Path=/11111
        < Content-Type: text/html;charset=UTF-8
        < Content-Language: de-DE
        < Content-Length: 253
        < Date: Sat, 07 Sep 2013 16:57:57 GMT
        <
         
        <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
        <html>
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Home</title>
        </head>
        <body>
          <h1>Home</h1>
        </body>
        </html>
        * Connection #0 to host v325.vanager.de left intact
        * Closing connection #0
        

        4. Perform an OPTIONS request now:

        mosipov@v325:~$ curl -X OPTIONS --verbose http://v325.vanager.de:8080/11111/
        * About to connect() to v325.vanager.de port 8080 (#0)
        *   Trying 85.119.155.135... connected
        * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0)
        > OPTIONS /11111/ HTTP/1.1
        > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1
        > Host: v325.vanager.de:8080
        > Accept: */*
        >
        < HTTP/1.1 200 OK
        < Server: Apache-Coyote/1.1
        < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
        < Content-Length: 0
        < Date: Sat, 07 Sep 2013 16:59:24 GMT
        <
        * Connection #0 to host v325.vanager.de left intact
        * Closing connection #0
        

        Now, why do I see so may allowed methods? On this resource only HEAD, GET, OPTIONS and at most POST should be/is permitted. If I do perform a DELETE or PUT, I will receive:

        mosipov@v325:~$ curl -X PUT --verbose http://v325.vanager.de:8080/11111/
        * About to connect() to v325.vanager.de port 8080 (#0)
        *   Trying 85.119.155.135... connected
        * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0)
        > PUT /11111/ HTTP/1.1
        > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1
        > Host: v325.vanager.de:8080
        > Accept: */*
        >
        < HTTP/1.1 405 Method Not Allowed
        < Server: Apache-Coyote/1.1
        < Allow: POST, HEAD, GET
        < Content-Type: text/html;charset=utf-8
        < Content-Length: 1082
        < Date: Sat, 07 Sep 2013 17:00:34 GMT
        <
        <html><head><title>Apache Tomcat/6.0.29 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 405 - Request method 'PUT' not supported</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Request method 'PUT' not supported</u></p><p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource (Request method 'PUT' not supported).</u></p><HR size="1" nos* Connection #0 to host v325.vanager.de left intact
        * Closing connection #0
        hade="noshade"><h3>Apache Tomcat/6.0.29</h3></body></html>
        

        mosipov@v325:~$ curl -X DELETE --verbose http://v325.vanager.de:8080* About to connect() to v325.vanager.de port 8080 (#0)
        *   Trying 85.119.155.135... connected
        * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0)
        > DELETE /11111/ HTTP/1.1
        > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1
        > Host: v325.vanager.de:8080
        > Accept: */*
        >
        < HTTP/1.1 405 Method Not Allowed
        < Server: Apache-Coyote/1.1
        < Allow: POST, HEAD, GET
        < Content-Type: text/html;charset=utf-8
        < Content-Length: 1091
        < Date: Sat, 07 Sep 2013 17:00:52 GMT
        <
        <html><head><title>Apache Tomcat/6.0.29 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 405 - Request method 'DELETE' not supported</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Request method 'DELETE' not supported</u></p><p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource (Request method 'DELETE' not supported).</u></p><HR siz* Connection #0 to host v325.vanager.de left intact
        * Closing connection #0
        e="1" noshade="noshade"><h3>Apache Tomcat/6.0.29</h3></body></html>
        

        The calculation of Allow is simply broken.

        Show
        michael-o Michael Osipov added a comment - - edited I have hit the same issue but even worse. 1. Create a stub project from: https://github.com/SpringSource/spring-framework-issues 2. Start it with mvn tomcat:run . 3. Perform a simple GET first with cURL : mosipov@v325:~$ curl --verbose http://v325.vanager.de:8080/11111/ * About to connect() to v325.vanager.de port 8080 (#0) * Trying 85.119.155.135... connected * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0) > GET /11111/ HTTP/1.1 > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1 > Host: v325.vanager.de:8080 > Accept: */* > < HTTP/1.1 200 OK < Server: Apache-Coyote/1.1 < Set-Cookie: JSESSIONID=1DC2480618B760639F75A4D50C5A1D5F; Path=/11111 < Content-Type: text/html;charset=UTF-8 < Content-Language: de-DE < Content-Length: 253 < Date: Sat, 07 Sep 2013 16:57:57 GMT <   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Home</title> </head> <body> <h1>Home</h1> </body> </html> * Connection #0 to host v325.vanager.de left intact * Closing connection #0 4. Perform an OPTIONS request now: mosipov@v325:~$ curl -X OPTIONS --verbose http://v325.vanager.de:8080/11111/ * About to connect() to v325.vanager.de port 8080 (#0) * Trying 85.119.155.135... connected * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0) > OPTIONS /11111/ HTTP/1.1 > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1 > Host: v325.vanager.de:8080 > Accept: */* > < HTTP/1.1 200 OK < Server: Apache-Coyote/1.1 < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH < Content-Length: 0 < Date: Sat, 07 Sep 2013 16:59:24 GMT < * Connection #0 to host v325.vanager.de left intact * Closing connection #0 Now, why do I see so may allowed methods? On this resource only HEAD, GET, OPTIONS and at most POST should be/is permitted. If I do perform a DELETE or PUT, I will receive: mosipov@v325:~$ curl -X PUT --verbose http://v325.vanager.de:8080/11111/ * About to connect() to v325.vanager.de port 8080 (#0) * Trying 85.119.155.135... connected * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0) > PUT /11111/ HTTP/1.1 > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1 > Host: v325.vanager.de:8080 > Accept: */* > < HTTP/1.1 405 Method Not Allowed < Server: Apache-Coyote/1.1 < Allow: POST, HEAD, GET < Content-Type: text/html;charset=utf-8 < Content-Length: 1082 < Date: Sat, 07 Sep 2013 17:00:34 GMT < <html><head><title>Apache Tomcat/6.0.29 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 405 - Request method 'PUT' not supported</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Request method 'PUT' not supported</u></p><p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource (Request method 'PUT' not supported).</u></p><HR size="1" nos* Connection #0 to host v325.vanager.de left intact * Closing connection #0 hade="noshade"><h3>Apache Tomcat/6.0.29</h3></body></html> mosipov@v325:~$ curl -X DELETE --verbose http://v325.vanager.de:8080* About to connect() to v325.vanager.de port 8080 (#0) * Trying 85.119.155.135... connected * Connected to v325.vanager.de (85.119.155.135) port 8080 (#0) > DELETE /11111/ HTTP/1.1 > User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1 > Host: v325.vanager.de:8080 > Accept: */* > < HTTP/1.1 405 Method Not Allowed < Server: Apache-Coyote/1.1 < Allow: POST, HEAD, GET < Content-Type: text/html;charset=utf-8 < Content-Length: 1091 < Date: Sat, 07 Sep 2013 17:00:52 GMT < <html><head><title>Apache Tomcat/6.0.29 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 405 - Request method 'DELETE' not supported</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Request method 'DELETE' not supported</u></p><p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource (Request method 'DELETE' not supported).</u></p><HR siz* Connection #0 to host v325.vanager.de left intact * Closing connection #0 e="1" noshade="noshade"><h3>Apache Tomcat/6.0.29</h3></body></html> The calculation of Allow is simply broken.
        Hide
        rstoya05-aop Rossen Stoyanchev added a comment - - edited

        Eugen Paraschiv, I see why you might expect that only "Allow: GET" is returned in this case. However, I don't quite see how it could work based on the given configuration. After all the path "/count" matches the pattern "/{id}", i.e. there is no way to tell that "count" is not an id. In fact a request for "DELETE /count" will be matched to the method deleteOneById.

        Michael Osipov, the reason all HTTP methods are returned is most likely because the DispatcherServlet does not have its "dispatchOptionsRequest" property configured in which case OPTIONS requests are handled with the default behavior of the HttpServlet base class. See this part of the web.xml in the example project I created.

        Show
        rstoya05-aop Rossen Stoyanchev added a comment - - edited Eugen Paraschiv , I see why you might expect that only "Allow: GET" is returned in this case. However, I don't quite see how it could work based on the given configuration. After all the path "/count" matches the pattern "/{id}", i.e. there is no way to tell that "count" is not an id. In fact a request for "DELETE /count" will be matched to the method deleteOneById. Michael Osipov , the reason all HTTP methods are returned is most likely because the DispatcherServlet does not have its "dispatchOptionsRequest" property configured in which case OPTIONS requests are handled with the default behavior of the HttpServlet base class. See this part of the web.xml in the example project I created.
        Hide
        eugenparaschiv Eugen Paraschiv added a comment - - edited

        It's true that "count" does match "{id}" - so both returned values are in a way correct. However, one way to lean towards the more sensible default is to see if there is an exact match. If there is - then only consider these values when collecting the "Allow" values.
        This is similar to how, when the handler resolution is done, a request to "/count" would hit a method mapped to "count" even if there is another GET method mapped to "{id}".
        Hope that makes sense.

        Show
        eugenparaschiv Eugen Paraschiv added a comment - - edited It's true that "count" does match "{id}" - so both returned values are in a way correct. However, one way to lean towards the more sensible default is to see if there is an exact match. If there is - then only consider these values when collecting the "Allow" values. This is similar to how, when the handler resolution is done, a request to "/count" would hit a method mapped to "count" even if there is another GET method mapped to "{id}". Hope that makes sense.

          People

          • Assignee:
            rstoya05-aop Rossen Stoyanchev
            Reporter:
            eugenparaschiv Eugen Paraschiv
            Last updater:
            Eugen Paraschiv
          • Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Days since last comment:
              33 weeks, 2 days ago