@@ -7,6 +7,7 @@ import io.ktor.http.HttpMethod
77import io.ktor.http.HttpStatusCode
88import io.ktor.serialization.kotlinx.json.json
99import io.ktor.server.application.Application
10+ import io.ktor.server.application.ApplicationCall
1011import io.ktor.server.application.install
1112import io.ktor.server.plugins.calllogging.CallLogging
1213import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
@@ -17,6 +18,7 @@ import io.ktor.server.plugins.statuspages.StatusPages
1718import io.ktor.server.request.path
1819import io.ktor.server.response.respond
1920import io.ktor.server.websocket.WebSockets
21+ import io.ktor.util.AttributeKey
2022import kotlinx.serialization.json.Json
2123import org.slf4j.LoggerFactory
2224import kotlin.time.Duration.Companion.minutes
@@ -30,6 +32,7 @@ private const val PROXY_STORYBOARD_RATE_LIMIT = 1200
3032private const val USER_DATA_RATE_LIMIT = 120
3133private const val MAX_WEBSOCKET_FRAME_BYTES = 64L * 1024L * 1024L
3234private val RATE_LIMIT_WINDOW = 1 .minutes
35+ private val preserveTooManyRequestsBodyAttribute = AttributeKey <Unit >(" preserveTooManyRequestsBody" )
3336
3437val EXTRACTION_ZONE = RateLimitName (" extraction" )
3538val DEARROW_ZONE = RateLimitName (" dearrow" )
@@ -40,7 +43,6 @@ val PROXY_STORYBOARD_ZONE = RateLimitName("proxy-storyboard")
4043val USER_DATA_ZONE = RateLimitName (" user-data" )
4144
4245fun Application.configurePlugins (authService : AuthService ) {
43- val log = LoggerFactory .getLogger(" RequestLogger" )
4446 installRequestObservability()
4547 install(CallLogging ) {
4648 format(::requestLogLine)
@@ -94,8 +96,18 @@ fun Application.configurePlugins(authService: AuthService) {
9496 requestKey { call -> userDataRateLimitKey(call, authService) }
9597 }
9698 }
99+ configureStatusPages()
100+ }
101+
102+ internal fun ApplicationCall.preserveTooManyRequestsBody () {
103+ attributes.put(preserveTooManyRequestsBodyAttribute, Unit )
104+ }
105+
106+ internal fun Application.configureStatusPages () {
107+ val log = LoggerFactory .getLogger(" RequestLogger" )
97108 install(StatusPages ) {
98109 status(HttpStatusCode .TooManyRequests ) { call, status ->
110+ if (call.attributes.contains(preserveTooManyRequestsBodyAttribute)) return @status
99111 if (! call.response.headers.contains(HttpHeaders .RetryAfter )) call.response.headers.append(HttpHeaders .RetryAfter , " 60" )
100112 call.respond(status, ErrorResponse (" Too many requests" , " rate_limited" ))
101113 }
0 commit comments