diff --git a/binary-compatibility-validator/reference-public-api/ktor-server-core.txt b/binary-compatibility-validator/reference-public-api/ktor-server-core.txt index ace3399b2..bb7004451 100644 --- a/binary-compatibility-validator/reference-public-api/ktor-server-core.txt +++ b/binary-compatibility-validator/reference-public-api/ktor-server-core.txt @@ -620,14 +620,17 @@ public final class io/ktor/features/HSTS$Feature : io/ktor/application/Applicati public final class io/ktor/features/HttpsRedirect { public static final field Feature Lio/ktor/features/HttpsRedirect$Feature; public fun (Lio/ktor/features/HttpsRedirect$Configuration;)V + public final fun getExemptions ()Ljava/util/List; public final fun getPermanent ()Z public final fun getRedirectPort ()I } public final class io/ktor/features/HttpsRedirect$Configuration { public fun ()V + public final fun getExemptions ()Ljava/util/List; public final fun getPermanentRedirect ()Z public final fun getSslPort ()I + public final fun setExemptions (Ljava/util/List;)V public final fun setPermanentRedirect (Z)V public final fun setSslPort (I)V } diff --git a/ktor-server/ktor-server-core/jvm/src/io/ktor/features/HttpsRedirect.kt b/ktor-server/ktor-server-core/jvm/src/io/ktor/features/HttpsRedirect.kt index faa5d1c97..ab15bd426 100644 --- a/ktor-server/ktor-server-core/jvm/src/io/ktor/features/HttpsRedirect.kt +++ b/ktor-server/ktor-server-core/jvm/src/io/ktor/features/HttpsRedirect.kt @@ -23,6 +23,12 @@ class HttpsRedirect(config: Configuration) { */ val permanent: Boolean = config.permanentRedirect + /** + * Exempted paths + */ + + val exemptions: List = config.exemptions + /** * Redirect feature configuration */ @@ -36,6 +42,12 @@ class HttpsRedirect(config: Configuration) { * Use permanent redirect or temporary */ var permanentRedirect: Boolean = true + + /** + * Exempted path prefixes. Any request for a path starting with these prefixes will not be redirected. + */ + + var exemptions: List = listOf() } /** @@ -46,7 +58,8 @@ class HttpsRedirect(config: Configuration) { override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): HttpsRedirect { val feature = HttpsRedirect(Configuration().apply(configure)) pipeline.intercept(ApplicationCallPipeline.Features) { - if (call.request.origin.scheme == "http") { + if (call.request.origin.scheme == "http" && + !feature.exemptions.any { call.request.origin.uri.startsWith(it) }) { val redirectUrl = call.url { protocol = URLProtocol.HTTPS; port = feature.redirectPort } call.respondRedirect(redirectUrl, feature.permanent) finish() diff --git a/ktor-server/ktor-server-tests/jvm/test/io/ktor/tests/server/features/HttpsRedirectFeatureTest.kt b/ktor-server/ktor-server-tests/jvm/test/io/ktor/tests/server/features/HttpsRedirectFeatureTest.kt index 1f455a4aa..1de871ead 100644 --- a/ktor-server/ktor-server-tests/jvm/test/io/ktor/tests/server/features/HttpsRedirectFeatureTest.kt +++ b/ktor-server/ktor-server-tests/jvm/test/io/ktor/tests/server/features/HttpsRedirectFeatureTest.kt @@ -83,4 +83,24 @@ class HttpsRedirectFeatureTest { } } } + + @Test + fun testRedirectHttpsExemption() { + withTestApplication { + application.install(HttpsRedirect) { + exemptions = listOf("/exempted") + } + application.intercept(ApplicationCallPipeline.Fallback) { + call.respond("ok") + } + + handleRequest(HttpMethod.Get, "/nonexempted").let { call -> + assertEquals(HttpStatusCode.MovedPermanently, call.response.status()) + } + + handleRequest(HttpMethod.Get, "/exempted/path").let { call -> + assertEquals(HttpStatusCode.OK, call.response.status()) + } + } + } }