/* * Christopher Deckers (chrriis@nextencia.net) * http://www.nextencia.net * * See the file "readme.txt" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ package chrriis.common; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JOptionPane; import org.geopublishing.atlasViewer.http.Webserver; import org.geopublishing.geopublisher.swing.GpSwingUtil; import chrriis.dj.nativeswing.NSSystemProperty; import chrriis.dj.nativeswing.swtimpl.components.JHTMLEditor; import de.schmitzm.io.IOUtil; import de.schmitzm.swing.FileExtensionFilter; /** * @author Christopher Deckers */ public class WebServer { public static class HTTPRequest implements Cloneable { HTTPRequest(String urlPath, Map<String, String> headerMap) { this.headerMap = headerMap == null ? new HashMap<String, String>() : headerMap; setURLPath(urlPath); } private final Map<String, String> headerMap; public Map<String, String> getHeaderMap() { return headerMap; } private String endQuery = ""; private String urlPath; void setURLPath(String urlPath) { this.urlPath = urlPath; resourcePath = urlPath; int index = resourcePath.indexOf('?'); if (index != -1) { String queryString = resourcePath.substring(index + 1); endQuery = '?' + queryString; resourcePath = resourcePath.substring(0, index); for (String content : queryString.split("&")) { int eqIndex = content.indexOf('='); if (eqIndex > 0) { String key = content.substring(0, eqIndex); String value = Utils.decodeURL(content.substring(eqIndex + 1)); queryParameterMap.put(key, value); } else { queryParameterMap.put(content, ""); } } } index = resourcePath.indexOf('#'); if (index != -1) { anchor = resourcePath.substring(index + 1); endQuery = '#' + anchor + endQuery; resourcePath = resourcePath.substring(0, index); } } public String getURLPath() { return urlPath; } private String resourcePath; void setResourcePath(String resourcePath) { this.resourcePath = resourcePath; urlPath = resourcePath + endQuery; } public String getResourcePath() { return resourcePath; } private String anchor; public String getAnchor() { return anchor; } private Map<String, String> queryParameterMap = new HashMap<String, String>(); public Map<String, String> getQueryParameterMap() { return queryParameterMap; } private boolean isPostMethod; void setPostMethod(boolean isPostMethod) { this.isPostMethod = isPostMethod; } public boolean isPostMethod() { return isPostMethod; } private HTTPData[] httpPostDataArray; void setHTTPPostDataArray(HTTPData[] httpPostDataArray) { this.httpPostDataArray = httpPostDataArray; } public HTTPData[] getHTTPPostDataArray() { return httpPostDataArray; } @Override protected HTTPRequest clone() { try { HTTPRequest httpRequest = (HTTPRequest) super.clone(); httpRequest.queryParameterMap = new HashMap<String, String>(queryParameterMap); return httpRequest; } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } } public static class HTTPData { private final Map<String, String> headerMap = new HashMap<String, String>(); HTTPData() { } public Map<String, String> getHeaderMap() { return headerMap; } private byte[] bytes; public byte[] getBytes() { return bytes; } void setBytes(byte[] bytes) { this.bytes = bytes; } } public static abstract class WebServerContent { public static final String MIME_APPLICATION_OCTET_STREAM = "application/octet-stream"; private static Map<String, String> extensionToMimeTypeMap = new HashMap<String, String>(); static { extensionToMimeTypeMap.put("323", "text/h323"); extensionToMimeTypeMap.put("acx", "application/internet-property-stream"); extensionToMimeTypeMap.put("ai", "application/postscript"); extensionToMimeTypeMap.put("aif", "audio/x-aiff"); extensionToMimeTypeMap.put("aifc", "audio/x-aiff"); extensionToMimeTypeMap.put("aiff", "audio/x-aiff"); extensionToMimeTypeMap.put("asf", "video/x-ms-asf"); extensionToMimeTypeMap.put("asr", "video/x-ms-asf"); extensionToMimeTypeMap.put("asx", "video/x-ms-asf"); extensionToMimeTypeMap.put("au", "audio/basic"); extensionToMimeTypeMap.put("avi", "video/x-msvideo"); extensionToMimeTypeMap.put("axs", "application/olescript"); extensionToMimeTypeMap.put("bas", "text/plain"); extensionToMimeTypeMap.put("bcpio", "application/x-bcpio"); extensionToMimeTypeMap.put("bin", "application/octet-stream"); extensionToMimeTypeMap.put("bmp", "image/bmp"); extensionToMimeTypeMap.put("c", "text/plain"); extensionToMimeTypeMap.put("cat", "application/vnd.ms-pkiseccat"); extensionToMimeTypeMap.put("cdf", "application/x-cdf"); extensionToMimeTypeMap.put("cer", "application/x-x509-ca-cert"); extensionToMimeTypeMap.put("class", "application/octet-stream"); extensionToMimeTypeMap.put("clp", "application/x-msclip"); extensionToMimeTypeMap.put("cmx", "image/x-cmx"); extensionToMimeTypeMap.put("cod", "image/cis-cod"); extensionToMimeTypeMap.put("cpio", "application/x-cpio"); extensionToMimeTypeMap.put("crd", "application/x-mscardfile"); extensionToMimeTypeMap.put("crl", "application/pkix-crl"); extensionToMimeTypeMap.put("crt", "application/x-x509-ca-cert"); extensionToMimeTypeMap.put("csh", "application/x-csh"); extensionToMimeTypeMap.put("css", "text/css"); extensionToMimeTypeMap.put("dcr", "application/x-director"); extensionToMimeTypeMap.put("der", "application/x-x509-ca-cert"); extensionToMimeTypeMap.put("dir", "application/x-director"); extensionToMimeTypeMap.put("dll", "application/x-msdownload"); extensionToMimeTypeMap.put("dms", "application/octet-stream"); extensionToMimeTypeMap.put("doc", "application/msword"); extensionToMimeTypeMap.put("dot", "application/msword"); extensionToMimeTypeMap.put("dvi", "application/x-dvi"); extensionToMimeTypeMap.put("dxr", "application/x-director"); extensionToMimeTypeMap.put("eps", "application/postscript"); extensionToMimeTypeMap.put("etx", "text/x-setext"); extensionToMimeTypeMap.put("evy", "application/envoy"); extensionToMimeTypeMap.put("exe", "application/octet-stream"); extensionToMimeTypeMap.put("fif", "application/fractals"); extensionToMimeTypeMap.put("flr", "x-world/x-vrml"); extensionToMimeTypeMap.put("gif", "image/gif"); extensionToMimeTypeMap.put("gtar", "application/x-gtar"); extensionToMimeTypeMap.put("gz", "application/x-gzip"); extensionToMimeTypeMap.put("h", "text/plain"); extensionToMimeTypeMap.put("hdf", "application/x-hdf"); extensionToMimeTypeMap.put("hlp", "application/winhlp"); extensionToMimeTypeMap.put("hqx", "application/mac-binhex40"); extensionToMimeTypeMap.put("hta", "application/hta"); extensionToMimeTypeMap.put("htc", "text/x-component"); extensionToMimeTypeMap.put("htm", "text/html"); extensionToMimeTypeMap.put("html", "text/html"); extensionToMimeTypeMap.put("htt", "text/webviewhtml"); extensionToMimeTypeMap.put("ico", "image/x-icon"); extensionToMimeTypeMap.put("ief", "image/ief"); extensionToMimeTypeMap.put("iii", "application/x-iphone"); extensionToMimeTypeMap.put("ins", "application/x-internet-signup"); extensionToMimeTypeMap.put("isp", "application/x-internet-signup"); extensionToMimeTypeMap.put("jfif", "image/pipeg"); extensionToMimeTypeMap.put("jnlp", "application/x-java-jnlp-file"); extensionToMimeTypeMap.put("jpe", "image/jpeg"); extensionToMimeTypeMap.put("jpeg", "image/jpeg"); extensionToMimeTypeMap.put("jpg", "image/jpeg"); extensionToMimeTypeMap.put("js", "application/x-javascript"); extensionToMimeTypeMap.put("latex", "application/x-latex"); extensionToMimeTypeMap.put("lha", "application/octet-stream"); extensionToMimeTypeMap.put("lsf", "video/x-la-asf"); extensionToMimeTypeMap.put("lsx", "video/x-la-asf"); extensionToMimeTypeMap.put("lzh", "application/octet-stream"); extensionToMimeTypeMap.put("m13", "application/x-msmediaview"); extensionToMimeTypeMap.put("m14", "application/x-msmediaview"); extensionToMimeTypeMap.put("m3u", "audio/x-mpegurl"); extensionToMimeTypeMap.put("man", "application/x-troff-man"); extensionToMimeTypeMap.put("mdb", "application/x-msaccess"); extensionToMimeTypeMap.put("me", "application/x-troff-me"); extensionToMimeTypeMap.put("mht", "message/rfc822"); extensionToMimeTypeMap.put("mhtml", "message/rfc822"); extensionToMimeTypeMap.put("mid", "audio/mid"); extensionToMimeTypeMap.put("mny", "application/x-msmoney"); extensionToMimeTypeMap.put("mov", "video/quicktime"); extensionToMimeTypeMap.put("movie", "video/x-sgi-movie"); extensionToMimeTypeMap.put("mp2", "video/mpeg"); extensionToMimeTypeMap.put("mp3", "audio/mpeg"); extensionToMimeTypeMap.put("mpa", "video/mpeg"); extensionToMimeTypeMap.put("mpe", "video/mpeg"); extensionToMimeTypeMap.put("mpeg", "video/mpeg"); extensionToMimeTypeMap.put("mpg", "video/mpeg"); extensionToMimeTypeMap.put("mpp", "application/vnd.ms-project"); extensionToMimeTypeMap.put("mpv2", "video/mpeg"); extensionToMimeTypeMap.put("ms", "application/x-troff-ms"); extensionToMimeTypeMap.put("mvb", "application/x-msmediaview"); extensionToMimeTypeMap.put("nws", "message/rfc822"); extensionToMimeTypeMap.put("oda", "application/oda"); extensionToMimeTypeMap.put("oga", "audio/ogg"); extensionToMimeTypeMap.put("ogg", "audio/ogg"); extensionToMimeTypeMap.put("ogv", "video/ogg"); extensionToMimeTypeMap.put("p10", "application/pkcs10"); extensionToMimeTypeMap.put("p12", "application/x-pkcs12"); extensionToMimeTypeMap.put("p7b", "application/x-pkcs7-certificates"); extensionToMimeTypeMap.put("p7c", "application/x-pkcs7-mime"); extensionToMimeTypeMap.put("p7m", "application/x-pkcs7-mime"); extensionToMimeTypeMap.put("p7r", "application/x-pkcs7-certreqresp"); extensionToMimeTypeMap.put("p7s", "application/x-pkcs7-signature"); extensionToMimeTypeMap.put("pbm", "image/x-portable-bitmap"); extensionToMimeTypeMap.put("pdf", "application/pdf"); extensionToMimeTypeMap.put("pfx", "application/x-pkcs12"); extensionToMimeTypeMap.put("pgm", "image/x-portable-graymap"); extensionToMimeTypeMap.put("pko", "application/ynd.ms-pkipko"); extensionToMimeTypeMap.put("pma", "application/x-perfmon"); extensionToMimeTypeMap.put("pmc", "application/x-perfmon"); extensionToMimeTypeMap.put("pml", "application/x-perfmon"); extensionToMimeTypeMap.put("pmr", "application/x-perfmon"); extensionToMimeTypeMap.put("pmw", "application/x-perfmon"); extensionToMimeTypeMap.put("png", "image/png"); extensionToMimeTypeMap.put("pnm", "image/x-portable-anymap"); extensionToMimeTypeMap.put("pot,", "application/vnd.ms-powerpoint"); extensionToMimeTypeMap.put("ppm", "image/x-portable-pixmap"); extensionToMimeTypeMap.put("pps", "application/vnd.ms-powerpoint"); extensionToMimeTypeMap.put("ppt", "application/vnd.ms-powerpoint"); extensionToMimeTypeMap.put("prf", "application/pics-rules"); extensionToMimeTypeMap.put("ps", "application/postscript"); extensionToMimeTypeMap.put("pub", "application/x-mspublisher"); extensionToMimeTypeMap.put("qt", "video/quicktime"); extensionToMimeTypeMap.put("ra", "audio/x-pn-realaudio"); extensionToMimeTypeMap.put("ram", "audio/x-pn-realaudio"); extensionToMimeTypeMap.put("ras", "image/x-cmu-raster"); extensionToMimeTypeMap.put("rgb", "image/x-rgb"); extensionToMimeTypeMap.put("rmi", "audio/mid"); extensionToMimeTypeMap.put("roff", "application/x-troff"); extensionToMimeTypeMap.put("rtf", "application/rtf"); extensionToMimeTypeMap.put("rtx", "text/richtext"); extensionToMimeTypeMap.put("scd", "application/x-msschedule"); extensionToMimeTypeMap.put("sct", "text/scriptlet"); extensionToMimeTypeMap.put("setpay", "application/set-payment-initiation"); extensionToMimeTypeMap.put("setreg", "application/set-registration-initiation"); extensionToMimeTypeMap.put("sh", "application/x-sh"); extensionToMimeTypeMap.put("shar", "application/x-shar"); extensionToMimeTypeMap.put("sit", "application/x-stuffit"); extensionToMimeTypeMap.put("snd", "audio/basic"); extensionToMimeTypeMap.put("spc", "application/x-pkcs7-certificates"); extensionToMimeTypeMap.put("spl", "application/futuresplash"); extensionToMimeTypeMap.put("src", "application/x-wais-source"); extensionToMimeTypeMap.put("sst", "application/vnd.ms-pkicertstore"); extensionToMimeTypeMap.put("stl", "application/vnd.ms-pkistl"); extensionToMimeTypeMap.put("stm", "text/html"); extensionToMimeTypeMap.put("svg", "image/svg+xml"); extensionToMimeTypeMap.put("sv4cpio", "application/x-sv4cpio"); extensionToMimeTypeMap.put("sv4crc", "application/x-sv4crc"); extensionToMimeTypeMap.put("swf", "application/x-shockwave-flash"); extensionToMimeTypeMap.put("t", "application/x-troff"); extensionToMimeTypeMap.put("tar", "application/x-tar"); extensionToMimeTypeMap.put("tcl", "application/x-tcl"); extensionToMimeTypeMap.put("tex", "application/x-tex"); extensionToMimeTypeMap.put("texi", "application/x-texinfo"); extensionToMimeTypeMap.put("texinfo", "application/x-texinfo"); extensionToMimeTypeMap.put("tgz", "application/x-compressed"); extensionToMimeTypeMap.put("tif", "image/tiff"); extensionToMimeTypeMap.put("tiff", "image/tiff"); extensionToMimeTypeMap.put("tr", "application/x-troff"); extensionToMimeTypeMap.put("trm", "application/x-msterminal"); extensionToMimeTypeMap.put("tsv", "text/tab-separated-values"); extensionToMimeTypeMap.put("txt", "text/plain"); extensionToMimeTypeMap.put("uls", "text/iuls"); extensionToMimeTypeMap.put("ustar", "application/x-ustar"); extensionToMimeTypeMap.put("vcf", "text/x-vcard"); extensionToMimeTypeMap.put("vrml", "x-world/x-vrml"); extensionToMimeTypeMap.put("wav", "audio/x-wav"); extensionToMimeTypeMap.put("wax", "audio/x-ms-wax"); extensionToMimeTypeMap.put("wcm", "application/vnd.ms-works"); extensionToMimeTypeMap.put("wdb", "application/vnd.ms-works"); extensionToMimeTypeMap.put("wks", "application/vnd.ms-works"); extensionToMimeTypeMap.put("wm", "video/x-ms-wm"); extensionToMimeTypeMap.put("wma", "audio/x-ms-wma"); extensionToMimeTypeMap.put("wmd", "application/x-ms-wmd"); extensionToMimeTypeMap.put("wmf", "application/x-msmetafile"); extensionToMimeTypeMap.put("wmv", "audio/x-ms-wmv"); extensionToMimeTypeMap.put("wmx", "video/x-ms-wmx"); extensionToMimeTypeMap.put("wmz", "application/x-ms-wmz"); extensionToMimeTypeMap.put("wps", "application/vnd.ms-works"); extensionToMimeTypeMap.put("wri", "application/x-mswrite"); extensionToMimeTypeMap.put("wrl", "x-world/x-vrml"); extensionToMimeTypeMap.put("wrz", "x-world/x-vrml"); extensionToMimeTypeMap.put("wvx", "video/x-ms-wvx"); extensionToMimeTypeMap.put("xaf", "x-world/x-vrml"); extensionToMimeTypeMap.put("xbm", "image/x-xbitmap"); extensionToMimeTypeMap.put("xla", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xlc", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xlm", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xls", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xlt", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xlw", "application/vnd.ms-excel"); extensionToMimeTypeMap.put("xml", "application/xml"); extensionToMimeTypeMap.put("xof", "x-world/x-vrml"); extensionToMimeTypeMap.put("xpm", "image/x-xpixmap"); extensionToMimeTypeMap.put("xwd", "image/x-xwindowdump"); extensionToMimeTypeMap.put("z", "application/x-compress"); extensionToMimeTypeMap.put("zip", "application/zip"); } public static String getDefaultMimeType(String extension) { if (extension == null) { return MIME_APPLICATION_OCTET_STREAM; } if (extension.startsWith(".")) { extension = extension.substring(1); } String mimeType = extensionToMimeTypeMap.get(extension.toLowerCase(Locale.ENGLISH)); return mimeType != null ? mimeType : MIME_APPLICATION_OCTET_STREAM; } public abstract InputStream getInputStream(); public static InputStream getInputStream(String content) { if (content == null) { return null; } try { return new ByteArrayInputStream(content.getBytes("UTF-8")); } catch (Exception e) { e.printStackTrace(); return null; } } public String getContentType() { return getDefaultMimeType(".html"); } public long getContentLength() { return -1; } public long getLastModified() { return System.currentTimeMillis(); } } private static class WebServerConnectionThread extends Thread { private static int threadInitNumber; private static Semaphore semaphore = new Semaphore(10); private static synchronized int nextThreadNumber() { return threadInitNumber++; } private final Socket socket; public WebServerConnectionThread(Socket socket) { super("WebServer Connection-" + nextThreadNumber()); this.socket = socket; setDaemon(true); } private static final String LS = Utils.LINE_SEPARATOR; static void writeHTTPHeaders(BufferedOutputStream out, int code, String contentType, long contentLength, long lastModified) { StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.0 " + code + " OK" + LS); sb.append("Content-Type: " + contentType + LS); sb.append("Server: WebServer/1.0" + LS); sb.append("Date: " + new Date() + LS); // sb.append("Expires: " + new Date() + LS); // sb.append("Last-modified: " + new Date(lastModified) + LS); if (contentLength != -1) { sb.append("Content-Length: " + contentLength + LS); } sb.append(LS); try { out.write(sb.toString().getBytes("UTF-8")); } catch (IOException e) { e.printStackTrace(); } } static void writeHTTPError(BufferedOutputStream out, int code, String message) { writeHTTPHeaders(out, code, "text/html", message.length(), System.currentTimeMillis()); try { out.write(message.getBytes("UTF-8")); out.flush(); out.close(); } catch (IOException e) { // e.printStackTrace(); } } private static class HTTPInputStream extends InputStream { static enum LineSeparator { CR, LF, CRLF, } private final InputStream inputStream; public HTTPInputStream(InputStream inputStream) { this.inputStream = inputStream; } public String getLineSeparator() { switch (lineSeparator) { case CR: return "\r"; case LF: return "\n"; case CRLF: return "\r\n"; } return null; } private LineSeparator lineSeparator; private int lastByte = -1; public String readAsciiLine() throws IOException { if (lineSeparator == null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int b = read(); if (b == -1) { return null; } if (b == '\n') { lineSeparator = LineSeparator.LF; return new String(baos.toByteArray(), "UTF-8"); } if (b == '\r') { int b2 = read(); if (b2 == '\n') { lineSeparator = LineSeparator.CRLF; } else { lineSeparator = LineSeparator.CR; if (b2 != -1) { lastByte = b2; } } return new String(baos.toByteArray(), "UTF-8"); } baos.write(b); } } ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (lastByte != -1) { baos.write(lastByte); lastByte = -1; } switch (lineSeparator) { case CR: for (int b; (b = read()) != '\r' && b != -1; baos.write(b)) { } break; case LF: for (int b; (b = read()) != '\n' && b != -1; baos.write(b)) { } break; case CRLF: for (int b; (b = read()) != '\r' && b != -1; baos.write(b)) { } read(); break; } return new String(baos.toByteArray(), "UTF-8"); } @Override public void close() throws IOException { inputStream.close(); } @Override public int read(byte[] b) throws IOException { return inputStream.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return inputStream.read(b, off, len); } @Override public int read() throws IOException { int n = inputStream.read(); return n; } } @Override public void run() { try { HTTPInputStream in = new HTTPInputStream(new BufferedInputStream(socket.getInputStream())); BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream()); try { String request = in.readAsciiLine(); if (request == null || !(request.endsWith(" HTTP/1.0") || request.endsWith("HTTP/1.1"))) { writeHTTPError(out, 500, "Invalid Method."); return; } boolean isPostMethod = false; if (request.startsWith("POST ")) { isPostMethod = true; } else if (!request.startsWith("GET ")) { writeHTTPError(out, 500, "Invalid Method."); return; } String resourcePath = request.substring((isPostMethod ? "POST " : "GET ").length(), request.length() - " HTTP/1.0".length()); Map<String, String> headerMap = new HashMap<String, String>(); for (String header; (header = in.readAsciiLine()).length() > 0;) { int index = header.indexOf(": "); if (index > 0) { headerMap.put(header.substring(0, index), header.substring(index + ": ".length())); } } HTTPRequest httpRequest = new HTTPRequest(resourcePath, headerMap); // //MS-Hack.sn // String currFolder = // httpRequest.getQueryParameterMap().get("CurrentFolder"); // if ( currFolder != null && currFolder.equals("/") ) { // httpRequest.getQueryParameterMap().put("CurrentFolder","D:/DOWNLOAD/"); // } // if ( httpRequest.getQueryParameterMap().size() > 0 ) { // System.out.println("dsdss"); // } // MS-Hack.en httpRequest.setPostMethod(isPostMethod); if (isPostMethod) { HTTPData[] httpDataArray; String contentType = headerMap.get("Content-Type"); String contentLengthString = headerMap.get("Content-Length"); int contentLength = contentLengthString == null ? -1 : Integer.parseInt(contentLengthString); if (contentType != null && contentType.startsWith("multipart/")) { byte[] dataBytes; if (contentLength > 0) { dataBytes = new byte[contentLength]; in.read(dataBytes); } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; for (int i; (i = in.read(bytes)) != -1; baos.write(bytes, 0, i)) { } dataBytes = baos.toByteArray(); } String boundary = "--" + contentType.substring(contentType.indexOf("boundary=") + "boundary=".length()); byte[] boundaryBytes = boundary.getBytes("UTF-8"); List<Integer> indexList = new ArrayList<Integer>(); for (int i = 0; i < dataBytes.length - boundaryBytes.length; i++) { boolean isFound = true; for (int j = 0; j < boundaryBytes.length; j++) { if (dataBytes[i + j] != boundaryBytes[j]) { isFound = false; break; } } if (isFound) { indexList.add(i); i += boundaryBytes.length; } } httpDataArray = new HTTPData[indexList.size() - 1]; for (int i = 0; i < httpDataArray.length; i++) { HTTPData httpData = new HTTPData(); httpDataArray[i] = httpData; int start = indexList.get(i); ByteArrayInputStream bais = new ByteArrayInputStream(dataBytes, start, indexList.get(i + 1) - start - in.getLineSeparator().length()); HTTPInputStream din = new HTTPInputStream(bais); din.readAsciiLine(); Map<String, String> dataHeaderMap = httpData.getHeaderMap(); for (String header; (header = din.readAsciiLine()).length() > 0;) { String key = header.substring(header.indexOf(": ")); String value = header.substring(key.length() + ": ".length()); dataHeaderMap.put(key, value); } ByteArrayOutputStream aos = new ByteArrayOutputStream(); for (int n; (n = din.read()) != -1; aos.write(n)) { } httpData.setBytes(aos.toByteArray()); } } else { InputStreamReader reader = new InputStreamReader(in, "UTF-8"); String dataContent; if (contentLength > 0) { char[] chars = new char[contentLength]; int offset = 0; while (chars.length > offset) { int n = reader.read(chars, offset, chars.length - offset); offset = n == -1 ? chars.length : offset + n; } dataContent = new String(chars); } else { StringBuilder sb = new StringBuilder(); char[] chars = new char[1024]; for (int i; (i = reader.read(chars)) != -1; sb.append(chars, 0, i)) { } dataContent = sb.toString(); } HTTPData httpData = new HTTPData(); Map<String, String> dataHeaderMap = httpData.getHeaderMap(); for (String content : dataContent.split("&")) { int eqIndex = content.indexOf('='); if (eqIndex > 0) { String key = content.substring(0, eqIndex); String value = Utils.decodeURL(content.substring(eqIndex + 1)); dataHeaderMap.put(key, value); } else { dataHeaderMap.put(content, ""); } } httpDataArray = new HTTPData[] { httpData }; } httpRequest.setHTTPPostDataArray(httpDataArray); } WebServerContent webServerContent = getWebServerContent(httpRequest); InputStream resourceStream_ = null; if (webServerContent != null) { try { resourceStream_ = webServerContent.getInputStream(); } catch (Exception e) { e.printStackTrace(); } } boolean isPrintRequestsDebug = Boolean.parseBoolean(NSSystemProperty.WEBSERVER_DEBUG_PRINTREQUESTS .get()); String printDataProperty = NSSystemProperty.WEBSERVER_DEBUG_PRINTPORT.get(); boolean isPrintDataDebug = false; long printDataCount = -1; if (printDataProperty != null) { try { printDataCount = Long.parseLong(printDataProperty); isPrintDataDebug = true; } catch (Exception e) { isPrintDataDebug = Boolean.parseBoolean(printDataProperty); printDataCount = Integer.MAX_VALUE; } } if (resourceStream_ == null) { if (isPrintRequestsDebug) { System.err.println("Web Server " + (isPostMethod ? "POST" : "GET") + ": " + resourcePath + " -> 404 (not found)"); } writeHTTPError(out, 404, "File Not Found."); return; } if (isPrintRequestsDebug || isPrintDataDebug) { System.err.println("Web Server " + (isPostMethod ? "POST" : "GET") + ": " + resourcePath + " -> 200 (OK)"); } BufferedInputStream resourceStream = new BufferedInputStream(resourceStream_); writeHTTPHeaders(out, 200, webServerContent.getContentType(), webServerContent.getContentLength(), webServerContent.getLastModified()); byte[] bytes = new byte[4096]; for (int i; (i = resourceStream.read(bytes)) != -1; out.write(bytes, 0, i)) { if (isPrintDataDebug && i > 0 && printDataCount > 0) { System.err.print(new String(bytes, 0, (int) Math.min(i, printDataCount), "UTF-8")); printDataCount -= i; } } if (isPrintDataDebug) { System.err.println(); } try { resourceStream.close(); } catch (Exception e) { e.printStackTrace(); } } finally { out.flush(); out.close(); in.close(); socket.close(); } } catch (Exception e) { // e.printStackTrace(); } finally { semaphore.release(); } } } private int port; public WebServer() { this(0); } public WebServer(int port) { this.port = port; } private volatile boolean isRunning; public void stop() { isRunning = false; if (serverSocket != null) { ServerSocket serverSocket = this.serverSocket; this.serverSocket = null; try { serverSocket.close(); } catch (IOException e) { } } } public boolean isRunning() { return isRunning; } public void start() throws IOException { start(true); } private volatile ServerSocket serverSocket; private volatile int instanceID; public void start(boolean isDaemon) throws IOException { if (isRunning) { return; } isRunning = true; instanceID = ObjectRegistry.getInstance().add(this); serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(InetAddress.getByName(getHostAddress()), port)); port = serverSocket.getLocalPort(); if (Boolean.parseBoolean(NSSystemProperty.WEBSERVER_DEBUG_PRINTPORT.get())) { System.err.println("Web Server port: " + port); } Thread listenerThread = new Thread("WebServer") { @Override public void run() { while (isRunning) { try { Socket socket = serverSocket.accept(); // Too risky if there are multiple network interfaces. // Need to find a better way... // String hostAddress = // socket.getInetAddress().getHostAddress(); // if(!HOST_ADDRESS.equals(hostAddress) && // !"127.0.0.1".equals(hostAddress)) { // throw new // IllegalStateException("Illegal connection from host " // + hostAddress); // } socket.setSoTimeout(10000); try { WebServerConnectionThread.semaphore.acquire(); } catch (InterruptedException e) { } WebServerConnectionThread webServerConnectionThread = new WebServerConnectionThread(socket); webServerConnectionThread.start(); } catch (Exception e) { if (serverSocket != null) { e.printStackTrace(); } } } serverSocket = null; ObjectRegistry.getInstance().remove(instanceID); } }; listenerThread.setDaemon(isDaemon); listenerThread.start(); } public int getPort() { return port; } public String getURLPrefix() { return "http://" + hostAddress + ":" + port; } /** * @return A URL that when accessed will invoke the method * <code>static WebServerContent getWebServerContent(HTTPRequest)</code> of the parameter class (the method * visibility does not matter). */ public String getDynamicContentURL(String className, String parameter) { return getURLPrefix() + "/class/" + instanceID + "/" + className + "/" + Utils.encodeURL(parameter); } /** * @return A URL that when accessed will invoke the method * <code>static WebServerContent getWebServerContent(HTTPRequest)</code> of the parameter class (the method * visibility does not matter). */ public String getDynamicContentURL(String className, String codebase, String parameter) { return getURLPrefix() + "/class/" + instanceID + "/" + className + "/" + codebase + "/" + Utils.encodeURL(parameter); } public String getClassPathResourceURL(String className, String resourcePath) { if (!resourcePath.startsWith("/")) { String classPath = className.replace('.', '/'); classPath = classPath.substring(0, classPath.lastIndexOf('/') + 1); resourcePath = "/" + classPath + resourcePath; } return getURLPrefix() + "/classpath/" + instanceID + Utils.simplifyPath(resourcePath); } public String getResourcePathURL(String codeBase, String resourcePath) { if (codeBase == null) { codeBase = new File(SystemProperty.USER_DIR.get()).getAbsolutePath(); } return getURLPrefix() + "/resource/" + Utils.encodeURL(codeBase) + "/" + Utils.encodeURL(resourcePath); } public WebServerContent getURLContent(String resourceURL) { try { HTTPRequest httpRequest = new HTTPRequest(new URL(resourceURL).getPath(), null); return getWebServerContent(httpRequest); } catch (Exception e) { e.printStackTrace(); return null; } } private final List<ClassLoader> referenceClassLoaderList = new ArrayList<ClassLoader>(1); public void addReferenceClassLoader(ClassLoader referenceClassLoader) { if (referenceClassLoader == null || referenceClassLoader == getClass().getClassLoader()) { return; } referenceClassLoaderList.add(0, referenceClassLoader); } public void removeReferenceClassLoader(ClassLoader referenceClassLoader) { if (referenceClassLoader == null || referenceClassLoader == getClass().getClassLoader()) { return; } referenceClassLoaderList.remove(referenceClassLoader); } /** * A content provider for global resources. * * @author Christopher Deckers */ public static interface WebServerContentProvider { /** * Get the web server content, or return null to ignore the request. * * @param httpRequest * the request. * @return the content, or null to ignore the request and potentially let another handler process it. */ public WebServerContent getWebServerContent(HTTPRequest httpRequest); } private final List<WebServerContentProvider> contentProviderList = new ArrayList<WebServerContentProvider>(); /** * Add a content provider for content that is not natively supported by the web server. * * @param webServerContentProvider * the content provider to add. */ public void addContentProvider(WebServerContentProvider webServerContentProvider) { contentProviderList.add(webServerContentProvider); } /** * Remove a content provider. * * @param webServerContentProvider * the content provider to remove. */ public void removeContentProvider(WebServerContentProvider webServerContentProvider) { contentProviderList.remove(webServerContentProvider); } // MS-Hack.sn /** * Determines the calling {@link JHTMLEditor} instance from registry cache. */ public static JHTMLEditor determineJHTMLEditorFromRegistry(HTTPRequest httpRequest) { // extract the ID of the calling JHTMLEditor from resourcePath // e.g. // "class/2/chrriis.dj.nativeswing.swtimpl.components.JHTMLEditor/1/editor/filemanager/browser/default/browser.html" // --> we need the "1" between "JHTMLEditor" and "/editor" String resourcePath = httpRequest.getResourcePath(); final Pattern pattern = Pattern.compile("JHTMLEditor/(\\d+?)/editor"); Matcher matcher = pattern.matcher(resourcePath); int instanceId = 1; if (matcher.find()) { instanceId = Integer.valueOf(matcher.group(1)); // JOptionPane.showMessageDialog(null, "JHTMLEditor instance not found.", "Error", JOptionPane.ERROR_MESSAGE); } final Object object = ObjectRegistry.getInstance().get(instanceId); return (JHTMLEditor) object; } /** * Opens a file chooser. In case of request type "Image" the chosen file is copied to the "image" folder relative to * the {@linkplain JHTMLEditor#getFileBrowserStartFolder() file chooser start folder}. * * @param httpRequest * the request * @return a "dummy" {@link WebServerContent} which sets the new relative file path (of the chosen file) to the * calling component and closes the web browser window */ public static WebServerContent performFileBrowsing(HTTPRequest httpRequest) { final JHTMLEditor ed = (JHTMLEditor) determineJHTMLEditorFromRegistry(httpRequest); final File fileBrowserStartFolder = ed.getFileBrowserStartFolder(); String type = httpRequest.getQueryParameterMap().get("Type"); if(type==null){ type="Image"; //default } // Open file chooser FileExtensionFilter filter = null; if ("Image".equals(type)) filter = GpSwingUtil.IMAGE_FILE_FILTER; // i8n final File choosenFile = GpSwingUtil.chooseImageFile(ed, fileBrowserStartFolder, filter, "Image".equals(type) ? "Choose an image" : "Choose file"); String relImagePath = null; if (choosenFile != null) relImagePath = GpSwingUtil.copyFileToRelativeFolder(ed.getWebBrowser(), choosenFile, fileBrowserStartFolder, "images"); // if copy was successful replace the template // wildcard with the relative path of the // choosen file String approveStr = (relImagePath == null) ? "false" : "true"; String fileStr = (relImagePath == null) ? "" : relImagePath; String template = null; try { template = IOUtil.readURLasString(new URL("http://localhost:" + Webserver.PORT + "/browser.html")); } catch (MalformedURLException err) { return null; } String site = template.replace("${approve}", approveStr); site = site.replace("${fileTemplate}", fileStr); final String site_ = site; return new WebServerContent() { @Override public InputStream getInputStream() { return new ByteArrayInputStream(site_.getBytes()); } }; } // MS-Hack.en protected static WebServerContent getWebServerContent(HTTPRequest httpRequest) { String parameter = httpRequest.getResourcePath(); if (parameter.startsWith("/")) { parameter = parameter.substring(1); } // MS-Hack.sn // Because Geopublisher (with HTML editor) runs on local // system, we want to use a "normal" file chooser. // System.out.println(httpRequest.getResourcePath()); if (parameter.contains("filemanager/browser/default/browser.html")) { WebServerContent content = performFileBrowsing(httpRequest); if (content != null) return content; } // MS-Hack.en int index = parameter.indexOf('/'); if (index != -1) { String type = parameter.substring(0, index); parameter = parameter.substring(index + 1); if ("class".equals(type)) { index = parameter.indexOf('/'); WebServer webServer = (WebServer) ObjectRegistry.getInstance().get( Integer.parseInt(parameter.substring(0, index))); if (webServer == null) { return null; } parameter = parameter.substring(index + 1); index = parameter.indexOf('/'); String className = parameter.substring(0, index); parameter = Utils.decodeURL(parameter.substring(index + 1)); httpRequest = httpRequest.clone(); try { Class<?> clazz = null; for (ClassLoader referenceClassLoader : webServer.referenceClassLoaderList) { try { clazz = Class.forName(className, true, referenceClassLoader); break; } catch (Exception e) { } } if (clazz == null) { clazz = Class.forName(className); } Method getWebServerContentMethod = clazz .getDeclaredMethod("getWebServerContent", HTTPRequest.class); getWebServerContentMethod.setAccessible(true); httpRequest.setResourcePath(parameter); return (WebServerContent) getWebServerContentMethod.invoke(null, httpRequest); } catch (Exception e) { e.printStackTrace(); return null; } } if ("classpath".equals(type)) { index = parameter.indexOf('/'); final WebServer webServer = (WebServer) ObjectRegistry.getInstance().get( Integer.parseInt(parameter.substring(0, index))); if (webServer == null) { return null; } parameter = parameter.substring(index + 1); final String resourcePath = removeHTMLAnchor(parameter); return new WebServerContent() { @Override public String getContentType() { int index = resourcePath.lastIndexOf('.'); return getDefaultMimeType(index == -1 ? null : resourcePath.substring(index)); } @Override public InputStream getInputStream() { try { for (ClassLoader referenceClassLoader : webServer.referenceClassLoaderList) { InputStream in = referenceClassLoader.getResourceAsStream(resourcePath); if (in != null) { return in; } } return WebServer.class.getResourceAsStream('/' + resourcePath); } catch (Exception e) { e.printStackTrace(); return null; } } }; } if ("resource".equals(type)) { index = parameter.indexOf('/'); if (index > 0) { String subs = parameter.substring(index - 1); if (subs.startsWith("://")) { index = parameter.indexOf('/', index + 2); } } // MS-Hack.sn // String codeBase = Utils.decodeURL(parameter.substring(0, // index)); // parameter = Utils.decodeURL(parameter.substring(index + 1)); String codeBase = IOUtil.decodeURL(parameter.substring(0, index)); parameter = IOUtil.decodeURL(parameter.substring(index + 1)); // MS-Hack.en String resourceURL; try { URL url = new URL(codeBase); int port = url.getPort(); resourceURL = url.getProtocol() + "://" + url.getHost() + (port != -1 ? ":" + port : ""); if (parameter.startsWith("/")) { resourceURL += removeHTMLAnchor(parameter); } else { String path = url.getPath(); path = path.substring(0, path.lastIndexOf('/') + 1) + parameter; resourceURL += path.startsWith("/") ? path : "/" + path; } } catch (Exception e) { File file = Utils.getLocalFile(new File(codeBase, removeHTMLAnchor(parameter)).getAbsolutePath()); if (file != null) { resourceURL = new File(codeBase, removeHTMLAnchor(parameter)).toURI().toString(); } else { resourceURL = codeBase + "/" + removeHTMLAnchor(parameter); } } final String resourceURL_ = resourceURL; return new WebServerContent() { @Override public long getContentLength() { File file = Utils.getLocalFile(resourceURL_); if (file != null) { return file.length(); } return super.getContentLength(); } @Override public String getContentType() { int index = resourceURL_.lastIndexOf('.'); return getDefaultMimeType(index == -1 ? null : resourceURL_.substring(index)); } @Override public InputStream getInputStream() { try { return new URL(resourceURL_).openStream(); } catch (Exception e) { } try { return new FileInputStream("/" + resourceURL_); } catch (Exception e) { e.printStackTrace(); } return null; } }; } } for (WebServerContentProvider contentProvider : webServer.contentProviderList) { WebServerContent webServerContent = contentProvider.getWebServerContent(httpRequest); if (webServerContent != null) { return webServerContent; } } return null; } private static String removeHTMLAnchor(String location) { int anchorIndex = location.indexOf('#'); if (anchorIndex > 0) { location = location.substring(0, anchorIndex); } return location; } private static WebServer webServer; private static Object LOCK = new Object(); private static String hostAddress; static { String hostAddress = Utils.getLocalHostAddress(); if (hostAddress == null) { hostAddress = "127.0.0.1"; } WebServer.hostAddress = hostAddress; } private static String getHostAddress() { return hostAddress; } public static void stopDefaultWebServer() { synchronized (LOCK) { if (webServer != null) { webServer.stop(); webServer = null; } } } public static WebServer getDefaultWebServer() { synchronized (LOCK) { if (webServer != null) { return webServer; } webServer = new WebServer(); try { boolean isApplet = "applet".equals(System.getProperty("nativeswing.deployment.type")); webServer.start(!isApplet); } catch (Exception e) { e.printStackTrace(); } return webServer; } } }