/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package se.sics.gvod.system.util; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.nio.charset.Charset; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; import org.json.simple.JSONValue; import org.mortbay.util.URIUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.sics.gvod.config.VodConfig; import se.sics.gvod.system.main.SwingMain; import se.sics.gvod.system.util.ActiveTorrents.TorrentEntry; import se.sics.kompics.Kompics; /** * * @author jdowling */ public class BrowserGuiHandler implements HttpHandler { private static final String VIDEO_NAME = "myvideo.flv"; private static final String FLOWPLAYER = "flow.html"; private static final String JWPLAYER = "gvod.html"; private static final Logger logger = LoggerFactory.getLogger(BrowserGuiHandler.class); private SwingMain main; public BrowserGuiHandler(SwingMain main) { this.main = main; } @Override public void handle(HttpExchange exchange) throws IOException { logger.trace(exchange.getRequestMethod() + "\n" + exchange.getRequestHeaders().entrySet() + "\n" + exchange.getResponseHeaders().entrySet()); String requestMethod = exchange.getRequestMethod(); if (requestMethod.equalsIgnoreCase("GET")) { URI uri = exchange.getRequestURI(); String filename = uri.getPath().substring(1); StringBuffer sb = new StringBuffer(); URIUtil.encodePath(sb, filename); Map<String, Object> params = (Map<String, Object>) exchange.getAttribute("parameters"); String response = null; byte[] byteResponse = null; // JSON tutorial // http://code.google.com/p/json-simple/ if (params.containsKey("stats")) { // response = handleStatsQuery(exchange); } else if (params.containsKey("method")) { String fn = (String) params.get("method"); if (fn.compareToIgnoreCase("get_speed_info") == 0) { response = handleGetSpeedInfo(exchange); } } else if (params.containsKey("view")) { String video = (String) params.get("view"); response = handleViewVideo(exchange, video); } else if (params.containsKey("shutdown")) { // Sent by the plugin when it is stopped by the browser. // Allows the cleanup allocated resources. handleShutdown(exchange); } else if (params.containsKey("info")) { //Sent to convey its current status to the plugin, // which should be passed on to the user. handleInfo(exchange); } else { // This is the fileserver part - swfobject.js, player.swf, *.htm, etc String postfix = filename.substring(filename.lastIndexOf(".") + 1, filename.length()); if (postfix.compareToIgnoreCase("swf") == 0 || postfix.compareToIgnoreCase("ico") == 0) { byteResponse = handleBinaryFile(exchange, sb.toString(), postfix); } else { response = handleTextFile(exchange, sb.toString(), postfix); } } OutputStream responseBody = exchange.getResponseBody(); if (response != null) { responseBody.write(response.getBytes(Charset.defaultCharset())); } else if (byteResponse != null) { responseBody.write(byteResponse); } else { logger.warn("Bad request issued by client: " + requestMethod); throw new IllegalStateException("Something wrong."); } responseBody.flush(); responseBody.close(); } } /** * * @param exchange * @param filename * @param postfix * @return null if unsuccessful * @throws IOException */ private byte[] handleBinaryFile(HttpExchange exchange, String filename, String postfix) throws IOException { String type = null; if (postfix.compareToIgnoreCase("swf") == 0) { type = "application/x-shockwave-flash"; } else if (postfix.compareToIgnoreCase("ico") == 0) { type = "image/x-icon"; } //HTTP/1.1 200 OK //Last-Modified: Thu, 12 Mar 2009 17:09:30 GMT //ETag: "1036-464ef0c1c8680" //Server: Apache/2.2.11 (Unix) //X-Cache-TTL: 568 //X-Cached-Time: Thu, 21 Jan 2010 14:55:37 GMT //Accept-Ranges: bytes //Content-Length: 4150 //Content-Type: image/x-icon //Cache-Control: max-age=463 //Expires: Sun, 12 Sep 2010 14:22:09 GMT //Date: Sun, 12 Sep 2010 14:14:26 GMT //Connection: keep-alive File f = new File(VodConfig.getTorrentDir() + File.separator + "www" + File.separator + filename); long length = 0; byte[] buffer = null; if (f.exists()) { length = f.length(); if (length > Integer.MAX_VALUE) { throw new IllegalStateException("File was too large"); } BufferedInputStream bis; FileInputStream in = null; try { in = new FileInputStream(f); bis = new BufferedInputStream(in); buffer = new byte[(int) length]; int offset = 0; int numRead = 0; while (offset < buffer.length && (numRead = bis.read(buffer, offset, buffer.length - offset)) >= 0) { offset += numRead; } // Ensure all the bytes have been read in if (offset < length) { throw new IOException("Could not completely read file " + f.getName()); } } finally { if (in != null) { in.close(); } } } if (buffer != null) { Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Content-Type", type); responseHeaders.set("Connection", "Keep-Alive"); responseHeaders.set("Keep-Alive", "timeout=15, max=100"); responseHeaders.set("Accept-Ranges", "bytes"); responseHeaders.set("Content-Length", "" + length); exchange.sendResponseHeaders(200 /* http ok code*/, 0); } else { // TODO - broken send correct error code // Headers responseHeaders = exchange.getResponseHeaders(); // responseHeaders.set("Content-Type", "text/html"); exchange.sendResponseHeaders(404 /* file not found http error*/, 0); } return buffer; } private String handleTextFile(HttpExchange exchange, String filename, String postfix) throws IOException { StringBuilder sb = new StringBuilder(); // for .html & .js String type = "text/html"; if (postfix.compareToIgnoreCase("html") == 0 || postfix.compareToIgnoreCase("js") == 0 || postfix.compareToIgnoreCase("css") == 0) { type = "text/" + postfix; } File f = new File(VodConfig.getTorrentDir() + File.separator + "www" + File.separator + filename); boolean fileProb = false; long length = 0; if (f.exists()) { length = f.length(); if (length > Integer.MAX_VALUE) { throw new IllegalStateException("File was too large"); } try { ReadTextFileWithEncoding rf = new ReadTextFileWithEncoding(f, "ISO8859_1"); String text = rf.getText(); sb.append(text); } catch (IOException e) { fileProb = true; } } else { fileProb = true; logger.warn("HTTP SERVER: Could not find file: " + f.getAbsolutePath()); } Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Content-Type", type); responseHeaders.set("Connection", "Keep-Alive"); responseHeaders.set("Keep-Alive", "timeout=15, max=100"); responseHeaders.set("Accept-Ranges", "bytes"); responseHeaders.set("Content-Length", "" + sb.length()); if (fileProb) { exchange.sendResponseHeaders(404 /* http file not found*/, 0); } else { exchange.sendResponseHeaders(200 /* http ok code */, 0); } return sb.toString(); } private String handleViewVideo(HttpExchange exchange, String videoName) throws IOException { // return URL for .flv or .mp4 file to flashplayer StringBuffer sb = new StringBuffer(); StringBuffer encodedVideoName = new StringBuffer(); URIUtil.encodePath(encodedVideoName, videoName); String htmlFile = VodConfig.getTorrentDir() + File.separator + "www" + File.separator; if (SwingMain.PLAYER == 0) { htmlFile += JWPLAYER; } else if (SwingMain.PLAYER == 1) { htmlFile += FLOWPLAYER; } else { throw new IllegalStateException("Illegal parameter for media player."); } // Always stored the escaped (URI-encoded) video name TorrentEntry torrentEntry = ActiveTorrents.getTorrentEntry(encodedVideoName.toString()); String width = Integer.toString(torrentEntry.getWidth()); String height = Integer.toString(torrentEntry.getHeight()); File f = new File(htmlFile); boolean fileProb = false; if (f.exists()) { try { ReadTextFileWithEncoding rf = new ReadTextFileWithEncoding(f, "ISO8859_9"); String text = rf.getText(); text = text.replace(VIDEO_NAME, encodedVideoName.toString()); text = text.replace("640", width); text = text.replace("320", height); sb.append(text); } catch (IOException e) { fileProb = true; } } else { fileProb = true; } if (fileProb) { exchange.sendResponseHeaders(404 /* http file not found*/, 0); } else { exchange.sendResponseHeaders(200 /* http ok code */, 0); } return sb.toString(); } private void handleShutdown(HttpExchange exchange) throws IOException { Kompics.shutdown(); System.exit(-1); } private String handleInfo(HttpExchange exchange) throws IOException { return null; } private String handleGetSpeedInfo(HttpExchange exchange) throws IOException { Headers responseHeaders = exchange.getResponseHeaders(); responseHeaders.set("Server", "BaseHTTP/0.3 Java/1.6"); responseHeaders.set("Content-Type", "application/json"); responseHeaders.set("Connection", "Keep-Alive"); responseHeaders.set("Keep-Alive", "timeout=15, max=1001"); responseHeaders.set("Accept-Ranges", "bytes"); DateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); Date date = new Date(); String dateStr = dateFormat.format(date); // responseHeaders.set("Date", dateStr); //HTTP/1.1 200 OK //Server: BaseHTTP/0.3 Python/2.6.6 //Date: Thu, 21 Oct 2010 15:03:59 GMT //Connection: Keep-Alive //Keep-Alive: timeout=15, max=1001 //Content-Type: application/json //Accept-Ranges: bytes //Content-Length: 53 // //{"downspeed": 0.0, "success": "true", "upspeed": 0.0} //HTTP/1.1 200 OK //Transfer-encoding: chunked //Content-type: application/json //Content-length: 53 //Connection: Keep-Alive //Accept-ranges: bytes //Keep-alive: timeout=15, max=100 // //35 //{"downspeed": 1.0, "success": "true", "upspeed": 2.0} //0 int downSpeed = main.getSpeed(); int totalDownloaded = main.getTotalDownloaded(); String strResp = "{\"downspeed\":" + downSpeed + ", \"success\": \"true\", \"total\":" + totalDownloaded + "}"; Map obj = new LinkedHashMap(); obj.put("downspeed", new Integer(downSpeed)); obj.put("success", new Boolean(true)); obj.put("total", new Integer(totalDownloaded)); String jsonText = JSONValue.toJSONString(obj); // responseHeaders.set("Content-Length", "" + strResp.length()); // exchange.sendResponseHeaders(200 /* http error code */, strResp.length()); // return strResp; responseHeaders.set("Content-Length", "" + jsonText.length()); exchange.sendResponseHeaders(200 /* http error code */, jsonText.length()); return jsonText; } }