Posting this here as at the moment I'm not really sure if that's my issue with OkHTTP or Google Cloud Storage, but hopefully someone might be able to help.
The problem seems to happen only under quite specific conditions but I can recreate it every time. This is what I'm doing:
1) Starting a file upload on 3G network 2) Midway the upload, switching to WiFi
With the switch, the upload fails with a 400 code. Often if that's a large file, it will continue to upload it for a while, then fail with 400 at the very end. Each time I then attempt to get an upload range to resume the upload by sending a PUT request with the empty body and the hander containing Content-Range of * / fileSize (as documented here), instead of getting 308 with the range, I get a 400 again. The message inside the response doesn't seem to be making it back to my code (possibly an issue with OkHTTP stripping it out?) but if recreated in Postman, I'm getting the following:
Invalid request. There were 253001817 byte(s) in the request body. There should have been 264855641 byte(s) (starting at offset 0 and ending at offset 264855640) according to the Content-Range header.
This should not happen - I should get a 308 response with range inside a header.
Couple of things to note:
1) In general my resumable uploads work fine. I can pause an upload, go offline, resume the upload - that all works fine. It just can't cope with the scenario above. 2) This doesn't seem to be an issue on iOS (uploading to the same Google Cloud Storage) which makes me think that something breaks with OkHTTP? I'm not really sure how OkHTTP handles a 3G-to-WiFi switch.
Any thoughts appreciated.
Posting this here as at the moment I'm not really sure if that's my issue with OkHTTP or Google Cloud Storage, but hopefully someone might be able to help.
The problem seems to happen only under quite specific conditions but I can recreate it every time. This is what I'm doing:
1) Starting a file upload on 3G network 2) Midway the upload, switching to WiFi
With the switch, the upload fails with a 400 code. Often if that's a large file, it will continue to upload it for a while, then fail with 400 at the very end. Each time I then attempt to get an upload range to resume the upload by sending a PUT request with the empty body and the hander containing Content-Range of * / fileSize (as documented here), instead of getting 308 with the range, I get a 400 again. The message inside the response doesn't seem to be making it back to my code (possibly an issue with OkHTTP stripping it out?) but if recreated in Postman, I'm getting the following:
Invalid request. There were 253001817 byte(s) in the request body. There should have been 264855641 byte(s) (starting at offset 0 and ending at offset 264855640) according to the Content-Range header.
This should not happen - I should get a 308 response with range inside a header.
Couple of things to note:
1) In general my resumable uploads work fine. I can pause an upload, go offline, resume the upload - that all works fine. It just can't cope with the scenario above. 2) This doesn't seem to be an issue on iOS (uploading to the same Google Cloud Storage) which makes me think that something breaks with OkHTTP? I'm not really sure how OkHTTP handles a 3G-to-WiFi switch.
EDIT:
I think the failure always comes at when the written size reaches fileSize - numberOfBytes uploaded on 3G network So, for example if my file is 10mb, I uploaded 1mb on 3g then switched to WiFi, the upload will fail at 9mb.
Also I noticed that on switching to WiFi, OkHTTP is not issuing a new request, however public void writeTo(BufferedSink sink) gets called again. My implementation of writeTo looks like this:
@Override
public void writeTo(BufferedSink sink) throws IOException {
// Move to the first unsent byte
source.skip(uploadedBytes);
byte[] buffer = new byte[8 * 1024];
int count = 0;
while ((count = source.read(buffer)) != -1) {
sink.write(buffer, 0, count);
uploadedBytes += count;
}
}