Skip to content

Commit

Permalink
caddyhttp: Move HTTP redirect listener to an optional module (#4585)
Browse files Browse the repository at this point in the history
  • Loading branch information
francislavoie committed Feb 19, 2022
1 parent 7778912 commit 186fdba
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 5 deletions.
@@ -1,6 +1,7 @@
{
servers {
listener_wrappers {
http_redirect
tls
}
timeouts {
Expand Down Expand Up @@ -32,6 +33,9 @@ foo.com {
":443"
],
"listener_wrappers": [
{
"wrapper": "http_redirect"
},
{
"wrapper": "tls"
}
Expand Down
5 changes: 0 additions & 5 deletions modules/caddyhttp/app.go
Expand Up @@ -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)
Expand Down
42 changes: 42 additions & 0 deletions modules/caddyhttp/httpredirectlistener.go
Expand Up @@ -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(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
// of the request when the server is intended to accept HTTPS requests,
// to respond to an HTTP request with a redirect.
Expand Down Expand Up @@ -112,3 +149,8 @@ func firstBytesLookLikeHTTP(hdr []byte) bool {
}
return false
}

var (
_ caddy.ListenerWrapper = (*HTTPRedirectListenerWrapper)(nil)
_ caddyfile.Unmarshaler = (*HTTPRedirectListenerWrapper)(nil)
)

0 comments on commit 186fdba

Please sign in to comment.