[quickie synopsis]
A request arriving on a connector configured for scheme=https and with
secure=true is generating absolute redirect urls with scheme=https and port
= 80 (https://localhost:80/path.html) because incoming request was on 443
and didn't have an explicit port in the Host header.
[/quickie synopsis]

I have a the standard connector configured on port 8080.  I'm using an ssl
accelerator (stunnel, for the purposes of debugging this) to talk to a 2nd
connector which is configured to listen on port 8090.  I added secure="true"
and scheme="https" to the Connector tag of the second connector, but it is
otherwise identical.  The accelerator is configured to listen on port 443
and talk to port 8090.  The redirectPort of both connectors is set to 443.
If I connect to a resource, via stunnel, the connection correctly tunnels
through 443 to port 8090. Unfortunately, If the resource needs to construct
a redirect URL, after logging in to my app for example, the Connector goes
badly wrong.  I've gone through the code in the debugger and it correctly
gets a True response from request.isSecure().  Because the request is secure
and the response must also be secure, it can construct a standard redirect
url, so it calls response.sendResponse("/path.html"). That method eventually
needs to construct an absolute url, which is does via the toAbsolute()
method of org.apache.catalina.connector.Response.  That method uses
request.getScheme(), to retrieve "https" (correct) and
request.getServerName() to get the correct host name.  It then calls
request.getServerPort(), which incorrectly returns the value of 80.  I
assume it does this because there is no port specified in the Host header,
since the request is arriving on the default https port of 443, and there is
a bug which causes it to assume the default port is port 80, even though the
connector is configured to be secure and use https scheme.  The code which
constructs the url always appends :<port> to the hostname unless the port
matches the default port for the scheme, and since 80 != 443, it winds up
constructing a redirect url of https://localhost:80/path.html.   Needless to
say, this is totally incorrect.  There is nothing listening on port 80 at
all.  I could understand if the connector were to return a redirect url to
its own listen port of 8090.  I don't think it would be correct, but it
would at least make some sense.  But picking up port 80 when nothing is
listening to port 80 and the request isn't an http request without a port
has to be a bug (or at least a missing configuration option that doesn't
seem to be in the documentation anywhere).

What do I need to do to get the request to correctly return 443 as the port
when a request arrives on the connector without any port in the url or Host
header?

My two connectors are configured as such:

    <Connector
compressableMimeType="text/html,text/xml,text/javascript,text/css,application/x-amf"
               compression="on"
               compressionMinSize="2048"
               connectionTimeout="20000"
               enableLookups="false"
               noCompressionUserAgents="gozilla, traviata"
               port="8080"
               protocol="HTTP/1.1"
               redirectPort="443"/>

    <Connector
compressableMimeType="text/html,text/xml,text/javascript,text/css,application/x-amf"
               compression="on"
               compressionMinSize="2048"
               connectionTimeout="20000"
               enableLookups="false"
               noCompressionUserAgents="gozilla, traviata"
               port="8090"
               secure="true"
               scheme="https"
               protocol="HTTP/1.1"
               redirectPort="443"/>


[cringe]I'm not using 6.0.20 yet.  This is 6.0.18, but I couldn't find any
reference to a bug fix in 19 or 20.  It is a big deal to go to a new server
version, and I'd rather avoid the work if I can.  I'll test on 6.0.20 as
soon as I send this mail, but I am really hoping for a suggestion for how to
fix this on 6.0.18[/cringe]

Reply via email to