https://kotlinlang.org logo
#ktor
Title
# ktor
a

Andrew Steinmetz

07/28/2022, 4:50 PM
Does anybody happen to know what the syntax is to grab the request information from a request already made in the
HttpReceivePipeline.After
to be able update this old plugin to Ktor 2.0? Looking at the old and new versions of Ktor, it looks as if
context.request
is no longer accessible since the type on the receive pipeline is now Unit instead of
HttpClientCall
?
Copy code
class OAuthFeature(
    private val getToken: suspend () -> String,
    private val refreshToken: suspend () -> Unit
) {
    @KtorDsl
    public class Config {
        lateinit var getToken: suspend () -> String
        lateinit var refreshToken: suspend () -> Unit
    }

    public companion object Feature : HttpClientPlugin<Config, OAuthFeature> {
        override val key: AttributeKey<OAuthFeature> = AttributeKey("OAuth")

        override fun prepare(block: Config.() -> Unit): OAuthFeature {
            val config = Config().apply(block)
            return OAuthFeature(config.getToken, config.refreshToken)
        }

        private val RefreshKey = "Ktor-OAuth-Refresh"

        override fun install(plugin: OAuthFeature, scope: HttpClient) {
            scope.requestPipeline.intercept(HttpRequestPipeline.State) {
                // Add Refresh Header for handling infinite loop on 401s
                context.headers[RefreshKey] = context.headers.contains("Authorization").toString()

                // Add Authorization Header
                val token = plugin.getToken()
                Napier.d("Token: $token")
                context.headers["Authorization"] = "Bearer $token"

                proceed()
            }
            scope.receivePipeline.intercept(HttpReceivePipeline.After) {
                // Request is unauthorized
                if (subject.status == HttpStatusCode.Unauthorized && it.headers[RefreshKey] != true.toString()) {
                    try {
                        // Refresh the Token
                        plugin.refreshToken()

                        // Retry the request
                        val call = scope.requestPipeline.execute(
                            HttpRequestBuilder().takeFrom(context.request), // this is where request is no longer accessible
                            EmptyContent
                        ) as HttpClientCall

                        // Proceed with the new request
                        proceedWith(call.response)

                        return@intercept
                    } catch (exception: Exception) {
                        // If refresh fails, proceed as 401
                    }
                }
                // Proceed as normal request
                proceedWith(subject)
            }
        }
    }
}
Actually I think I found the answer, is it?
Copy code
HttpRequestBuilder().takeFrom(subject.call.request)
a

Aleksei Tirman [JB]

07/29/2022, 7:01 AM
Yes.
HttpRequestBuilder().takeFrom(it.call.request)
works too.
5 Views