https://kotlinlang.org logo
Title
t

Thomas

02/18/2020, 8:45 PM
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?
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

e5l

03/19/2020, 1:34 PM
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

Thomas

03/19/2020, 2:20 PM
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.
clientConfig.install("HttpsToHttp") {
    feature(HttpSend)!!.intercept { origin, context ->
        // the code below is not even reached.
        try {
            execute(context)
        } catch (throwable: Throwable) {
            TODO()
        }
    }
}
e

e5l

03/19/2020, 2:29 PM
could you share the stacktrace?
t

Thomas

03/19/2020, 2:30 PM
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

e5l

03/19/2020, 2:31 PM
But it should. Could you try to catch the exception in the
receivePipeline
? You can find it in
client.receivePipeline
t

Thomas

03/19/2020, 2:45 PM
Do you mean like this?
clientConfig.install("HttpsToHttp") {
    receivePipeline.intercept(HttpReceivePipeline.Before) {
        TODO()
    }
}
The
TODO()
is not reached here either, the ssl exception is still thrown like before
e

e5l

03/19/2020, 2:50 PM
nope, I mean intercept both independently
receivePipeline.intercept(HttpReceivePipeline.Before) {
        try {
            proceedWith(it)
        } catch(cause: Throwable) {
        }
    }
}
t

Thomas

03/19/2020, 2:59 PM
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

e5l

03/19/2020, 3:00 PM
Exactly
t

Thomas

03/19/2020, 3:02 PM
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

e5l

03/20/2020, 6:43 AM
Trying to figure it out.
It turns out that you can catch the exception in
sendPipeline
Before phase
sendPipeline.intercept(HttpReceivePipeline.Before) {
        try {
            proceedWith(it)
        } catch(cause: Throwable) {
        }
    }
}
t

Thomas

03/20/2020, 4:43 PM
@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

e5l

03/20/2020, 7:13 PM
Nope, but you can store the flag outside sendPipeline interceptor and check it in send feature interceptor
t

Thomas

03/21/2020, 6:51 PM
I tried the following but it throws an IllegalStateException with error message check failed.
Hi @e5l, do you know why the above fails with IllegalStateException?