[Geoserver-devel] Possible Bug in RestDispatcher 2.4.4

Hi,

We had an odd issue arise yesterday when we were testing an extension we have to GeoServer with a reverse proxy and a tomcat container using the proxyPort attribute on a catalina connector.

GeoServer 2.4.4

We have a reverse proxy listening on <servername/ip>:443/geoserver. This proxies the request behind our firewall to :8444. Our tomcat instance has a connector setup to listen on port 8444 with the proxy port set to 443. Our infrastructure team said this was to prevent the internal port from leaking back to the client browser and being visible in the developer tools during redirects. The /web, /gwc, /www, /w{m,f,c,mt}s, and /ows endpoints all work. However, /rest endpoint would return a 404 not found.

As a test, we added a second connector to the tomcat container listening on port 8443 but did not use the proxyPort attribute. When we exercised the application, the /rest/* endpoints started to work.

Tracing through our code as well as GeoServer code, we see that the authentication filters etc. are all being executed, but the main /rest/AddFile endpoint was never being called at all. I added some breakpoints to the package org.geoserver.rest, class RESTDispatcher, method createRoot() inside the new Router() init methods (line 158 in source code). Debugging behind the firewall, we found that request.getRoot().getParentRef() and request.getResourceRef() returned different values depending on whether the “standard” SSL port 443 was used or a non-standard port. It appears that the org.restlet.request does not return the port on request.getRoot() when it is the default 443, but does when it is anything else.

According to http://tomcat.apache.org/tomcat-5.5-doc/config/http.html, the proxyPort can be set “…to specify the server port to be returned for calls to request.getServerPort().” What we found is the following would not generate the expected dispatcher endpoint when the tomcat reported port and the actual listening port are different.

String baseURL = request.getRootRef().getParentRef().toString();

String rootPath = request.getRootRef().toString().substring(baseURL.length());

String pagePath = request.getResourceRef().toString().substring(baseURL.length());

In our case a primary call to our server may be the following

https://192.0.0.1/geoserver/rest/IngestStatus.json (this is an extension we built which returns status messages for an ingest process)

this is reverse proxy redirected to

https://192.1.1.1:8444/geoserver/rest/IngestStatus.json (internal systems)

Using the above code, this results in

request.getRootRef()= https://192.1.1.1/geoserver/rest “appears to be URL”

request. getResourceRef ()= https://192.1.1.1:8444/geoserver/rest/IngestStatus.json “actual listening URL”

baseURL = https://192.0.0.1/geoserver/ (length = 28)

rootPath = rest

pagePath = rver/rest/IngestStatus.json

since pagePath is using the getResouceRef() and the length of the baseURL, this offsets the expected result by the difference in the : and the port number, 5 in this case. So we end up with rver/rest/IngestStatus.json. Since this doesn’t exist in the routes mapping, we are returned a 404

Now, finally, the question:

Should the baseURL and rootPath be based on the request.getResourceRef().getParentRef() which would contain, ?I think?, the the complete URL to include the port vice the current way using request.getRootRef().getParentRef()?

This would preclude the pagePath variable from being generated from a different root URL, but using the length of the first root URL, right?

Thanks for looking,

Chris Snider

Senior Software Engineer

Intelligent Software Solutions, Inc.

Description: Description: Description: cid:image001.png@anonymised.com926...