Harald
Harald

Reputation: 5093

Redirect HTTP to HTTPS on the same port with Jetty --- identifying http vs. https from the Request

Starting with Jetty 9.4.? it is possible to run HTTP and HTTPs on the same port. The gist of it is:

HttpConnectionFactory http = new HttpConnectionFactory();
SslConnectionFactory https = new SslConnectionFactory(sslCtxFactory, http.getProtocol());
DetectorConnectionFactory conFactory = new DetectorConnectionFactory(https);
ServerConnector connector = new ServerConnector(server, conFactory, http);

Since I only want to serve HTTPS, I would like to redirect each and every http://host:port/stuff to https://host:port/stuff. I know how to redirect with either subclass of RedirectRule or just with a handler called early.

The thing I am struggling with is: how do I figure out from the request that the connection is HTTP and not HTTPS?

When I look at the Request in the debugger, I found no hints, everything looks as if it is http even if the connection is https, Request.isSecure() is false, scheme is http and so on. The best thing I could come up with was:

if (Request.getHttpChannel().getEndPoint() instanceof SslConnection.DecryptedEndPoint())

Here is an annotated and clipped stack trace showing how my handlers are wrapped into each other:

at server.HttpToHttpsRedirectRule.matchAndApply(HttpToHttpsRedirectRule.java:34)
         "^^ Here I do the matchAndApply myself and then use a jetty RedirectRule.apply"
         "The redirect works OK, but figuring whether it is HTTPS does not work"
at org.eclipse.jetty.rewrite.handler.RuleContainer.apply(RuleContainer.java:166)
at org.eclipse.jetty.rewrite.handler.RuleContainer.matchAndApply(RuleContainer.java:145)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:317)
at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:766)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at server.LogHandler.handle(LogHandler.java:33)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
                                   "^^^ the outermost handler"
[clip]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
                           "^^^ we decoded the ssl and feed the lower levels plain HTTP"
[clip]
at org.eclipse.jetty.io.ssl.SslConnection$1.run(SslConnection.java:146)
                           "^^^ we are in SSL"

It is in my HttpToHttpsRedirectRule where I would like to figure out which connection it is. Is there a saner solution than the instanceof mentioned above?

Upvotes: 1

Views: 710

Answers (1)

Harald
Harald

Reputation: 5093

To make sure the original scheme (and possibly more) information is kept, it is necessary to add a SecureRequestCustomizer to the http configuration like this:

HttpConfiguration httpConf = new HttpConfiguration();
httpConf.addCustomizer(new SecureRequestCustomizer());
HttpConnectionFactory http = new HttpConnectionFactory(httpConf);
SslConnectionFactory https = new SslConnectionFactory(sslCtxFactory, http.getProtocol());
DetectorConnectionFactory conFactory = new DetectorConnectionFactory(https);
ServerConnector connector = new ServerConnector(server, conFactory, http);

The crucial hint was found in the jetty mailing list.

Upvotes: 1

Related Questions