This week we updated our production Apache Tomcat installations to 8.0.15 (from 5.5.30). We don't need any of TC8's additional capabilities, but we do need an implementation with ongoing security updates. An unexpected difference between these versions is the handling of trailing slashes on URL paths. TC5 would send any requests that were not mapped to a specific servlet to the the ROOT servlet. For example, when the path "/A/B/" was presented to TC5 it would look for servlet A and, not finding it, send the traffic to ROOT. TC8 does not: It returns an HTTP 404 error.
I tried to solve the problem by coding a TC8 Valve to intercept the request, rewrite the URL without a trailing slash, and then have TC8 restart the request process. And all without losing any request content sent with, for example, a PUT request. I was able to intercept and rewrite the URL, but I never successfully got TC8 to restart the request. I was very close, but time ran out for further exploration. (I was also unsuccessful with a Filter implementation.)
Our services are fronted by haproxy and it does allow for URL rewriting. The following placed in a frontend or a backend definition will remove any trailing slashes in the URL's path:
acl has-trailing-slash path_end / reqrep ^(HEAD\ )(.*?)(\/+)(\?.*?)?(\ HTTP\/1.) \1\2\4\5 if has-trailing-slash reqrep ^(GET\ )(.*?)(\/+)(\?.*?)?(\ HTTP\/1.) \1\2\4\5 if has-trailing-slash reqrep ^(PUT\ )(.*?)(\/+)(\?.*?)?(\ HTTP\/1.) \1\2\4\5 if has-trailing-slash reqrep ^(POST\ )(.*?)(\/+)(\?.*?)?(\ HTTP\/1.) \1\2\4\5 if has-trailing-slash
One could replace the 4 rewrite rules with just one that handles all the HTTP methods but I chose not to: The leading 2 characters are enough to quickly select the right rule.