Created
December 14, 2016 14:07
-
-
Save SemonCat/ba5c7c1e8bb13d589afe2097db52e0b2 to your computer and use it in GitHub Desktop.
This file contains 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
package com.asus.robot.storytelling.chromecast; | |
import android.text.TextUtils; | |
import android.util.Log; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.Map; | |
import fi.iki.elonen.NanoHTTPD; | |
/** | |
* Created by semoncat on 2016/11/28. | |
*/ | |
public class FileServer extends NanoHTTPD { | |
private static final String TAG = "FileServer"; | |
public FileServer() { | |
super(9527); | |
} | |
@Override | |
public Response serve(IHTTPSession session) { | |
String filePath = session.getParms().get("file_path"); | |
//filePath = "/storage/emulated/0/storytelling/TW_SevenSheep/interactive/videos/En_036.mp4"; | |
Log.d(TAG, "serve: " + filePath); | |
if (!TextUtils.isEmpty(filePath)) { | |
return serveFile(session.getHeaders(), new File(filePath)); | |
} | |
return newChunkedResponse(Response.Status.BAD_REQUEST, "", null); | |
} | |
private Response serveFile(Map<String, String> header, File file) { | |
Response res; | |
String mime = "video/mp4"; | |
try { | |
// Calculate etag | |
String etag = Integer.toHexString((file.getAbsolutePath() + | |
file.lastModified() + "" + file.length()).hashCode()); | |
// Support (simple) skipping: | |
long startFrom = 0; | |
long endAt = -1; | |
String range = header.get("range"); | |
if (range != null) { | |
if (range.startsWith("bytes=")) { | |
range = range.substring("bytes=".length()); | |
int minus = range.indexOf('-'); | |
try { | |
if (minus > 0) { | |
startFrom = Long.parseLong(range.substring(0, minus)); | |
endAt = Long.parseLong(range.substring(minus + 1)); | |
} | |
} catch (NumberFormatException ignored) { | |
} | |
} | |
} | |
// Change return code and add Content-Range header when skipping is requested | |
long fileLen = file.length(); | |
if (range != null && startFrom >= 0) { | |
if (startFrom >= fileLen) { | |
res = createResponse(Response.Status.RANGE_NOT_SATISFIABLE, MIME_PLAINTEXT, ""); | |
res.addHeader("Content-Range", "bytes 0-0/" + fileLen); | |
res.addHeader("ETag", etag); | |
} else { | |
if (endAt < 0) { | |
endAt = fileLen - 1; | |
} | |
long newLen = endAt - startFrom + 1; | |
if (newLen < 0) { | |
newLen = 0; | |
} | |
final long dataLen = newLen; | |
FileInputStream fis = new FileInputStream(file) { | |
@Override | |
public int available() throws IOException { | |
return (int) dataLen; | |
} | |
}; | |
fis.skip(startFrom); | |
res = createResponse(Response.Status.PARTIAL_CONTENT, mime, fis, fis.available()); | |
res.addHeader("Content-Length", "" + dataLen); | |
res.addHeader("Content-Range", "bytes " + startFrom + "-" + | |
endAt + "/" + fileLen); | |
res.addHeader("ETag", etag); | |
} | |
} else { | |
if (etag.equals(header.get("if-none-match"))) | |
res = createResponse(Response.Status.NOT_MODIFIED, mime, ""); | |
else { | |
res = createResponse(Response.Status.OK, mime, new FileInputStream(file), file.length()); | |
res.addHeader("Content-Length", "" + fileLen); | |
res.addHeader("ETag", etag); | |
} | |
} | |
} catch (IOException ioe) { | |
res = getResponse("Forbidden: Reading file failed"); | |
} | |
return (res == null) ? getResponse("Error 404: File not found") : res; | |
} | |
// Announce that the file server accepts partial content requests | |
private Response createResponse(Response.Status status, String mimeType, InputStream message, long total) { | |
Response res = newFixedLengthResponse(status, mimeType, message, total); | |
res.addHeader("Accept-Ranges", "bytes"); | |
return res; | |
} | |
// Announce that the file server accepts partial content requests | |
private Response createResponse(Response.Status status, String mimeType, String message) { | |
Response res = newFixedLengthResponse(status, mimeType, message); | |
res.addHeader("Accept-Ranges", "bytes"); | |
return res; | |
} | |
private Response getResponse(String message) { | |
return createResponse(Response.Status.OK, "text/plain", message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment