caddyhttp: Move HTTP redirect listener to an optional module (#4585)

This commit is contained in:
Francis Lavoie 2022-02-19 17:36:36 -05:00 committed by GitHub
parent 7778912d4e
commit 186fdba916
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 5 deletions

View file

@ -1,6 +1,7 @@
{ {
servers { servers {
listener_wrappers { listener_wrappers {
http_redirect
tls tls
} }
timeouts { timeouts {
@ -32,6 +33,9 @@ foo.com {
":443" ":443"
], ],
"listener_wrappers": [ "listener_wrappers": [
{
"wrapper": "http_redirect"
},
{ {
"wrapper": "tls" "wrapper": "tls"
} }

View file

@ -343,11 +343,6 @@ func (app *App) Start() error {
// enable TLS if there is a policy and if this is not the HTTP port // 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() useTLS := len(srv.TLSConnPolicies) > 0 && int(listenAddr.StartPort+portOffset) != app.httpPort()
if useTLS { 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 // create TLS listener
tlsCfg := srv.TLSConnPolicies.TLSConfig(app.ctx) tlsCfg := srv.TLSConnPolicies.TLSConfig(app.ctx)
ln = tls.NewListener(ln, tlsCfg) ln = tls.NewListener(ln, tlsCfg)

View file

@ -20,8 +20,45 @@ import (
"net" "net"
"net/http" "net/http"
"sync" "sync"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
) )
func init() {
caddy.RegisterModule(HTTPRedirectListenerWrapper{})
}
// HTTPRedirectListenerWrapper 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 HTTPRedirectListenerWrapper struct{}
func (HTTPRedirectListenerWrapper) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "caddy.listeners.http_redirect",
New: func() caddy.Module { return new(HTTPRedirectListenerWrapper) },
}
}
func (h *HTTPRedirectListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return nil
}
func (h *HTTPRedirectListenerWrapper) WrapListener(l net.Listener) net.Listener {
return &httpRedirectListener{l}
}
// httpRedirectListener is listener that checks the first few bytes // httpRedirectListener is listener that checks the first few bytes
// of the request when the server is intended to accept HTTPS requests, // of the request when the server is intended to accept HTTPS requests,
// to respond to an HTTP request with a redirect. // to respond to an HTTP request with a redirect.
@ -112,3 +149,8 @@ func firstBytesLookLikeHTTP(hdr []byte) bool {
} }
return false return false
} }
var (
_ caddy.ListenerWrapper = (*HTTPRedirectListenerWrapper)(nil)
_ caddyfile.Unmarshaler = (*HTTPRedirectListenerWrapper)(nil)
)