Send Content-Length if required

This commit is contained in:
Jonas Lochmann 2023-02-13 01:00:00 +01:00
parent 80b58e134d
commit dac0ce74fe
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
3 changed files with 78 additions and 11 deletions

View file

@ -1,5 +1,5 @@
/*
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@ val httpClient: OkHttpClient by lazy {
if (BuildConfig.DEBUG) {
builder.addInterceptor (HttpLoggingInterceptor {
Log.d("HttpClient", it)
})
}.apply { level = HttpLoggingInterceptor.Level.HEADERS })
}
builder.build()

View file

@ -23,12 +23,15 @@ import io.timelimit.android.async.Threads
import io.timelimit.android.coroutines.executeAndWait
import io.timelimit.android.coroutines.waitForResponse
import io.timelimit.android.sync.network.*
import io.timelimit.android.util.okio.LengthSink
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import okhttp3.internal.closeQuietly
import okio.BufferedSink
import okio.GzipSink
import okio.Sink
import okio.buffer
import java.io.OutputStreamWriter
@ -63,9 +66,11 @@ class HttpServerApi(private val endpointWithoutSlashAtEnd: String): ServerApi {
private val JSON = "application/json; charset=utf-8".toMediaTypeOrNull()
private fun createJsonRequestBody(serialize: (writer: JsonWriter) -> Unit) = object: RequestBody() {
override fun contentType() = JSON
override fun writeTo(sink: BufferedSink) {
private fun createJsonRequestBody(
serialize: (writer: JsonWriter) -> Unit,
measureContentLength: Boolean
): RequestBody {
fun write(sink: Sink) {
val writer = JsonWriter(
OutputStreamWriter(
GzipSink(sink)
@ -75,11 +80,22 @@ class HttpServerApi(private val endpointWithoutSlashAtEnd: String): ServerApi {
serialize(writer)
writer.flush()
writer.close()
}
val length =
if (measureContentLength) LengthSink().also { write(it) }.length
else null
return object: RequestBody() {
override fun contentType() = JSON
override fun writeTo(sink: BufferedSink) = write(sink)
override fun contentLength(): Long = length ?: -1
}
}
}
private var sendContentLength = false
override suspend fun getTimeInMillis(): Long {
httpClient.newCall(
@ -595,10 +611,30 @@ class HttpServerApi(private val endpointWithoutSlashAtEnd: String): ServerApi {
path: String,
requestBody: (writer: JsonWriter) -> Unit
): Response {
if (!sendContentLength) {
val response = postJsonRequest(path, requestBody, transmitContentLength = false)
if (response.code != 411) return response
Threads.network.executeAndWait { response.closeQuietly() }
sendContentLength = true
}
return postJsonRequest(path, requestBody, transmitContentLength = true)
}
private suspend fun postJsonRequest(
path: String,
requestBody: (writer: JsonWriter) -> Unit,
transmitContentLength: Boolean
): Response {
val body = createJsonRequestBody(requestBody, transmitContentLength)
return httpClient.newCall(
Request.Builder()
.url("$endpointWithoutSlashAtEnd/$path")
.post(createJsonRequestBody(requestBody))
.post(body)
.header("Content-Encoding", "gzip")
.build()
).waitForResponse()

View file

@ -0,0 +1,31 @@
/*
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.timelimit.android.util.okio
import okio.Buffer
import okio.Sink
import okio.Timeout
class LengthSink: Sink {
private var lengthInternal = 0L
val length get() = lengthInternal
override fun write(source: Buffer, byteCount: Long) { lengthInternal += byteCount }
override fun timeout(): Timeout = Timeout.NONE
override fun flush() = Unit
override fun close() = Unit
}