Repository: ktorio/ktor
File: ktor-client/ktor-client-core/common/src/io/ktor/client/plugins/HttpRedirect.kt (Kotlin)

Code before:
public val HttpRedirect: ClientPlugin<HttpRedirectConfig> = createClientPlugin(
    "HttpRedirect",
    ::HttpRedirectConfig
) {

    val checkHttpMethod: Boolean = pluginConfig.checkHttpMethod
    val allowHttpsDowngrade: Boolean = pluginConfig.allowHttpsDowngrade

    suspend fun Send.Sender.handleCall(
        context: HttpRequestBuilder,
        origin: HttpClientCall,
        allowHttpsDowngrade: Boolean,
        client: HttpClient
    ): HttpClientCall {
        var call = origin
        var requestBuilder = context
        val originProtocol = origin.request.url.protocol
        val originAuthority = origin.request.url.authority

        while (true) {
            if (!call.response.status.isRedirect()) return call

            val location = call.response.headers[HttpHeaders.Location]

            if (location == null) {
                LOGGER.trace("Received redirect response with no location header for request ${context.url}")
                return call
            }

            client.monitor.raise(HttpResponseRedirectEvent, call.response)
            LOGGER.trace("Received redirect response to $location for request ${context.url}")

            requestBuilder = HttpRequestBuilder().apply {
                takeFromWithExecutionContext(requestBuilder)
                url.parameters.clear()
                url.takeFrom(location)

                /**
                 * Disallow redirect with a security downgrade.
                 */
                if (!allowHttpsDowngrade && originProtocol.isSecure() && !url.protocol.isSecure()) {
                    LOGGER.trace("Can not redirect ${context.url} because of security downgrade")
                    return call
                }

                if (originAuthority != url.authority) {
                    headers.remove(HttpHeaders.Authorization)
                    LOGGER.trace("Removing Authorization header from redirect for ${context.url}")
                }
            }


Review comment (suggestion):
I think it would be useful to upgrade this to a WARN and to include info on how we handle it:

```
Location header missing from redirect response ${context.url}; returning response as is
```

Code after:
public val HttpRedirect: ClientPlugin<HttpRedirectConfig> = createClientPlugin(
    "HttpRedirect",
    ::HttpRedirectConfig
) {

    val checkHttpMethod: Boolean = pluginConfig.checkHttpMethod
    val allowHttpsDowngrade: Boolean = pluginConfig.allowHttpsDowngrade

    suspend fun Send.Sender.handleCall(
        context: HttpRequestBuilder,
        origin: HttpClientCall,
        allowHttpsDowngrade: Boolean,
        client: HttpClient
    ): HttpClientCall {
        var call = origin
        var requestBuilder = context

        while (true) {
            // Protocol/authority of the current hop
            val previousProtocol = call.request.url.protocol
            val previousAuthority = call.request.url.authority
            if (!call.response.status.isRedirect()) return call

            val location = call.response.headers[HttpHeaders.Location]

            if (location == null) {
                LOGGER.warn(
                    "Location header missing from redirect response ${call.request.url}; returning response as is"
                )
                return call
            }

            client.monitor.raise(HttpResponseRedirectEvent, call.response)
            LOGGER.trace("Received redirect response to $location for request ${call.request.url}")

            requestBuilder = HttpRequestBuilder().apply {
                takeFromWithExecutionContext(requestBuilder)
                url.parameters.clear()
                url.takeFrom(location)

                /**
                 * Disallow redirect with a security downgrade.
                 */
                if (!allowHttpsDowngrade && previousProtocol.isSecure() && !url.protocol.isSecure()) {
                    LOGGER.trace("Blocked redirect from ${call.request.url} to $location due to HTTPS downgrade")
                    return call
                }

                if (previousAuthority != url.authority) {
                    headers.remove(HttpHeaders.Authorization)
                    LOGGER.trace(