Search code examples
javakotlinrequestmultipart

java.lang.ArrayIndexOutOfBoundsException: size=2048 offset=0 byteCount=-1


Why I will get this exception in writeTo function?

2019-07-02 12:17:03.525 13663-14248/com.zoinla.pegasus_work E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher Process: com.xxx, PID: 13663 java.lang.ArrayIndexOutOfBoundsException: size=2048 offset=0 byteCount=-1 at okio.Util.checkOffsetAndCount(Util.java:30) at okio.Buffer.write(Buffer.java:1096) at okio.Buffer.write(Buffer.java:54) at com.xxx.ProgressRequestBody.writeTo(ProgressRequestBody.kt:33) at okhttp3.MultipartBody.writeOrCountBytes(MultipartBody.java:173) at okhttp3.MultipartBody.writeTo(MultipartBody.java:114) at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:202)

ProgressRequestBody

open class ProgressRequestBody(val file: File, val listener: UploadCallbacks) : RequestBody() {
    override fun contentType(): MediaType? {
        return MediaType.parse("$content_type/")
    }

    override fun writeTo(sink: BufferedSink) {
        val fileLength = file?.length()
        val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
        val `in` = FileInputStream(file)
        var uploaded: Long = 0

        try {
            var read: Int
            val handler = Handler(Looper.getMainLooper())

            do {
                read = `in`.read(buffer)
                handler.post(ProgressUpdater(uploaded, fileLength!!))

                uploaded += read.toLong()
                sink.write(buffer, 0, read)

                if (read == -1) {
                    break
                }

            } while (true)
        } finally {
            `in`.close()
        }
    }

    override fun contentLength(): Long {
        return file.length()
    }

    val content_type = ""

    companion object {

        val DEFAULT_BUFFER_SIZE = 2048

    }

    private inner class ProgressUpdater(private val mUploaded: Long, private val mTotal: Long) : Runnable {

        override fun run() {
            listener?.onProgressUpdate((100 * mUploaded / mTotal).toInt())
        }
    }

    interface UploadCallbacks {
        fun onProgressUpdate(percentage: Int)
        fun onError()
        fun onFinish()
    }
}

It pointed to this line

sink.write(buffer, 0, read)

Solution

  • Yes, this will happen when read == -1. You should test it before you use it:

            do {
                read = `in`.read(buffer)
                handler.post(ProgressUpdater(uploaded, fileLength!!))
    
                if (read == -1) {
                    break
                }
    
                uploaded += read.toLong()
                sink.write(buffer, 0, read)
    
            } while (true)
    

    Or perhaps:

            do {
                read = `in`.read(buffer)
    
                if (read == -1) {
                    break
                }
    
                uploaded += read.toLong()
                sink.write(buffer, 0, read)
                handler.post(ProgressUpdater(uploaded, fileLength!!))
    
            } while (true)