Increase read timeout.
When range interceptor modifies request it also increases read timeout, that allows server to do transcoding of the response and skip bytes to offset value. Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
This commit is contained in:
parent
72333f245f
commit
c8c8766b55
|
@ -32,4 +32,4 @@ abstract class BaseInterceptorTest {
|
|||
.url(mockWebServerRule.mockWebServer.url("/"))
|
||||
.also { additionalParams(it) }
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class RangeHeaderInterceptorTest : BaseInterceptorTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `Should not add range header if request doens't contain it`() {
|
||||
fun `Should not add range header if request doesnt contain it`() {
|
||||
mockWebServerRule.mockWebServer.enqueue(MockResponse())
|
||||
val request = createRequest { }
|
||||
|
||||
|
@ -56,4 +56,4 @@ class RangeHeaderInterceptorTest : BaseInterceptorTest() {
|
|||
executedRequest.headers.names() `should contain` "Range"
|
||||
executedRequest.headers["Range"]!! `should equal to` "bytes=$offset-"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,17 @@ package org.moire.ultrasonic.api.subsonic.interceptors
|
|||
import okhttp3.Interceptor
|
||||
import okhttp3.Interceptor.Chain
|
||||
import okhttp3.Response
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
|
||||
internal const val SOCKET_READ_TIMEOUT_DOWNLOAD = 30 * 1000
|
||||
// Allow 20 seconds extra timeout pear MB offset.
|
||||
internal const val TIMEOUT_MILLIS_PER_OFFSET_BYTE = 0.02
|
||||
|
||||
/**
|
||||
* Modifies request "Range" header to be according to HTTP standard.
|
||||
*
|
||||
* Also increases read timeout to allow server to transcode response and offset it.
|
||||
*
|
||||
* See [range rfc](https://tools.ietf.org/html/rfc7233).
|
||||
*/
|
||||
internal class RangeHeaderInterceptor : Interceptor {
|
||||
|
@ -14,12 +21,21 @@ internal class RangeHeaderInterceptor : Interceptor {
|
|||
val originalRequest = chain.request()
|
||||
val headers = originalRequest.headers()
|
||||
return if (headers.names().contains("Range")) {
|
||||
val offset = "bytes=${headers["Range"]}-"
|
||||
chain.proceed(originalRequest.newBuilder()
|
||||
val offsetValue = headers["Range"] ?: "0"
|
||||
val offset = "bytes=$offsetValue-"
|
||||
chain.withReadTimeout(getReadTimeout(offsetValue.toInt()), MILLISECONDS)
|
||||
.proceed(originalRequest.newBuilder()
|
||||
.removeHeader("Range").addHeader("Range", offset)
|
||||
.build())
|
||||
} else {
|
||||
chain.proceed(originalRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set socket read timeout. Note: The timeout increases as the offset gets larger. This is
|
||||
// to avoid the thrashing effect seen when offset is combined with transcoding/downsampling
|
||||
// on the server. In that case, the server uses a long time before sending any data,
|
||||
// causing the client to time out.
|
||||
private fun getReadTimeout(offset: Int)
|
||||
= (SOCKET_READ_TIMEOUT_DOWNLOAD + offset * TIMEOUT_MILLIS_PER_OFFSET_BYTE).toInt()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue