| 1: | /* | |
| 2: | * Copyright (c) 1998-99 The WebApp Framework. All rights reserved. | |
| 3: | * | |
| 4: | * Redistribution and use in source and binary forms, with or without | |
| 5: | * modification, are permitted provided that the following conditions | |
| 6: | * are met: | |
| 7: | * | |
| 8: | * 1. Redistributions of source code must retain the above copyright | |
| 9: | * notice, this list of conditions and the following disclaimer. | |
| 10: | * | |
| 11: | * 2. Redistributions in binary form must reproduce the above copyright | |
| 12: | * notice, this list of conditions and the following disclaimer in the | |
| 13: | * documentation and/or other materials provided with the distribution. | |
| 14: | * | |
| 15: | * 3. The WebApp Framework may be used for evaluation, private or | |
| 16: | * educational purposes without fee. | |
| 17: | * | |
| 18: | * 4. The right to redistribute The WebApp Framework or any part of it | |
| 19: | * as part of free software is hereby granted. Redistribution as part | |
| 20: | * of a commercial product is NOT permitted in any form without prior | |
| 21: | * written permission. | |
| 22: | * | |
| 23: | * 5. Every modification must be notified to The WebApp Framework, i.e. | |
| 24: | * Peter Rossbach and Hendrik Schreiber, and redistribution of the | |
| 25: | * modified code without prior notification is NOT permitted in any form. | |
| 26: | * | |
| 27: | * 6. All advertising materials mentioning features or use of this | |
| 28: | * software must display the following acknowledgment: "This product | |
| 29: | * includes software developed by Peter Rossbach and Hendrik Schreiber | |
| 30: | * (http://www.webapp.de/)." | |
| 31: | * | |
| 32: | * 7. The names "WebApp" and "WebApp Framework" must not be used to | |
| 33: | * endorse or promote products derived from this software without prior | |
| 34: | * written permission. | |
| 35: | * | |
| 36: | * 8. Redistributions of any form whatsoever must retain the following | |
| 37: | * acknowledgment: "This product includes software developed by Peter | |
| 38: | * Rossbach and Hendrik Schreiber (http://www.webapp.de/)." | |
| 39: | * | |
| 40: | * 9. As this release also contains software by Sun Microsystems the | |
| 41: | * following conditions have to be met, too. They apply to the | |
| 42: | * files lib/servlet.jar, lib/mail.jar and lib/activation.jar | |
| 43: | * contained in this release. | |
| 44: | * | |
| 45: | * 10. Java Platform Interface. Licensee may not modify the Java Platform | |
| 46: | * Interface (JPI, identified as classes contained within the javax | |
| 47: | * package or any subpackages of the javax package), by creating additional | |
| 48: | * classes within the JPI or otherwise causing the addition to or modification | |
| 49: | * of the classes in the JPI. In the event that Licensee creates any | |
| 50: | * Java-related API and distribute such API to others for applet or | |
| 51: | * application development, you must promptly publish broadly, an accurate | |
| 52: | * specification for such API for free use by all developers of Java-based | |
| 53: | * software. | |
| 54: | * | |
| 55: | * 11. Restrictions. Software is confidential copyrighted information of Sun and | |
| 56: | * title to all copies is retained by Sun and/or its licensors. Licensee | |
| 57: | * shall not modify, decompile, disassemble, decrypt, extract, or otherwise | |
| 58: | * reverse engineer Software. Software may not be leased, assigned, or | |
| 59: | * sublicensed, in whole or in part. Software is not designed or intended | |
| 60: | * for use in on-line control of aircraft, air traffic, aircraft navigation | |
| 61: | * or aircraft communications; or in the design, construction, operation or | |
| 62: | * maintenance of any nuclear facility. Licensee warrants that it will not | |
| 63: | * use or redistribute the Software for such purposes. | |
| 64: | * | |
| 65: | * 12. Disclaimer of Warranty. Software is provided "AS IS," without a warranty | |
| 66: | * of any kind. * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, | |
| 67: | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
| 68: | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. | |
| 69: | * | |
| 70: | * 13. Termination. This License is effective until terminated. Licensee may | |
| 71: | * terminate this License at any time by destroying all copies of Software. | |
| 72: | * This License will terminate immediately without notice from Sun if Licensee | |
| 73: | * fails to comply with any provision of this License. Upon such termination, | |
| 74: | * Licensee must destroy all copies of Software. | |
| 75: | * | |
| 76: | * 14. Export Regulations. Software, including technical data, is subject to U.S. | |
| 77: | * export control laws, including the U.S. Export Administration Act and its | |
| 78: | * associated regulations, and may be subject to export or import regulations | |
| 79: | * in other countries. Licensee agrees to comply strictly with all such | |
| 80: | * regulations and acknowledges that it has the responsibility to obtain | |
| 81: | * licenses to export, re-export, or import Software. Software may not be | |
| 82: | * downloaded, or otherwise exported or re-exported (i) into, or to a national | |
| 83: | * or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any | |
| 84: | * country to which the U.S. has embargoed goods; or (ii) to anyone on the | |
| 85: | * U.S. Treasury Department's list of Specially Designated Nations or the U.S. | |
| 86: | * Commerce Department's Table of Denial Orders. | |
| 87: | * | |
| 88: | * THIS SOFTWARE IS PROVIDED BY PETER ROSSBACH AND HENDRIK SCHREIBER | |
| 89: | * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 90: | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 91: | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PETER | |
| 92: | * ROSSBACH AND HENDRIK SCHREIBER BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 93: | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 94: | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
| 95: | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 96: | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 97: | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 98: | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 99: | * SUCH DAMAGE. | |
| 100: | * | |
| 101: | * For more information on The WebApp Framework, Peter Rossbach or | |
| 102: | * Hendrik Schreiber, please see <http://www.webapp.de/>. | |
| 103: | * | |
| 104: | */ | |
| 105: | ||
| 106: | ||
| 107: | ||
| 108: | import java.io.*; | |
| 109: | import java.net.*; | |
| 110: | import java.util.*; | |
| 111: | ||
| 112: | /** | |
| 113: | * Server, which is capable of performing | |
| 114: | * the <code>GET</code> command. Compared to {@link SimpleHttp} | |
| 115: | * some improvements are found. For instance, the error- and | |
| 116: | * status codes are set correctly. The Content-Type is set, | |
| 117: | * if a file <code>mime.types</code> is located in the current | |
| 118: | * directory. It should conform the following format: | |
| 119: | * <xmp> | |
| 120: | * .ra=audio/x-realaudio | |
| 121: | * .wav=audio/x-wav | |
| 122: | * .gif=image/gif | |
| 123: | * .jpeg=image/jpeg | |
| 124: | * .jpg=image/jpeg | |
| 125: | * .png=image/png | |
| 126: | * .tiff=image/tiff | |
| 127: | * .html=text/html | |
| 128: | * .htm=text/html | |
| 129: | * .txt=text/plain | |
| 130: | * </xmp> | |
| 131: | * | |
| 132: | * @author Hendrik Schreiber, Peter Rossbach | |
| 133: | * @version $Id: SimpleHttpd2.java,v 1.7 2000/07/15 12:23:39 Hendrik Exp $ | |
| 134: | * @see OneShotHttpd | |
| 135: | * @see SimpleHttpd | |
| 136: | */ | |
| 137: | public class SimpleHttpd2 extends Thread | |
| 138: | { | |
| 139: | /** | |
| 140: | * Version | |
| 141: | */ | |
| 142: | public static String vcid = "$Id: SimpleHttpd2.java,v 1.7 2000/07/15 12:23:39 Hendrik Exp $"; | |
| 143: | ||
| 144: | /** | |
| 145: | * Socket of a request. | |
| 146: | */ | |
| 147: | protected Socket s = null; | |
| 148: | ||
| 149: | /** | |
| 150: | * Document root. | |
| 151: | */ | |
| 152: | protected static File docRoot; | |
| 153: | ||
| 154: | /** | |
| 155: | * Canonical document root. | |
| 156: | */ | |
| 157: | protected static String canonicalDocRoot; | |
| 158: | ||
| 159: | /** | |
| 160: | * The port the server will listen to | |
| 161: | */ | |
| 162: | public final static int HTTP_PORT = 8080; | |
| 163: | ||
| 164: | /** | |
| 165: | * CRLF | |
| 166: | */ | |
| 167: | public final static String CRLF = "\r\n"; | |
| 168: | ||
| 169: | /** | |
| 170: | * Protocol out server understands. | |
| 171: | */ | |
| 172: | public final static String PROTOCOL = "HTTP/1.0 "; | |
| 173: | ||
| 174: | /** | |
| 175: | * Status code: All OK. | |
| 176: | */ | |
| 177: | public final static String SC_OK = "200 OK"; | |
| 178: | ||
| 179: | /** | |
| 180: | * Status code: Bad request. | |
| 181: | */ | |
| 182: | public final static String SC_BAD_REQUEST = "400 Bad Request"; | |
| 183: | ||
| 184: | /** | |
| 185: | * Status code: Forbidden request. | |
| 186: | */ | |
| 187: | public final static String SC_FORBIDDEN = "403 Forbidden"; | |
| 188: | ||
| 189: | /** | |
| 190: | * Status code: Resource not found. | |
| 191: | */ | |
| 192: | public final static String SC_NOT_FOUND = "404 Not Found"; | |
| 193: | ||
| 194: | /** | |
| 195: | * Content type map. | |
| 196: | */ | |
| 197: | protected static Properties typeMap = new Properties(); | |
| 198: | ||
| 199: | /** | |
| 200: | * Current status code. | |
| 201: | */ | |
| 202: | protected String statusCode = SC_OK; | |
| 203: | ||
| 204: | /** | |
| 205: | * Current header. | |
| 206: | */ | |
| 207: | protected Hashtable myHeaders = new Hashtable(); | |
| 208: | ||
| 209: | /** | |
| 210: | * Waits for an <code>GET</code> request and performs it. | |
| 211: | * Objects are searched for relatively to the current directory | |
| 212: | * (Document root = "./"). If no file is specified, only | |
| 213: | * a directory, the file <code>index.html</code> is delivered.<br> | |
| 214: | * If the request is not a <code>GET</code> request, the error | |
| 215: | * message 400, <code>Bad Request</code>, is sent to the client. | |
| 216: | */ | |
| 217: | public static void main(String argv[]) | |
| 218: | { | |
| 219: | try | |
| 220: | { | |
| 221: | typeMap.load(new FileInputStream("mime.types")); | |
| 222: | docRoot = new File("."); | |
| 223: | canonicalDocRoot = docRoot.getCanonicalPath(); | |
| 224: | ServerSocket listen = new ServerSocket(HTTP_PORT); | |
| 225: | while(true) | |
| 226: | { | |
| 227: | SimpleHttpd2 aRequest = new SimpleHttpd2(listen.accept()); | |
| 228: | } | |
| 229: | } | |
| 230: | catch(IOException e) | |
| 231: | { | |
| 232: | System.err.println("Error: " + e.toString()); | |
| 233: | } | |
| 234: | } | |
| 235: | ||
| 236: | /** | |
| 237: | * Sets the socket of this request and starts the thread. | |
| 238: | * | |
| 239: | * @param s Socket of a request | |
| 240: | */ | |
| 241: | public SimpleHttpd2(Socket s) | |
| 242: | { | |
| 243: | this.s = s; | |
| 244: | start(); | |
| 245: | } | |
| 246: | ||
| 247: | /** | |
| 248: | * The actually slogger of this class. The request is parsed | |
| 249: | * and the method {@link #getDocument()} is called | |
| 250: | */ | |
| 251: | public void run() | |
| 252: | { | |
| 253: | try | |
| 254: | { | |
| 255: | setHeader("Server","SimpleHttpd2"); | |
| 256: | BufferedReader is = new BufferedReader(new InputStreamReader(s.getInputStream())); | |
| 257: | DataOutputStream os = new DataOutputStream(s.getOutputStream()); | |
| 258: | String request = is.readLine(); | |
| 259: | System.out.println("Request: " + request); | |
| 260: | StringTokenizer st = new StringTokenizer(request); | |
| 261: | if((st.countTokens() == 3) && st.nextToken().equals("GET")) | |
| 262: | { | |
| 263: | String filename = docRoot.getPath() + st.nextToken(); | |
| 264: | if(filename.endsWith("/") || filename.equals("")) | |
| 265: | filename += "index.html"; | |
| 266: | File file = new File(filename); | |
| 267: | if(file.getCanonicalPath().startsWith(canonicalDocRoot)) | |
| 268: | sendDocument(os,file); | |
| 269: | else | |
| 270: | sendError(SC_FORBIDDEN,os); | |
| 271: | } | |
| 272: | else | |
| 273: | { | |
| 274: | sendError(SC_BAD_REQUEST,os); | |
| 275: | } | |
| 276: | is.close(); | |
| 277: | os.close(); | |
| 278: | s.close(); | |
| 279: | } | |
| 280: | catch(IOException ioe) | |
| 281: | { | |
| 282: | System.err.println("Error: " + ioe.toString()); | |
| 283: | } | |
| 284: | } | |
| 285: | ||
| 286: | /** | |
| 287: | * Reads the file, specified in <code>request</code> and writes it to | |
| 288: | * the OutputStream.<br> | |
| 289: | * If the file could not be found, the error message 404, | |
| 290: | * <code>Not Found</code>, is returned. | |
| 291: | * | |
| 292: | * @exception IOException in case writing to the <code>DataOutputStream</code> | |
| 293: | * fails. | |
| 294: | * @param os Stream, where the requested object is to be copied to. | |
| 295: | * @param file file to copy. | |
| 296: | */ | |
| 297: | protected void sendDocument(DataOutputStream os, File file) throws IOException | |
| 298: | { | |
| 299: | try | |
| 300: | { | |
| 301: | BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); | |
| 302: | sendStatusLine(os); | |
| 303: | setHeader("Content-Length",(new Long(file.length())).toString()); | |
| 304: | setHeader("Content-Type",guessType(file.getPath())); | |
| 305: | sendHeader(os); | |
| 306: | os.writeBytes(CRLF); | |
| 307: | byte[] buf = new byte[1024]; | |
| 308: | int len; | |
| 309: | while((len = in.read(buf,0,1024)) != -1) | |
| 310: | { | |
| 311: | os.write(buf,0,len); | |
| 312: | } | |
| 313: | in.close(); | |
| 314: | } | |
| 315: | catch(FileNotFoundException fnfe) | |
| 316: | { | |
| 317: | sendError(SC_NOT_FOUND,os); | |
| 318: | } | |
| 319: | } | |
| 320: | ||
| 321: | /** | |
| 322: | * Sets a status code. | |
| 323: | * | |
| 324: | * @param statusCode status code | |
| 325: | */ | |
| 326: | protected void setStatusCode(String statusCode) | |
| 327: | { | |
| 328: | this.statusCode = statusCode; | |
| 329: | } | |
| 330: | ||
| 331: | /** | |
| 332: | * Gets the status code. | |
| 333: | * | |
| 334: | * @return status code | |
| 335: | */ | |
| 336: | protected String getStatusCode() | |
| 337: | { | |
| 338: | return statusCode; | |
| 339: | } | |
| 340: | ||
| 341: | /** | |
| 342: | * Writes the status line to the consigned <code>DataOutputStream</code>. | |
| 343: | * | |
| 344: | * @param out DataOutputStream where the line is to be written. | |
| 345: | * @exception IOException in case writing fails. | |
| 346: | */ | |
| 347: | protected void sendStatusLine(DataOutputStream out) throws IOException | |
| 348: | { | |
| 349: | out.writeBytes(PROTOCOL + getStatusCode() + CRLF); | |
| 350: | } | |
| 351: | ||
| 352: | /** | |
| 353: | * Sets an header value. | |
| 354: | * | |
| 355: | * @param key key of the header value. | |
| 356: | * @param value the header value. | |
| 357: | */ | |
| 358: | protected void setHeader(String key, String value) | |
| 359: | { | |
| 360: | myHeaders.put(key,value); | |
| 361: | } | |
| 362: | ||
| 363: | /** | |
| 364: | * Writes the header to the consigned <code>DataOutputStream</code>. | |
| 365: | * | |
| 366: | * @param out DataOutputStream where the header is to be written. | |
| 367: | * @exception IOException in case writing fails. | |
| 368: | */ | |
| 369: | protected void sendHeader(DataOutputStream out) throws IOException | |
| 370: | { | |
| 371: | String line; | |
| 372: | String key; | |
| 373: | Enumeration e = myHeaders.keys(); | |
| 374: | while(e.hasMoreElements()) | |
| 375: | { | |
| 376: | key = (String)e.nextElement(); | |
| 377: | out.writeBytes(key + ": " + myHeaders.get(key) + CRLF); | |
| 378: | } | |
| 379: | } | |
| 380: | ||
| 381: | /** | |
| 382: | * Writes an error message to the consigned <code>DataOutputStream</code>. | |
| 383: | * | |
| 384: | * @param out DataOutputStream where the error message is to be written. | |
| 385: | * @param statusCode status code. | |
| 386: | * @exception IOException in case writing fails. | |
| 387: | */ | |
| 388: | protected void sendError(String statusCode, DataOutputStream out) throws IOException | |
| 389: | { | |
| 390: | setStatusCode(statusCode); | |
| 391: | sendStatusLine(out); | |
| 392: | out.writeBytes(CRLF + "<html>" + "<head><title>" + getStatusCode() + "</title></head>" + "<body><h1>" + getStatusCode() + "</h1></body>" + "</html>"); | |
| 393: | System.err.println(getStatusCode()); | |
| 394: | } | |
| 395: | ||
| 396: | /** | |
| 397: | * Surmise the <code>Content-Type</code> of the file by means | |
| 398: | * of the file extension. | |
| 399: | * | |
| 400: | * @param filename file name | |
| 401: | * @return Content-Type or "unknown/unknown" in case no | |
| 402: | * appropriate type is found. | |
| 403: | */ | |
| 404: | public String guessType(String filename) | |
| 405: | { | |
| 406: | String type = null; | |
| 407: | int i = filename.lastIndexOf("."); | |
| 408: | if(i > 0) | |
| 409: | type = typeMap.getProperty(filename.substring(i)); | |
| 410: | if(type == null) | |
| 411: | type = "unknown/unknown"; | |
| 412: | return type; | |
| 413: | } | |
| 414: | ||
| 415: | } | |
| 416: | ||
| 417: | // end of class |
This page was automatically generated by SharpDevelop.