Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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)
)