I am trying to create a resumable upload session using drive rest API in Android.
As per the documentation the 3 steps needed to be followed are
- Start a resumable session
- Save the resumable session URI
- Upload the file
Step 1 : I use the following code to start the resumable session.
File body = new File();
body.setName(fileName);
body.setMimeType(mimeType);
body.setCreatedTime(modifiedDate);
body.setModifiedTime(modifiedDate);
body.setParents(Collections.singletonList(parentId));
HttpHeaders header = new HttpHeaders();
header.setContentLength(0L);
header.setContentType("application/json; charset=UTF-8");
header.set("X-Upload-Content-Type","image/jpeg");
HttpResponse response= driveObject
.files()
.create(body)
.setRequestHeaders(header)
.set("uploadType","resumable")
.buildHttpRequest()
.execute();
Step 2: Once the execution is complete, I'm printing the response header of the request to see the Location URI
System.out.println(response.getHeader().toString());
The output is as follows
{
cache-control=[no-cache, no-store, max-age=0, must-revalidate],
content-encoding=[gzip],
content-type=[application/json; charset=UTF-8],
date=[Thu, 06 Oct 2016 02:20:18 GMT],
expires=[Mon, 01 Jan 1990 00:00:00 GMT],
alt-svc=[quic=":443"; ma=2592000; v="36,35,34,33,32"],
pragma=[no-cache],
server=[GSE],
transfer-encoding=[chunked],
vary=[Origin, X-Origin],
x-android-received-millis=[1475720421761],
x-android-response-source=[NETWORK 200],
x-android-sent-millis=[1475720420804],
x-content-type-options=[nosniff],
x-frame-options=[SAMEORIGIN],
x-xss-protection=[1; mode=block]
}
I don't find the Location URI in the response header to start uploading filedata as specified in the documentation nor I find any Java samples to perform resumable upload.
How do I retrieve Location URI as specified in documentation?
Maybe this https://github.com/PiyushXCoder/google-drive-ResumableUpload/blob/master/ResumableUpload.java help you out. However, it was written for servlets but you may easily modify it for android instead.
Well, after getting the comments let me put some extra descriptions.
However, the "ResumableUpload.java" github repo link is well commented and it is enough to make you clear how to perform this upload on google drive. And, you don't actually need to read this long description.
As described in https://developers.google.com/drive/v3/web/resumable-upload by google about how to perform a resumable upload
The following method uploads a file dividing it into chunks.
That's all.
I was trying for the better part of a week now and I finally got the resumable uploads to run. It does not work how I expected it would, but it does work.
Don't Use the Drive REST API for Everything
What I learned is that the Google Drive REST API is, as far as I know, not really capable of making chunked uploads. This may be a bug or it may be by design. I may also be too stupid.
But what got me thinking was that I could not see code examples anywhere. Everybody just talked about
Http
headers all the time. So this is what we're gonna do below. We'll use just the headers.So here is how you do resumable, chunked uploads with the Google Drive REST API and Android:
0) Initialization
1) Start a Resumable Session
Follow the rules outlined by Google in this document:
Set all the header fields just like in Google's example. Send it as a
POST
request. Use yourcredential
variable to get the authorization token. The mime type forX-Upload-Content-Type
is not so important, it works without it too (this SO answer provides a nice function to retrieve it from a path). Set theX-Upload-Content-Length
to the total length of your file. SetContent-Type
to JSON format, since our body will provide the metadata for Google in the JSON format.Now create your metadata body. I put in a file name and a parent. Set the
Content-Length
to the length of yourbody
in bytes. Then write your body to therequest.getOutputStream()
output stream.2) Save the Resumable Session URI
Finally,
connect()
and wait for a response. If the response code is200
, you have successfully initiated a chunked, resumable upload. Now save thelocation
header URI somewhere (database, text file, whatever). You're gonna need it later.3) Upload the File
Put the following code in a loop, until the entire file is uploaded. After every chunk, you will get a response with code
308
and arange
header. From thisrange
header, you can read the next chunk start (see (4)).Content-Type
is going to be the mime type again.Content-Length
is the number of bytes you upload in this chunk.Content-Range
needs to be of the formbytes startByte-EndByte/BytesTotal
. You put this in aPUT
request.Then you create a
FileInputStream
and set the position to your start byte (which you got from your last responserange
header) and read another chunk into your buffer. This buffer is then written to the connection output stream. Finally,connect()
.4) Handle Response
After this you will get a response with code
308
(if successful). This response contains arange
header (mentioned).You split this up and obtain your new chunk start byte.
5) The Response Code Is Not 308?!
It can happen that you get a
5xx
response. Your internet connection could fail, the file could be deleted/renamed during upload, etc. etc. Don't worry. As long as you save your session URI and your chunk start byte, you can resume the upload anytime.In order to do that, send a header of the following form:
You will then receive a
308
with arange
header, from which you can read the last uploaded byte (just as we did above). Take this number and start to loop again.I hope I could help some of you. If you have any more questions, just ask in the comments and I will edit the answer.
You don't have to care about all this logic. The documentation indeed explain the flow to complete a resumable upload but it's error prone if done "manually".
Fortunately, Google expose a dedicated class to handle such case, i.e the
MediaHttpUploader
.This snippet of code do the job of a resumable upload on drive (same thing can be achieved on GCS):
}
Note that no where we mention location. All the logic is hidden in the
MediaHttpUploader
class.So I don't really answer the question (where to find "Location") but I point the fact that this not really needed when using classes from Google library (and I am pretty sure other third party libraries exist to do the same job).
UPDATE: the mediaHttpUploader is what is used under the hood by the Drive v3 client. So we can think about something like that:
If you were able to get a 200 Http status, it will provide the
Location
as part of the header. But from what I saw on yourSystem.print
, there's noHttpResponse.getHeader
, this may just be a typo and you're referring toHttpResponse.getHeaders
.If this is the case, I'd suggest to first determine if you got
200 OK
Http status code, and loop thegetAllheaders
to determine if there's aLocation
header listed.Hope this helps!