その名の通りに、KtorでHTTPでのリクエストを弾くFeatureをシンプルに実装します。
REST API とかだとHTTPへのリクエストをHTTPSにリダイレクトさせるよりはエラーを吐かせたほうが良い気がしました。
Featureとは
Ktorアプリケーションを構成する一連の機能の事で基本的にはリクエストとレスポンスのパイプラインに組み込まれるものです。
Webアプリを作る上で欠かせない主要な機能であるルーティングもそのFeature
の一つとして定義されています。
Feature
を定義するためには、そのFeature
を表すクラスと、それを組み立てるために必要な情報を詰めるクラス、ApplicationFeature
を継承したcompanion object
が必要です。(別にcompanion object
じゃなくても動くけど公式のFeature達に倣う)
今回はHTTPでのリクエストを弾いてしまうFeature
を作るのでHttpsOnly
って名前にしたいと思います。
HttpsOnly
のざっくりした機能
とにかくシンプルにHttpでのリクエストを拒否したいだけなので要件は2つだけです。
- Httpでのリクエストを受け取った際に
HttpStatusCode:403
を返す。 - Httpでのリクエストを受け取った際に、任意の型のレスポンスボディを返す。
コード
解説はコード内コメントで行います。
//Httpでのリクエストを拒否するためのFeature
class HttpsOnly(configuration: Configuration) {
//Httpでのリクエストが有った際に返すレスポンスのボディ
val response = configuration.responseObject
//HttpsOnlyを組み立てるための設定
class Configuration {
//Httpでのリクエストが有った際に返すレスポンスのボディ
var responseObject: Any = "https only"
}
companion object Feature : ApplicationFeature<ApplicationCallPipeline, Configuration, HttpsOnly> {
//Featureを一意に表すキー
override val key: AttributeKey<HttpsOnly> = AttributeKey("HttpsOnly")
//Featureのインストールを行う関数
override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): HttpsOnly {
//configureを元にHttpsOnlyを組み立て
val feature = HttpsOnly(Configuration().apply(configure))
/*
ApplicationCallPipelineに、リクエストがHttpではないかをチェックして
そうだったときにHttpStatusCode 403とHttpsOnly#responseを返す処理を挟む
*/
pipeline.intercept(ApplicationCallPipeline.Features) {
if (call.request.origin.scheme != "http") return@intercept
call.respond(HttpStatusCode.Forbidden, feature.response)
finish()
}
return feature
}
}
}
実際に使う際には
fun Application.installHttpsOnly() = install(HttpsOnly) {
responseObject = ErrorResponse(
statusCode = HttpStatusCode.Forbidden.value,
reason = "sslRequired",
message = "SSL is required for requests to this server"
)
}
のようにしてやればHttpでのリクエストを受け取った際にエラーレスポンスを任意のオブジェクトをレスポンスボディにして返してやることが出来ます。
ktor-jackson
等と組み合わせればJSONを返すことも可能です。
間違ったことや、おかしな点があればご指摘して頂けれると嬉しいです。
参考
https://ktor.io/servers/features.html
https://ktor.io/advanced/pipeline.html
https://ktor.io/servers/lifecycle.html
https://github.com/ktorio/ktor/blob/43eef9ed31ba33137501820a1b292af946ede6f8/ktor-server/ktor-server-core/jvm/src/io/ktor/features/DefaultHeaders.kt