0

I have a progress emitting request body..

class ProgressEmittingRequestBody(
    private val delegate: RequestBody,
    private val progressListener: ProgressListener,
) : RequestBody() {
    override fun contentType(): MediaType? = delegate.contentType()

    override fun contentLength(): Long {
        try {
            return delegate.contentLength()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return -1
    }

    override fun writeTo(sink: BufferedSink) {
        val bufferedSink = CountingSink(sink).buffer()
        delegate.writeTo(bufferedSink)
        bufferedSink.flush()
    }

    private inner class CountingSink(
        delegate: Sink
    ) : ForwardingSink(delegate) {
        var bytesWritten = 0L
        override fun write(source: Buffer, byteCount: Long) {
            super.write(source, byteCount)
            bytesWritten += byteCount
            progressListener.onProgressUpdate(bytesWritten, contentLength())
        }

    }

}

But when I try to upload large files.. sometimes.. the following out of memory exception is thrown..

Exception

The custom http logging interceptor I am using is..

      if (!logBody || requestBody == null) {
                logger.log("--> END ${request.method}")
            } else if (bodyHasUnknownEncoding(request.headers)) {
                logger.log("--> END ${request.method} (encoded body omitted)")
            } else if (requestBody.isDuplex()) {
                logger.log("--> END ${request.method} (duplex request body omitted)")
            } else if (requestBody.isOneShot()) {
                logger.log("--> END ${request.method} (one-shot body omitted)")
            } else {
                if (requestBody.contentLength() == -1L) {
                    logger.log("Unknown content length.")
                } else if (requestBody.contentLength() > 1024L * 1024) {
                    logger.log("Request body size exceeded ${1024 * 1024} bytes. Cannot log the request body.") //So that large source are not buffered.. Main change over here..
                } else {
                    var buffer = Buffer()
                    requestBody.writeTo(buffer)

                    var gzippedLength: Long? = null
                    if ("gzip".equals(headers["Content-Encoding"], ignoreCase = true)) {
                        gzippedLength = buffer.size
                        GzipSource(buffer).use { gzippedResponseBody ->
                            buffer = Buffer()
                            buffer.writeAll(gzippedResponseBody)
                        }
                    }

                    val charset: Charset = requestBody.contentType().charset()

                    logger.log("")
                    if (!buffer.isProbablyUtf8()) {
                        logger.log(
                            "--> END ${request.method} (binary ${requestBody.contentLength()}-byte body omitted)"
                        )
                    } else if (gzippedLength != null) {
                        logger.log("--> END ${request.method} (${buffer.size}-byte, $gzippedLength-gzipped-byte body)")
                    } else {
                        logger.log(buffer.readString(charset))

                        logger.log("--> END ${request.method} (${requestBody.contentLength()}-byte body)")
                    }
                }
            }

If the out of memory exception was always happening, I would have trace the error.. But OOM is thrown for about 1 in 5 uploads and I am not able to track the error..

What am I doing wrong?

Diken Mhrz
  • 327
  • 2
  • 14

0 Answers0