Ktor Native (iOS) questions: We are using a precon...
# ktor
m
Ktor Native (iOS) questions: We are using a preconfigured URLSession to do background downloads on iOS. We configure it that way:
Copy code
private val sessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfiguration(identifier)
    private val ktorDelegate = KtorNSURLSessionDelegate()
    private val session = NSURLSession.sessionWithConfiguration(
        sessionConfiguration,
        ktorDelegate,
        delegateQueue = null
    )

    protected val httpClient = HttpClient(Darwin) {
        engine {
            usePreconfiguredSession(session, ktorDelegate)
        }
        expectSuccess = true
    }
Everything works fine as long as requests succeed. If a request returns for example a 404 response, a simple
httpClient.get(<RequestWithURLThatReturns404>)
simply never returns Changing sessionConfiguration to
private val sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration
fixes the problem Question 1: Anyone has ever encountered this problem and come up with a solution Question 2: I would like to contribute a fix if it’s not the case, any pointers on where I could start in the ktor code base
I did build my own SessionDelegate to make sure the URLSession was calling back in
didReceiveData
and
didCompleteWithError
a
What version of Ktor do you use?
m
2.3.3
a
Unfortunately, I cannot reproduce your problem on MacosX64 target with the following code:
Copy code
val sessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfiguration("identifier")
val ktorDelegate = KtorNSURLSessionDelegate()
val session = NSURLSession.sessionWithConfiguration(
    sessionConfiguration,
    ktorDelegate,
    delegateQueue = null
)

val httpClient = HttpClient(Darwin) {
    engine {
        usePreconfiguredSession(session, ktorDelegate)
    }
    expectSuccess = true
}

@OptIn(DelicateCoroutinesApi::class)
fun main() {
    val job = GlobalScope.launch {
        httpClient.get("<https://example.com/404>")
    }
    while (job.isActive) {}
}
Is it only reproducible on iOS? Can you file an issue with a minimal sample project attached?
ł
@Marc Lefrancois I am just dealing with background downloads on iOS. Does “Everything works fine” mean that the downloads are processed even when the app is minimized (as described in https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background)? I couldn’t make it so with similar config.
I can confirm that requesting non-existing url on Android gets 404 error page and on iOS it hangs indefinetly also with this multiplatform config
Copy code
val client = HttpClient() {
    install(Logging) {
        level = LogLevel.BODY
    }
    install(ContentNegotiation) {
        json()
    }
    install(HttpTimeout) {
        requestTimeoutMillis = 20000L
        connectTimeoutMillis = 20000L
        socketTimeoutMillis = 20000L
    }
}
m
@Łukasz Zieliński I think you are missing an important part:
expectSuccess = true
that should threat 404 response has errors for the flow ? As for my problem @Aleksei Tirman [JB] I can now confirm that it was a setup problem on our side combine with an unexpected (bug?) behaviour of
backgroundSessionConfiguration
. I’ll try to explain clearly, do not hesitate if it is not clear enough I was by error using 2
backgroundSessionConfiguration()
with the same
identifier
in 2 different instance of
HttpClient
. So 2
URLSession
instances , with 2
KtorNSURLSessionDelegate
instances. 1. When the requests are successful, no problems. 2. When the requests have an error status code (like 404). The following happened using the second HttpClient: a. When the request is initiated,
read
is called on the right
KtorDelegate
instance b. When the urlSession calls back to the delegate for
didReceiveData
and
didCompleteWithError
it does so on the other
KtorDelegate
instance. So there is no
NSURLSessionTask
in the
taskHandlers
map and the flow never emits anything.
This leads u to believe that calling
NSURLSessionConfiguration.backgroundSessionConfiguration
returns shared configuration per identifier and that there is a mechanism to handle the multiple delegates
But there might be a bug in the multiple delegate handling for in error requests in Apple’s code
This is the farthest we went in our investigation since having different identifiers for each background configuration fixed the problem for us