home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / net / www / httpd / server.java < prev    next >
Text File  |  1995-08-11  |  12KB  |  406 lines

  1. /*
  2.  * @(#)Server.java    1.4 95/05/12 James Gosling
  3.  * 
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19. package net.www.httpd;
  20.  
  21. import net.NetworkServer;
  22. import net.InetAddress;
  23. import net.www.html.MessageHeader;
  24. import net.www.html.URL;
  25. import java.io.*;
  26. import java.util.Hashtable;
  27. import java.util.Cache;
  28.  
  29. /**
  30.  * This is the base class for http servers.  To define a new type
  31.  * of server define a new subclass of Server with a getRequest
  32.  * method that services one request.  Start the server by executing:
  33.  * <pre>
  34.  *    new MyServerClass().startServer(port);
  35.  * </pre>
  36.  */
  37. public class Server extends NetworkServer {
  38.  
  39.     /** The mime header from the request. */
  40.     MessageHeader mh;
  41.     static int totalConnections;
  42.  
  43.     static URL defaultContext;
  44.     ServerParameters params;
  45.  
  46.     Cache fileCache = new Cache(1000);
  47.  
  48.     /** True iff the client expects a mime header (ie. HTTP/1.n) */
  49.     boolean expectsMime;
  50.  
  51.     Server (String argv[]) {
  52.     params = new ServerParameters(getClass().getName(), argv);
  53.     if (params.verbose)
  54.         params.print();
  55.     }
  56.  
  57.     /** Satisfy one get request.  It is invoked with the clientInput and
  58.     clientOutput streams initialized.  This method handles one client
  59.     connection. When it is done, it can simply exit. */
  60.     protected void getRequest(URL u, String param) {
  61.     try {
  62.         String fn = u.file;
  63.         if (fn.endsWith("/"))
  64.         fn = fn + params.welcome;
  65.         InputStream is = null;
  66.         int size = 0;
  67.         is = new FileInputStream(fn);
  68.         size = is.available();
  69.         String ct = params.mimeType(fn);
  70.         CachedFile cf = null;
  71.         MessageHeader mh = new MessageHeader();
  72.         mh.add("Content-type", ct);
  73.         mh.add("Server", params.serverName);
  74.         mh.add("Content-length", String.valueOf(size));
  75.         if (size <= params.maxRamCacheEntryBuffer) {
  76.         try {
  77.             cf = new CachedFile(is, size, mh);
  78.             fileCache.put(u, cf);
  79.             if (params.verbose)
  80.             System.out.print(u.toExternalForm() + ": Into RAM cache\n");
  81.         } catch(Exception e) {
  82.             if (params.verbose)
  83.             e.printStackTrace();
  84.         }
  85.         } else if (params.verbose)
  86.         System.out.print(u.toExternalForm() + ": from disk (too big for RAM cache: " + size + ")\n");
  87.         if (expectsMime) {
  88.         clientOutput.print("HTTP/1.0 200 Document follows\n");
  89.         mh.print(clientOutput);
  90.         }
  91.         if (cf != null)
  92.         cf.sendto(clientOutput);
  93.         else {
  94.         int nb;
  95.         byte buf[] = new byte[2048];
  96.         while ((nb = is.read(buf)) >= 0)
  97.             clientOutput.write(buf, 0, nb);
  98.         }
  99.         if (is != null)
  100.         is.close();
  101.     } catch(Exception e) {
  102.         if (params.verbose)
  103.         e.printStackTrace();
  104.         error("Can't read " + u.file);
  105.     }
  106.     }
  107.  
  108.     private static File TrashFile;    // File to rename to instead of
  109.     // removing files
  110.  
  111.     private void remove(File f) {
  112.     if (TrashFile == null)
  113.         TrashFile = new File(params.CacheRoot + "/trash");
  114.     try {
  115.         f.renameTo(TrashFile);
  116.     } catch(Exception e) {
  117.         System.out.print("Couldn't remove " + f + "\n");
  118.     }
  119.     }
  120.  
  121.     /** Satisfy one get request where this host is acting as a proxy.
  122.     It is invoked with the clientInput and
  123.     clientOutput streams initialized.  This method handles one client
  124.     connection. When it is done, it can simply exit. The default
  125.     server just echoes it's input. */
  126.     protected void getProxyRequest(URL u, String param) {
  127.     InputStream is = null;
  128.     OutputStream os = null;
  129.     MessageHeader mh = null;
  130.     boolean tryCache = params.Caching && u.canCache();
  131.     String ff = u.toExternalForm();
  132.     File CacheFile = new File(params.CacheRoot, u.toExternalForm()
  133.                   .replace('/', File.separatorChar) + "+");
  134.  
  135.     CachedFile cf = null;
  136.     if (tryCache) {
  137.         try {
  138.         is = new BufferedInputStream(new FileInputStream(CacheFile));
  139.         if (params.verbose)
  140.             System.out.print(u.toExternalForm() + ": Found in proxy cache\n");
  141.         tryCache = false;
  142.         mh = new MessageHeader(is);
  143.         u.content_type = mh.findValue("content-type");
  144.         /* we have it: try to put it in the RAM cache */
  145.         int size = is.available();
  146.         mh.set("Content-size", String.valueOf(size));
  147.         if (size <= params.maxRamCacheEntryBuffer) {
  148.             try {
  149.  
  150.             /*
  151.              * slurp it into the RAM cache, then shoot it out
  152.              * right away
  153.              */
  154.             cf = new CachedFile(is, size, mh);
  155.             fileCache.put(u, cf);
  156.             if (params.verbose)
  157.                 System.out.print(u.toExternalForm() + ": Proxy cached file into RAM cache\n");
  158.             if (expectsMime) {
  159.                 clientOutput.print("HTTP/1.0 200 Document follows\n");
  160.                 mh.print(clientOutput);
  161.             }
  162.             cf.sendto(clientOutput);
  163.             is.close();
  164.             return;
  165.             } catch(Exception e) {
  166.             if (params.verbose)
  167.                 e.printStackTrace();
  168.             }
  169.         } else if (params.verbose)
  170.             System.out.print(u.toExternalForm() + ": Too big for RAM cache (" + size +
  171.                    "<" + params.maxRamCacheEntryBuffer + ")\n");
  172.         } catch(Exception e) {
  173.         if (is != null) {
  174.             e.printStackTrace();
  175.             is.close();
  176.         }
  177.         is = null;
  178.         }
  179.     }
  180.     if (is == null)
  181.         if (params.CacheNoConnect) {
  182.         if (params.verbose)
  183.             System.out.print("Proxy cache missed with remote access disabled " + u.toExternalForm() + "\n");
  184.         if (expectsMime)
  185.             clientOutput.print("HTTP/1.0 404 not found (remote access disabled)\n" +
  186.                        "Server: " + params.serverName +
  187.                        "\nContent-type: text/html" +
  188.                        "\n\n");
  189.         clientOutput.print("<html><body><h1>File not found in cache, remote access disabled.</h1>\n"
  190.                    + u.toExternalForm() + "\n");
  191.         return;
  192.         } else {
  193.         try {
  194.             is = u.openStream();
  195.             if (params.verbose)
  196.             System.out.print(u.toExternalForm() + ": Proxy get.\n");
  197.         } catch(FileNotFoundException e) {
  198.             if (params.verbose)
  199.             System.out.print(u.toExternalForm() + ": Proxy get failed.\n");
  200.             if (expectsMime)
  201.             clientOutput.print("HTTP/1.0 404 not found\n" +
  202.                        "Server: " + params.serverName +
  203.                        "\nContent-type: text/html" +
  204.                        "\n\n");
  205.             clientOutput.print("<html><body><h1>File not found</h1>\n"
  206.                        + u.toExternalForm() + "\n");
  207.             return;
  208.         }
  209.         }
  210.     if (tryCache) {
  211.         try {
  212.         try {
  213.             os = new BufferedOutputStream(new FileOutputStream(CacheFile));
  214.         } catch(Exception e) {
  215.             new File(CacheFile.getParent()).mkdirs();
  216.             os = new BufferedOutputStream(new FileOutputStream(CacheFile));
  217.         }
  218.         } catch(Exception e) {
  219.         }
  220.     }
  221.     if (os != null)
  222.         if (mh != null)
  223.         mh.print(new PrintStream(os));
  224.         else
  225.         new PrintStream(os).print("Content-type: " + u.content_type + "\n\n");
  226.     if (expectsMime) {
  227.         clientOutput.print("HTTP/1.0 200 Document follows\n");
  228.         if (mh != null)
  229.         mh.print(clientOutput);
  230.         else
  231.         clientOutput.print("Server: " + params.serverName +
  232.                    "\nContent-type: " + u.content_type +
  233.                    "\n\n");
  234.     }
  235.     byte buf[] = new byte[2048];
  236.     int nb;
  237.     int nWritten = 0;
  238.     while ((nb = is.read(buf)) >= 0) {
  239.         if (os != null) {
  240.         try {
  241.             os.write(buf, 0, nb);
  242.             nWritten += nb;
  243.         } catch(Exception e) {
  244.             if (params.verbose)
  245.             System.out.print("Cache write to " + CacheFile + " failed (" + e + ")\n");
  246.             remove(CacheFile);
  247.             os.close();
  248.             os = null;
  249.         }
  250.         }
  251.         clientOutput.write(buf, 0, nb);
  252.     }
  253.     if (os != null)
  254.         os.close();
  255.     if (is != null)
  256.         is.close();
  257.     }
  258.  
  259.     /** Start generating an html reply to a get request.  This is a
  260.         convenience method to simplify getRequest */
  261.     public void startHtml(String title)
  262.     {
  263.     if (expectsMime)
  264.         clientOutput.print("HTTP/1.0 200 Document follows\n" +
  265.                    "Server: Java/" + params.serverName + "\n" +
  266.                    "Content-type: text/html\n\n");
  267.     clientOutput.print("<html><head><title>" + title +
  268.                "</title></head>\n<body><h1>" +
  269.                title + "</h1>\n");
  270.     }
  271.  
  272.     /** Generate an html reply to a get request that contains a
  273.         dump of the statistics for the current server.  getRequest
  274.         handlers can call it in response to special file names. */
  275.     protected void generateStatistics()
  276.     {
  277.     startHtml("Server statistics");
  278.     clientOutput.print(totalConnections + " total connections.<p>\n");
  279.     }
  280.  
  281.     /** Generate an html reply to a get request that contains the
  282.         output after executing a system command.  getRequest
  283.         handlers can call it in response to special file names. */
  284.     public void generateProcessOutput(String title, String command)
  285.     {
  286.     startHtml(title);
  287.     try {
  288.         InputStream in = new BufferedInputStream(System.execin(command));
  289.         clientOutput.print("<pre>\n");
  290.         int c;
  291.         while ((c = in.read()) >= 0)
  292.         switch (c) {
  293.           case '<':
  294.             clientOutput.print("<");
  295.             break;
  296.           case '&':
  297.             clientOutput.print("&");
  298.             break;
  299.           default:
  300.             clientOutput.write(c);
  301.             break;
  302.         }
  303.         in.close();
  304.         clientOutput.print("</pre>\n");
  305.     } catch(Exception e) {
  306.         clientOutput.print("Failed to execute " + command + "\n");
  307.     }
  308.     }
  309.  
  310.     public void error(String msg)
  311.     {
  312.     if (expectsMime)
  313.         clientOutput.print("HTTP/1.0 403 Error - " + msg + "\n" +
  314.                    "Content-type: text/html\n\n");
  315.     clientOutput.print("<html><head>Error</head><body>" +
  316.                "<H1>Error when fetching document:</h1>\n" +
  317.                msg + "\n");
  318.     if (mh != null) {
  319.         clientOutput.print("<p><hr><pre>\n");
  320.         mh.print(clientOutput);
  321.         clientOutput.print("</pre>\n");
  322.     }
  323.     }
  324.  
  325.     final public void serviceRequest()
  326.     {
  327.     totalConnections++;
  328.     if (defaultContext == null)
  329.         defaultContext = new URL("http", InetAddress.localHostName, "/");
  330.     try {
  331.         mh = new MessageHeader(clientInput);
  332.         String cmd = mh.findValue(null);
  333.         if (cmd == null) {
  334.         error("Missing command " + mh);
  335.         return;
  336.         }
  337.         int fsp = cmd.indexOf(' ');
  338.         if (fsp < 0) {
  339.         error("Syntax error in command: " + cmd);
  340.         return;
  341.         }
  342.         String k = cmd.substring(0, fsp);
  343.         int nsp = cmd.indexOf(' ', fsp + 1);
  344.         String p1, p2;
  345.         if (nsp > 0) {
  346.         p1 = cmd.substring(fsp + 1, nsp);
  347.         p2 = cmd.substring(nsp + 1);
  348.         } else {
  349.         p1 = cmd.substring(fsp + 1);
  350.         p2 = null;
  351.         }
  352.         expectsMime = p2 != null;
  353.         if (k.equalsIgnoreCase("get")) {
  354.         URL u = new URL(defaultContext, p1);
  355.         CachedFile cf = (CachedFile) fileCache.get(u);
  356.         if (cf != null) {
  357.             /* Found in RAM cache */
  358.             if (params.verbose)
  359.             System.out.print(u.toExternalForm() + ": get from RAM cache\n");
  360.             if (expectsMime) {
  361.             clientOutput.print("HTTP/1.0 200 Document follows\n");
  362.             cf.headerto(clientOutput);
  363.             }
  364.             cf.sendto(clientOutput);
  365.         } else if (u.protocol.equals(defaultContext.protocol) &&
  366.                u.host.equals(defaultContext.host)) {
  367.             /* Local request */
  368.             String fn = u.file;
  369.             Object r = params.applyRules(fn);
  370.             if (fn == null || fn == params.failObject)
  371.             error("Access denied (by rule)");
  372.             else if (r instanceof String) {
  373.             u.file = (String) r;
  374.             getRequest(u, p2);
  375.             } else if (r instanceof ServerPlugin) {
  376.             ((ServerPlugin) r).getRequest(this, u);
  377.             } else {
  378.             error("Can't cope with " + r + " yet\n");
  379.             }
  380.         } else
  381.             getProxyRequest(u, p2);
  382.         } else {
  383.         error("Unknown command: " + k + " (" + cmd + ")");
  384.         return;
  385.         }
  386.     } catch(IOException e) {
  387.         // totally ignore IOException.  Theyre usually client
  388.         // crashes.
  389.         error("IOException: " + e);
  390.     } catch(Exception e) {
  391.         e.printStackTrace();
  392.         error("Exception: " + e);
  393.     }
  394.     }
  395.  
  396.     public static void main(String argv[])
  397.     {
  398.     Server s = new Server (argv);
  399.     try {
  400.         s.startServer(s.params.port);
  401.     } catch(Exception e) {
  402.         e.printStackTrace();
  403.     }
  404.     }
  405. }
  406.