From d990577b2b0aadfb422f2e7f201334e129fd6b24 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Sat, 19 Feb 2022 01:40:06 -0500 Subject: [PATCH] caddyhttp: Move HTTP redirect listener to an optional module --- .../global_server_options_single.txt | 4 ++ modules/caddyhttp/app.go | 5 --- modules/caddyhttp/httpredirectlistener.go | 42 +++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt index fb0af2c3533..da3e6bc2f66 100644 --- a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt +++ b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt @@ -1,6 +1,7 @@ { servers { listener_wrappers { + http_redirect tls } timeouts { @@ -32,6 +33,9 @@ foo.com { ":443" ], "listener_wrappers": [ + { + "wrapper": "http_redirect" + }, { "wrapper": "tls" } diff --git a/modules/caddyhttp/app.go b/modules/caddyhttp/app.go index 67f9d1d68fc..64cc5401b91 100644 --- a/modules/caddyhttp/app.go +++ b/modules/caddyhttp/app.go @@ -343,11 +343,6 @@ func (app *App) Start() error { // enable TLS if there is a policy and if this is not the HTTP port useTLS := len(srv.TLSConnPolicies) > 0 && int(listenAddr.StartPort+portOffset) != app.httpPort() if useTLS { - // create HTTP redirect wrapper, which detects if - // the request had HTTP bytes on the HTTPS port, and - // triggers a redirect if so. - ln = &httpRedirectListener{Listener: ln} - // create TLS listener tlsCfg := srv.TLSConnPolicies.TLSConfig(app.ctx) ln = tls.NewListener(ln, tlsCfg) diff --git a/modules/caddyhttp/httpredirectlistener.go b/modules/caddyhttp/httpredirectlistener.go index 38225a3d262..53fb5e7eb7d 100644 --- a/modules/caddyhttp/httpredirectlistener.go +++ b/modules/caddyhttp/httpredirectlistener.go @@ -20,8 +20,45 @@ import ( "net" "net/http" "sync" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" ) +func init() { + caddy.RegisterModule(HttpRedirectWrapper{}) +} + +// HttpRedirectWrapper provides HTTP->HTTPS redirects for +// connections that come on the TLS port as an HTTP request, +// by detecting using the first few bytes that it's not a TLS +// handshake, but instead an HTTP request. +// +// This is especially useful when using a non-standard HTTPS port. +// A user may simply type the address in their browser without the +// https:// scheme, which would cause the browser to attempt the +// connection over HTTP, but this would cause a "Client sent an +// HTTP request to an HTTPS server" error response. +// +// This listener wrapper must be placed BEFORE the "tls" listener +// wrapper, for it to work properly. +type HttpRedirectWrapper struct{} + +func (HttpRedirectWrapper) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "caddy.listeners.http_redirect", + New: func() caddy.Module { return new(HttpRedirectWrapper) }, + } +} + +func (h *HttpRedirectWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + return nil +} + +func (h *HttpRedirectWrapper) WrapListener(l net.Listener) net.Listener { + return &httpRedirectListener{l} +} + // httpRedirectListener is listener that checks the first few bytes // of the request when the server is intended to accept HTTPS requests, // to respond to an HTTP request with a redirect. @@ -112,3 +149,8 @@ func firstBytesLookLikeHTTP(hdr []byte) bool { } return false } + +var ( + _ caddy.ListenerWrapper = (*HttpRedirectWrapper)(nil) + _ caddyfile.Unmarshaler = (*HttpRedirectWrapper)(nil) +)