// Copyright 2012 Citrix Systems, Inc. Licensed under the // Apache License, Version 2.0 (the "License"); you may not use this // file except in compliance with the License. Citrix Systems, Inc. // reserves all rights not expressly granted by the License. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.consoleproxy; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Date; import java.util.HashMap; import java.util.Map; import com.cloud.consoleproxy.util.Logger; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; public class ConsoleProxyResourceHandler implements HttpHandler { private static final Logger s_logger = Logger.getLogger(ConsoleProxyResourceHandler.class); static Map<String, String> s_mimeTypes; static { s_mimeTypes = new HashMap<String, String>(); s_mimeTypes.put("jar", "application/java-archive"); s_mimeTypes.put("js", "text/javascript"); s_mimeTypes.put("css", "text/css"); s_mimeTypes.put("jpg", "image/jpeg"); s_mimeTypes.put("html", "text/html"); s_mimeTypes.put("htm", "text/html"); s_mimeTypes.put("log", "text/plain"); } static Map<String, String> s_validResourceFolders; static { s_validResourceFolders = new HashMap<String, String>(); s_validResourceFolders.put("applet", ""); s_validResourceFolders.put("logs", ""); s_validResourceFolders.put("images", ""); s_validResourceFolders.put("js", ""); s_validResourceFolders.put("css", ""); s_validResourceFolders.put("html", ""); } public ConsoleProxyResourceHandler() { } public void handle(HttpExchange t) throws IOException { try { if(s_logger.isDebugEnabled()) s_logger.debug("Resource Handler " + t.getRequestURI()); long startTick = System.currentTimeMillis(); doHandle(t); if(s_logger.isDebugEnabled()) s_logger.debug(t.getRequestURI() + " Process time " + (System.currentTimeMillis() - startTick) + " ms"); } catch (IOException e) { throw e; } catch(Throwable e) { s_logger.error("Unexpected exception, ", e); t.sendResponseHeaders(500, -1); // server error } finally { t.close(); } } @SuppressWarnings("deprecation") private void doHandle(HttpExchange t) throws Exception { String path = t.getRequestURI().getPath(); if(s_logger.isInfoEnabled()) s_logger.info("Get resource request for " + path); int i = path.indexOf("/", 1); String filepath = path.substring(i + 1); i = path.lastIndexOf("."); String extension = (i == -1) ? "" : path.substring(i + 1); String contentType = getContentType(extension); if(!validatePath(filepath)) { if(s_logger.isInfoEnabled()) s_logger.info("Resource access is forbidden, uri: " + path); t.sendResponseHeaders(403, -1); // forbidden return; } File f = new File ("./" + filepath); if(f.exists()) { long lastModified = f.lastModified(); String ifModifiedSince = t.getRequestHeaders().getFirst("If-Modified-Since"); if (ifModifiedSince != null) { long d = Date.parse(ifModifiedSince); if (d + 1000 >= lastModified) { Headers hds = t.getResponseHeaders(); hds.set("Content-Type", contentType); t.sendResponseHeaders(304, -1); if(s_logger.isInfoEnabled()) s_logger.info("Sent 304 file has not been " + "modified since " + ifModifiedSince); return; } } long length = f.length(); Headers hds = t.getResponseHeaders(); hds.set("Content-Type", contentType); hds.set("Last-Modified", new Date(lastModified).toGMTString()); t.sendResponseHeaders(200, length); responseFileContent(t, f); if(s_logger.isInfoEnabled()) s_logger.info("Sent file " + path + " with content type " + contentType); } else { if(s_logger.isInfoEnabled()) s_logger.info("file does not exist" + path); t.sendResponseHeaders(404, -1); } } private static String getContentType(String extension) { String key = extension.toLowerCase(); if(s_mimeTypes.containsKey(key)) { return s_mimeTypes.get(key); } return "application/octet-stream"; } private static void responseFileContent(HttpExchange t, File f) throws Exception { OutputStream os = t.getResponseBody(); FileInputStream fis = new FileInputStream(f); while (true) { byte[] b = new byte[8192]; int n = fis.read(b); if (n < 0) { break; } os.write(b, 0, n); } fis.close(); os.close(); } private static boolean validatePath(String path) { int i = path.indexOf("/"); if(i == -1) { if(s_logger.isInfoEnabled()) s_logger.info("Invalid resource path: can not start at resource root"); return false; } if(path.contains("..")) { if(s_logger.isInfoEnabled()) s_logger.info("Invalid resource path: contains relative up-level navigation"); return false; } return isValidResourceFolder(path.substring(0, i)); } private static boolean isValidResourceFolder(String name) { return s_validResourceFolders.containsKey(name); } }