I would like to retry HTTPS requests with HTTP req...
# ktor
t
I would like to retry HTTPS requests with HTTP requests if there is a
ConnectException
. Is the code below correct or is there a better way to do this?
Copy code
client.install("HttpsToHttp") {
    requestPipeline.intercept(HttpRequestPipeline.Before) {
        val requestBuilder = this.context
        try {
            proceedWith(it)
        } catch (exception: ConnectException) {
            if (requestBuilder.url.protocol == URLProtocol.HTTPS) {
                requestBuilder.url.protocol = URLProtocol.HTTP
                proceedWith(requestPipeline.execute(requestBuilder, it)) // not sure if this is correct
            } else {
                throw exception
            }
        }
    }
}
e
Hi @Thomas, sorry for the delay. It doesn't look right for me. Probably you can grab idea from the
HttpRedirect
feature: https://github.com/ktorio/ktor/blob/b66e3072865de0bff9e6514a5d19cfc404985156/ktor-client/ktor-client-core/common/src/io/ktor/client/features/HttpRedirect.kt#L86
t
Hi @e5l, thanks for the link. I tried to create a HttpSend interceptor like below, but the code does not appear to be reached. I think the ssl exception is thrown earlier.
Copy code
clientConfig.install("HttpsToHttp") {
    feature(HttpSend)!!.intercept { origin, context ->
        // the code below is not even reached.
        try {
            execute(context)
        } catch (throwable: Throwable) {
            TODO()
        }
    }
}
e
could you share the stacktrace?
t
Here is the exception. Looks like it is thrown here: https://github.com/ktorio/ktor/blob/b66e3072865de0bff9e6514a5d19cfc404985156/ktor-client/ktor-client-core/common/src/io/ktor/client/features/HttpSend.kt#L79 So that means it does not reach the interceptors a few lines lower in HttpSend.
e
But it should. Could you try to catch the exception in the
receivePipeline
? You can find it in
client.receivePipeline
t
Do you mean like this?
Copy code
clientConfig.install("HttpsToHttp") {
    receivePipeline.intercept(HttpReceivePipeline.Before) {
        TODO()
    }
}
The
TODO()
is not reached here either, the ssl exception is still thrown like before
e
nope, I mean intercept both independently
Copy code
receivePipeline.intercept(HttpReceivePipeline.Before) {
        try {
            proceedWith(it)
        } catch(cause: Throwable) {
        }
    }
}
t
If I add your code then I can still not catch the exception. I don’t understand what you mean by intercepting both independently. Do you mean I need to intercept HttpSend like before and add the code in your comment using the receivePipeline as well?
e
Exactly
t
So like this?
None of them catches the ssl exception in the catch block where I added the TODO
The ssl exception is thrown here (see stack trace in comments above) so how could it ever reach the interceptors that are called a few lines lower?
e
Trying to figure it out.
It turns out that you can catch the exception in
sendPipeline
Before phase
Copy code
sendPipeline.intercept(HttpReceivePipeline.Before) {
        try {
            proceedWith(it)
        } catch(cause: Throwable) {
        }
    }
}
t
@e5l that is great! I can confirm it catches the exception. Do you know how to retry the request (after modifying it) in the catch block?
I don’t think it is possible to call proceedWith a second time. Is there a way to retry the request?
e
Nope, but you can store the flag outside sendPipeline interceptor and check it in send feature interceptor
t
I tried the following but it throws an IllegalStateException with error message check failed.
Untitled.kt
Untitled
Hi @e5l, do you know why the above fails with IllegalStateException?