📄 serve.java
字号:
// Serve - minimal Java servlet container class
//
// Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
//
// All enhancments Copyright (C)1998-2007 by Dmitriy Rogatkin
// This version is compatible with JSDK 2.5
// http://tjws.sourceforge.net
// $Id: Serve.java,v 1.112 2007/01/04 00:33:29 rogatkin Exp $
package Acme.Serve;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.Vector;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionContext;
import javax.servlet.SingleThreadModel;
import Acme.Utils;
/// Minimal Java servlet container class.
// <P>
// This class implements a very small embeddable servlet container.
// It runs Servlets compatible with the API used by Sun's
// <A HREF="http://docs.sun.com/app/docs/doc/819-3653">Java System Application </A> server.
// Servlet API can be found <A HREF="http://java.sun.com/products/servlet/">here</A>.
// It comes with default Servlets which provide the usual
// httpd services, returning files and directory listings.
// <P>
// This is not in any sense a competitor for Java System Application server.
// Java System Application server is a full-fledged HTTP server and more.
// Acme.Serve is tiny, about 5000 lines, and provides only the
// functionality necessary to deliver an Applet's .class files
// and then start up a Servlet talking to the Applet.
// They are both written in Java, they are both web servers, and
// they both implement the Servlet API; other than that they couldn't
// be more different.
// <P>
// This is actually the second HTTP server I've written.
// The other one is called
// <A HREF="http://www.acme.com/software/thttpd/">thttpd</A>,
// it's written in C, and is also pretty small although much more
// featureful than this.
// <P>
// Other Java HTTP servers:
// <UL>
// <LI> The above-mentioned <A
// HREF="http://docs.sun.com/app/docs/doc/819-3653">JavaServer</A>.
// <LI> W3C's <A HREF="http://www.w3.org/pub/WWW/Jigsaw/">Jigsaw</A>.
// <LI> David Wilkinson's <A
// HREF="http://www.netlink.co.uk/users/cascade/http/">Cascade</A>.
// <LI> Yahoo's <A
// HREF="http://www.yahoo.com/Computers_and_Internet/Software/Internet/World_Wide_Web/Servers/Java/">list
// of Java web servers</A>.
// </UL>
// <P>
// A <A HREF="http://www.byte.com/art/9706/sec8/art1.htm">June 1997 BYTE
// magazine article</A> mentioning this server.<BR>
// A <A HREF="http://www.byte.com/art/9712/sec6/art7.htm">December 1997 BYTE
// magazine article</A> giving it an Editor's Choice Award of Distinction.<BR>
// <A HREF="/resources/classes/Acme/Serve/Serve.java">Fetch the
// software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
// <P>
// @see Acme.Serve.servlet.http.HttpServlet
// @see FileServlet
// @see CgiServlet
// <h3>Post notes</h3>
// Currently the server 3 more times complex and can compete with
// most popular app and web servers used for deploying of web
// Java applications.
// Inheritance can extend usage of this server
public class Serve implements ServletContext, Serializable {
private static final String progName = "Serve";
public static final String ARG_PORT = "port";
public static final String ARG_THROTTLES = "throttles";
public static final String ARG_SERVLETS = "servlets";
public static final String ARG_REALMS = "realms";
public static final String ARG_ALIASES = "aliases";
public static final String ARG_BINDADDRESS = "bind-address";
public static final String ARG_BACKLOG = "backlog";
public static final String ARG_CGI_PATH = "cgi-path";
public static final String ARG_ERR = "error-stream";
public static final String ARG_OUT = "out-stream";
public static final String ARG_SESSION_TIMEOUT = "session-timeout";
public static final String ARG_LOG_OPTIONS = "log-options";
public static final String ARG_SOCKET_FACTORY = "socketFactory";
public static final String ARG_NOHUP = "nohup";
public static final String ARG_JSP = "JSP";
public static final String ARG_WAR = "war-deployer";
public static final String ARG_KEEPALIVE = "keep-alive";
public static final String DEF_LOGENCODING = "tjws.serve.log.encoding";
public static final String ARG_KEEPALIVE_TIMEOUT = "timeout-keep-alive";
public static final String ARG_MAX_CONN_USE = "max-alive-conn-use";
public static final String ARG_SESSION_PERSIST = "sssn-persistance";
public static final String ARG_MAX_ACTIVE_SESSIONS = "max-active-sessions";
public static final String ARG_ACCESS_LOG_FMT = "access-log-format";
public static final String ARG_THREAD_POOL_SIZE = Utils.ThreadPool.MAXNOTHREAD;
protected static final int DEF_SESSION_TIMEOUT = 30; // in minutes
protected static final int DEF_MIN_ACT_SESS = 10;
public static final int DEF_PORT = 8080;
public static final String BGCOLOR = "BGCOLOR=\"#D1E9FE\"";
/**
* max number of alive connections default value
*/
protected static final int DEF_MAX_CONN_USE = 100;
protected static final String UTF8 = "UTF-8"; // default encoding
// / Main routine, if you want to run this directly as an application.
public static void main(String[] args) {
Map arguments = new HashMap(20);
StringBuffer messages = null;
int argc = args.length;
int argn;
// Parse args.
workPath = System.getProperty("user.dir", ".");
if (argc == 0) { // a try to read from file for java -jar server.jar
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File(workPath, "cmdparams")));
args = Utils.splitStr(br.readLine(), "\"");
argc = args.length;
} catch (Exception e) { // many can happen
if (messages == null)
messages = new StringBuffer(100);
messages.append("Can't read from CLA file ").append(e).append('\n');
} finally {
if (br != null)
try {
br.close();
} catch (IOException ioe) {
}
}
}
// TODO: redesign process of parameters based on a map
for (argn = 0; argn < argc && args[argn].length() > 0 && args[argn].charAt(0) == '-';) {
if (args[argn].equals("-p") && argn + 1 < argc) {
++argn;
arguments.put(ARG_PORT, new Integer(args[argn]));
} else if (args[argn].equals("-t") && argn + 1 < argc) {
++argn;
arguments.put(ARG_THROTTLES, args[argn]);
} else if (args[argn].equals("-s") && argn + 1 < argc) {
++argn;
arguments.put(ARG_SERVLETS, args[argn]);
} else if (args[argn].equals("-r") && argn + 1 < argc) {
++argn;
arguments.put(ARG_REALMS, args[argn]);
} else if (args[argn].equals("-a") && argn + 1 < argc) {
++argn;
arguments.put(ARG_ALIASES, args[argn]);
} else if (args[argn].equals("-b") && argn + 1 < argc) {
++argn;
arguments.put(ARG_BINDADDRESS, args[argn]);
} else if (args[argn].equals("-k") && argn + 1 < argc) {
++argn;
arguments.put(ARG_BACKLOG, args[argn]);
} else if (args[argn].equals("-j") && argn + 1 < argc) {
++argn;
arguments.put(ARG_JSP, args[argn]);
} else if (args[argn].equals("-w") && argn + 1 < argc) {
++argn;
arguments.put(ARG_WAR, args[argn]);
} else if (args[argn].equals("-c") && argn + 1 < argc) {
++argn;
arguments.put(ARG_CGI_PATH, args[argn]);
} else if (args[argn].equals("-mka") && argn + 1 < argc) {
++argn;
arguments.put(ARG_MAX_CONN_USE, args[argn]);
arguments.put(ARG_KEEPALIVE, Boolean.TRUE);
} else if (args[argn].equals("-nka")) {
arguments.put(ARG_KEEPALIVE, Boolean.FALSE);
} else if (args[argn].equals("-sp")) {
arguments.put(ARG_SESSION_PERSIST, Boolean.TRUE);
} else if (args[argn].equals("-kat") && argn + 1 < argc) {
++argn;
arguments.put(ARG_KEEPALIVE_TIMEOUT, args[argn]);
arguments.put(ARG_KEEPALIVE, Boolean.TRUE);
} else if (args[argn].equals("-e") && argn + 1 < argc) {
++argn;
try {
arguments.put(ARG_SESSION_TIMEOUT, new Integer(args[argn]));
} catch (NumberFormatException nfe) {
}
} else if (args[argn].equals("-z") && argn + 1 < argc) {
++argn;
arguments.put(ARG_THREAD_POOL_SIZE, args[argn]);
// backlog will be anyway upper limitation
} else if (args[argn].startsWith("-l")) {
arguments
.put(ARG_ACCESS_LOG_FMT,
"{0}:{9} {1} {2} [{3,date,dd/MMM/yyyy:HH:mm:ss Z}] \"{4} {5} {6}\" {7,number,#} {8,number} {10} {11}");
if (args[argn].length() > 2) {
arguments.put(ARG_LOG_OPTIONS, args[argn].substring(2).toUpperCase());
if (args[argn].indexOf('f') >= 0) {
++argn;
arguments.put(ARG_ACCESS_LOG_FMT, args[argn]);
}
} else
arguments.put(ARG_LOG_OPTIONS, "");
} else if (args[argn].startsWith("-nohup")) {
arguments.put(ARG_NOHUP, ARG_NOHUP);
} else if (args[argn].equals("-m") && argn + 1 < argc) {
++argn;
try {
arguments.put(ARG_MAX_ACTIVE_SESSIONS, new Integer(args[argn]));
if (((Integer) arguments.get(ARG_MAX_ACTIVE_SESSIONS)).intValue() < DEF_MIN_ACT_SESS)
arguments.put(ARG_MAX_ACTIVE_SESSIONS, new Integer(DEF_MIN_ACT_SESS));
} catch (NumberFormatException nfe) {
// ignored
}
} else if (args[argn].equals("-err")) {
if (argn + 1 < argc && args[argn + 1].startsWith("-") == false) {
++argn;
try {
arguments.put(ARG_ERR, (PrintStream) Class.forName(args[argn]).newInstance());
} catch (Error er) {
if (messages == null)
messages = new StringBuffer(100);
messages.append("Problem of processing class parameter of error redirection stream: ").append(
er).append('\n');
} catch (Exception ex) {
if (messages == null)
messages = new StringBuffer(100);
messages.append("Exception in processing class parameter of error redirection stream: ")
.append(ex).append('\n');
}
} else
arguments.put(ARG_ERR, System.err);
} else if (args[argn].equals("-out")) {
if (argn + 1 < argc && args[argn + 1].startsWith("-") == false) {
++argn;
try {
arguments.put(ARG_OUT, (PrintStream) Class.forName(args[argn]).newInstance());
} catch (Error er) {
if (messages == null)
messages = new StringBuffer(100);
messages.append("Problem of processing class parameter of out redirection stream: ").append(er)
.append('\n');
} catch (Exception ex) {
if (messages == null)
messages = new StringBuffer(100);
messages.append("Exception in processing class parameter of out redirection stream: ").append(
ex).append('\n');
}
}
} else if (args[argn].startsWith("-")) { // free args, note it generate problem since free arguments can match internal arguments
if (args[argn].length() > 1)
arguments.put(args[argn].substring(1),// .toUpperCase(),
argn < argc - 1 ? args[++argn] : "");
} else
usage();
++argn;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -