Skip to content

Instantly share code, notes, and snippets.

@tolmachevroman
Last active August 29, 2015 14:14
Show Gist options
  • Save tolmachevroman/be77b272d127e95d904d to your computer and use it in GitHub Desktop.
Save tolmachevroman/be77b272d127e95d904d to your computer and use it in GitHub Desktop.
Resumable file upload to Nginx powered server
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
if(!isUploading) {
// EditText view with file path
if(!mTextViewUploadFile.getText().toString().contains("Select file")) {
upload(mTextViewUploadFile.getText().toString());
} else {
Toast.makeText(this, "Select file to upload", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Wait until file is uploaded", Toast.LENGTH_LONG).show();
}
}
void upload(String filePath) {
mTotalBytes = null;
mOffset = 0;
mChunkNumber = 0;
if(!wasInterrupted) {
mSessionId = System.currentTimeMillis() + "";
}
File file = new File(filePath);
if(file.exists()) {
try {
mTotalBytes = Files.toByteArray(file);
mTotalSize = mTotalBytes.length;
if(mTotalSize > 0) {
String[] subfolders = filePath.split("/");
mFileName = subfolders[subfolders.length - 1];
mProgressBar.setMax(mTotalSize);
mRequestUrl = new URL("http://my.webserver.com:8000/upload");
byte[] chunk = Arrays.copyOfRange(mTotalBytes, mOffset, CHUNK_SIZE);
mUpperOffset = mOffset + chunk.length - 1;
new ContinuousUploadTask(chunk).execute();
isUploading = true;
} else {
Toast.makeText(this, "File is corrupted", Toast.LENGTH_LONG).show();
}
} catch(IOException e) {
Log.d("ERROR", e.getMessage());
} catch (OutOfMemoryError e) {
Toast.makeText(this, "This file is way too large", Toast.LENGTH_LONG).show();
}
}
}
//inner AsynTask class
int CHUNK_SIZE = 256*1024;
URL mRequestUrl;
String mFileName;
String mSessionId;
int mOffset = 0;
int mUpperOffset;
int mTotalSize;
byte[] mTotalBytes;
int mChunkNumber = 0;
boolean isUploading;
boolean wasInterrupted;
class ContinuousUploadTask extends AsyncTask<Void, Void, Void> {
int responseCode;
String rawResponse;
byte[] content;
public ContinuousUploadTask(byte[] content) {
this.content = content;
}
public String doPostRequest() {
String responseString = null;
DefaultHttpClient httpclient = new DefaultHttpClient();
if(connectedToInternet()) {
try {
HttpPost httpPost = new HttpPost(mRequestUrl.toString());
httpPost.setHeader("X-Session-ID", mSessionId);
httpPost.setHeader("Content-Type", "application/octet-stream");
httpPost.setHeader("Content-Disposition", "attachment; filename=" + mFileName);
String contentRange = "bytes " + mOffset +
"-" + mUpperOffset + "/" + mTotalSize;
//log just once
if(mOffset == 0) {
log("X-Session-ID: " + mSessionId);
log("Content-Type: " + "application/octet-stream");
log("Content-Disposition: " + "attachment; filename=" + mFileName);
log("X-Content-Range: " + contentRange);
log("Total # of chunks: " + mTotalSize / CHUNK_SIZE);
} else {
log("X-Session-ID: " + mSessionId);
}
httpPost.setHeader("X-Content-Range", contentRange);
httpPost.setHeader("Connection", "Keep-Alive");
httpPost.setEntity(new ByteArrayEntity(content));
HttpResponse response = httpclient.execute(httpPost);
rawResponse = response.getStatusLine().toString();
log("Raw response: " + rawResponse);
responseString = EntityUtils.toString(response
.getEntity(), "UTF-8");
responseCode = response.getStatusLine().getStatusCode();
if(response.getFirstHeader("Range") != null) {
String rangeHeader = response.getFirstHeader("Range").toString();
log("Server has mTotalBytes from " + rangeHeader.split("/")[0].split("-")[0].split(":")[1].trim() +
" to " + rangeHeader.split("/")[0].split("-")[1] + ". " +
"Total file size is " + rangeHeader.split("/")[1] + ".");
//continue previous download
if(mUpperOffset != Integer.parseInt(rangeHeader.split("/")[0].split("-")[1])) {
mOffset = Integer.parseInt(rangeHeader.split("/")[0].split("-")[1]);
} else {
mOffset += CHUNK_SIZE;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
isUploading = false;
wasInterrupted = true;
}
return responseString;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
doPostRequest();
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
log("\n");
if(connectedToInternet()) {
if(responseCode == 201 && mOffset < mTotalSize) {
log("Chunk " + (mChunkNumber + 1) + " accepted");
mProgressBar.setProgress(mOffset);
//continue
mChunkNumber++;
byte[] chunk;
if(mOffset + CHUNK_SIZE <= mTotalSize) {
chunk = Arrays.copyOfRange(mTotalBytes, mOffset, mOffset + CHUNK_SIZE);
} else {
chunk = Arrays.copyOfRange(mTotalBytes, mOffset, mTotalSize);
}
mUpperOffset = mOffset + chunk.length - 1;
new ContinuousUploadTask(chunk).execute();
} else if(responseCode == 200) {
log("File fully accepted");
mProgressBar.setProgress(mTotalSize);
isUploading = false;
wasInterrupted = false;
} else if(responseCode == 500) {
Toast.makeText(TestActivity.this, rawResponse, Toast.LENGTH_LONG).show();
isUploading = false;
wasInterrupted = true;
}
} else {
isUploading = false;
wasInterrupted = true;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment