Last active
August 29, 2015 14:14
-
-
Save tolmachevroman/be77b272d127e95d904d to your computer and use it in GitHub Desktop.
Resumable file upload to Nginx powered server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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