HTTPS redirect middleware for the Infrastructure package (#52)

This commit is contained in:
2026-08-24 17:32:02 +02:00
parent fcfb3f21d5
commit 1520c44b16
8 changed files with 400 additions and 5 deletions
@@ -52,6 +52,7 @@ func application(
analytics: reader.analytics,
cacheControl: reader.cacheControl,
compressionMinResponseSize: reader.compressionMinResponseSize,
httpsRedirect: reader.httpsRedirect,
rateLimit: reader.rateLimit,
securityHeaders: reader.securityHeaders,
logLevel: reader.logLevel,
@@ -135,21 +136,23 @@ private func logger(
/// Builds the application's router.
///
/// Registers the request-logging middleware, the security-headers middleware that stamps the given `securityHeaders` onto every response, the
/// vary middleware that marks every response as varying on `Accept-Encoding`, the response-compression middleware that compresses responses
/// HTTPS-redirect middleware that bounces requests forwarded over plain HTTP to the canonical origin, the vary middleware that marks every response as varying on `Accept-Encoding`, the response-compression middleware that compresses responses
/// larger than `minimumResponseSizeToCompress` when the client advertises support, the localization middleware that negotiates the request's
/// language from its `Accept-Language` header, the not-found middleware that serves the error page, and the static file middleware that serves the
/// contents of `staticFilesPath` (tagging responses with the given `cacheControl` directives), then adds the `RootController` routes that
/// render the landing page, and the `HealthController` routes that serve the health check.
///
/// The security-headers middleware sits just inside request logging so it covers every response that reaches a client the landing page, the compressed
/// responses, the rendered error page, and the served static files.
/// responses, the rendered not-found page, and the served static files. The HTTPS redirect sits directly beneath it, so a redirect carries the security
/// headers but skips the negotiation, compression, and file lookup it would otherwise pay for.
/// - Parameters:
/// - staticFilesPath: the folder, relative to the working directory, the static files are served from.
/// - assetVersion: the version token the pages append to their asset URLs, or `nil` to leave them unversioned.
/// - analytics: the analytics tracker both pages embed, or `nil` to omit it.
/// - cacheControl: the cache-control directives applied to the served static files.
/// - compressionMinResponseSize: the minimum response body size, in bytes, before compression is applied.
/// - rateLimit: the rate limit applied to the rate-limited routes.
/// - httpsRedirect: the origin plain-HTTP requests are redirected to, and whether the forwarded-protocol header is trusted.
/// - rateLimit: the rate limit applied to the subscription endpoint.
/// - securityHeaders: the security headers applied to every response.
/// - logLevel: the level the request-logging middleware logs at.
/// - probe: the probe consulted by the `HealthController` readiness route.
@@ -160,6 +163,7 @@ private func router(
analytics: Analytics?,
cacheControl: CacheControl,
compressionMinResponseSize: Int,
httpsRedirect: HTTPSRedirectMiddleware<AppRequestContext>.Configuration,
rateLimit: RateLimitMiddleware<AppRequestContext>.Configuration,
securityHeaders: SecurityHeadersMiddleware<AppRequestContext>.Configuration,
logLevel: Logger.Level,
@@ -177,6 +181,9 @@ private func router(
SecurityHeadersMiddleware(
configuration: securityHeaders
)
HTTPSRedirectMiddleware(
configuration: httpsRedirect
)
VaryMiddleware()
ResponseCompressionMiddleware(
minimumResponseSizeToCompress: compressionMinResponseSize