Source Code Cross Referenced for Serve.java in  » Web-Server » Acme-WebServer » Acme » Serve » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Server » Acme WebServer » Acme.Serve 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Serve - minimal Java HTTP server class
0002:        //
0003:        // Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.
0004:        //
0005:        // Redistribution and use in source and binary forms, with or without
0006:        // modification, are permitted provided that the following conditions
0007:        // are met:
0008:        // 1. Redistributions of source code must retain the above copyright
0009:        //    notice, this list of conditions and the following disclaimer.
0010:        // 2. Redistributions in binary form must reproduce the above copyright
0011:        //    notice, this list of conditions and the following disclaimer in the
0012:        //    documentation and/or other materials provided with the distribution.
0013:        //
0014:        // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0015:        // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0016:        // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0017:        // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0018:        // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0019:        // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0020:        // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0021:        // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0022:        // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0023:        // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0024:        // SUCH DAMAGE.
0025:        //
0026:        // Visit the ACME Labs Java page for up-to-date versions of this and other
0027:        // fine Java utilities: http://www.acme.com/java/
0028:        //
0029:
0030:        // All enhancments Copyright (C)1998-2002 by Dmitriy Rogatkin
0031:        // this version is compatible with JSDK 2.3
0032:        // http://tjws.sourceforge.net
0033:        // $Id: Serve.java,v 1.1 2004/09/08 22:00:24 drogatkin Exp $
0034:
0035:        package Acme.Serve;
0036:
0037:        import java.io.*;
0038:        import java.util.*;
0039:        import java.net.*;
0040:        import java.text.*;
0041:        import javax.servlet.*;
0042:        import javax.servlet.http.*;
0043:
0044:        /// Minimal Java HTTP server class.
0045:        // <P>
0046:        // This class implements a very small embeddable HTTP server.
0047:        // It runs Servlets compatible with the API used by JavaSoft's
0048:        // <A HREF="http://java.sun.com/products/java-server/">JavaServer</A> server.
0049:        // It comes with default Servlets which provide the usual
0050:        // httpd services, returning files and directory listings.
0051:        // <P>
0052:        // This is not in any sense a competitor for JavaServer.
0053:        // JavaServer is a full-fledged HTTP server and more.
0054:        // Acme.Serve is tiny, about 1500 lines, and provides only the
0055:        // functionality necessary to deliver an Applet's .class files
0056:        // and then start up a Servlet talking to the Applet.
0057:        // They are both written in Java, they are both web servers, and
0058:        // they both implement the Servlet API; other than that they couldn't
0059:        // be more different.
0060:        // <P>
0061:        // This is actually the second HTTP server I've written.
0062:        // The other one is called
0063:        // <A HREF="http://www.acme.com/software/thttpd/">thttpd</A>,
0064:        // it's written in C, and is also pretty small although much more
0065:        // featureful than this.
0066:        // <P>
0067:        // Other Java HTTP servers:
0068:        // <UL>
0069:        // <LI> The above-mentioned <A HREF="http://java.sun.com/products/java-server/">JavaServer</A>.
0070:        // <LI> W3C's <A HREF="http://www.w3.org/pub/WWW/Jigsaw/">Jigsaw</A>.
0071:        // <LI> David Wilkinson's <A HREF="http://www.netlink.co.uk/users/cascade/http/">Cascade</A>.
0072:        // <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>.
0073:        // </UL>
0074:        // <P>
0075:        // A <A HREF="http://www.byte.com/art/9706/sec8/art1.htm">June 1997 BYTE magazine article</A> mentioning this server.<BR>
0076:        // 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>
0077:        // <A HREF="/resources/classes/Acme/Serve/Serve.java">Fetch the software.</A><BR>
0078:        // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
0079:        // <P>
0080:        // @see Acme.Serve.servlet.http.HttpServlet
0081:        // @see FileServlet
0082:        // @see CgiServlet
0083:
0084:        // make it final?
0085:        public class Serve implements  ServletContext, RequestDispatcher {
0086:
0087:            private static final String progName = "Serve";
0088:            public static final String ARG_PORT = "port";
0089:            public static final String ARG_THROTTLES = "throttles";
0090:            public static final String ARG_SERVLETS = "servlets";
0091:            public static final String ARG_REALMS = "realms";
0092:            public static final String ARG_ALIASES = "aliases";
0093:            public static final String ARG_CGI_PATH = "cgi-path";
0094:            public static final String ARG_SESSION_TIMEOUT = "session-timeout";
0095:            public static final String ARG_LOG_OPTIONS = "log-options";
0096:            public static final String ARG_SOCKET_FACTORY = "socketFactory";
0097:
0098:            protected static final int DEF_SESSION_TIMEOUT = 30; // in minutes
0099:            protected static final int DEF_PORT = 9090;
0100:
0101:            /// Main routine, if you want to run this directly as an application.
0102:            public static void main(String[] args) {
0103:                Hashtable arguments = new Hashtable(20);
0104:
0105:                int argc = args.length;
0106:                int argn;
0107:                // Parse args.
0108:                if (argc == 0) // a try to read from file for java -jar server.jar
0109:                    try {
0110:                        BufferedReader br = new BufferedReader(new FileReader(
0111:                                "cmdparams"));
0112:                        StringTokenizer st = new StringTokenizer(br.readLine(),
0113:                                " ");
0114:                        args = new String[st.countTokens()];
0115:                        argc = args.length; // tail can be nulled
0116:                        for (int i = 0; i < argc && st.hasMoreTokens(); i++)
0117:                            args[i] = st.nextToken();
0118:                    } catch (Exception e) { // many can happen
0119:                    }
0120:                for (argn = 0; argn < argc && args[argn].charAt(0) == '-';) {
0121:                    if (args[argn].equals("-p") && argn + 1 < argc) {
0122:                        ++argn;
0123:                        arguments.put(ARG_PORT, new Integer(args[argn]));
0124:                    } else if (args[argn].equals("-t") && argn + 1 < argc) {
0125:                        ++argn;
0126:                        arguments.put(ARG_THROTTLES, args[argn]);
0127:                    } else if (args[argn].equals("-s") && argn + 1 < argc) {
0128:                        ++argn;
0129:                        arguments.put(ARG_SERVLETS, args[argn]);
0130:                    } else if (args[argn].equals("-r") && argn + 1 < argc) {
0131:                        ++argn;
0132:                        arguments.put(ARG_REALMS, args[argn]);
0133:                    } else if (args[argn].equals("-a") && argn + 1 < argc) {
0134:                        ++argn;
0135:                        arguments.put(ARG_ALIASES, args[argn]);
0136:                    } else if (args[argn].equals("-c") && argn + 1 < argc) {
0137:                        ++argn;
0138:                        arguments.put(ARG_CGI_PATH, args[argn]);
0139:                    } else if (args[argn].equals("-e") && argn + 1 < argc) {
0140:                        ++argn;
0141:                        try {
0142:                            arguments.put(ARG_SESSION_TIMEOUT, new Integer(
0143:                                    args[argn]));
0144:                        } catch (NumberFormatException nfe) {
0145:                        }
0146:                    } else if (args[argn].startsWith("-l")) {
0147:                        if (args[argn].length() > 2)
0148:                            arguments.put(ARG_LOG_OPTIONS, args[argn]
0149:                                    .substring(2).toUpperCase());
0150:                        else
0151:                            arguments.put(ARG_LOG_OPTIONS, "");
0152:                    } else if (args[argn].startsWith("-")) {
0153:                        if (args[argn].length() > 1)
0154:                            arguments.put(args[argn].substring(1),//.toUpperCase(),
0155:                                    argn < argc - 1 ? args[++argn] : "");
0156:                    } else
0157:                        usage();
0158:
0159:                    ++argn;
0160:                }
0161:                if (argn != argc)
0162:                    usage();
0163:                /** format path mapping
0164:                from=givenpath;dir=realpath
0165:                 */
0166:                PrintStream printstream = System.err;
0167:                try {
0168:                    printstream = new PrintStream(new FileOutputStream("AWS-"
0169:                            + System.currentTimeMillis() + ".log"), true);
0170:                    System.setErr(printstream);
0171:                } catch (IOException e) {
0172:                    System.err.println("IO problem at setting a log stream "
0173:                            + e);
0174:                }
0175:                PathTreeDictionary mappingtable = new PathTreeDictionary();
0176:                if (arguments.get(ARG_ALIASES) != null) {
0177:                    File file = new File((String) arguments.get(ARG_ALIASES));
0178:                    if (file.exists() && file.canRead()) {
0179:                        try {
0180:                            DataInputStream in = new DataInputStream(
0181:                                    new FileInputStream(file));
0182:                            do {
0183:                                String mappingstr = in.readLine();
0184:                                if (mappingstr == null)
0185:                                    break;
0186:                                StringTokenizer maptokenzr = new StringTokenizer(
0187:                                        mappingstr, "=;");
0188:                                if (maptokenzr.hasMoreTokens()) {
0189:                                    if (maptokenzr.nextToken("=")
0190:                                            .equalsIgnoreCase("from")) {
0191:                                        if (maptokenzr.hasMoreTokens()) {
0192:                                            String srcpath = maptokenzr
0193:                                                    .nextToken("=;");
0194:                                            if (maptokenzr.hasMoreTokens()
0195:                                                    && maptokenzr.nextToken(
0196:                                                            ";=")
0197:                                                            .equalsIgnoreCase(
0198:                                                                    "dir"))
0199:                                                try {
0200:                                                    if (maptokenzr
0201:                                                            .hasMoreTokens())
0202:                                                        mappingtable
0203:                                                                .put(
0204:                                                                        srcpath,
0205:                                                                        maptokenzr
0206:                                                                                .nextToken());
0207:                                                } catch (NullPointerException e) {
0208:                                                }
0209:                                        }
0210:                                    }
0211:                                }
0212:                            } while (true);
0213:                        } catch (IOException e) {
0214:                            System.err.println("Problem reading aliases file: "
0215:                                    + arguments.get(ARG_ALIASES) + "/" + e);
0216:                        }
0217:                    } else
0218:                        System.err.println("FIle " + arguments.get(ARG_ALIASES)
0219:                                + " doesn't exist or not readable.");
0220:                }
0221:                /** format realmname=path,user:password,,,,
0222:                 */
0223:                PathTreeDictionary realms = new PathTreeDictionary();
0224:                if (arguments.get(ARG_REALMS) != null) {
0225:                    try {
0226:                        DataInputStream in = new DataInputStream(
0227:                                new FileInputStream((String) arguments
0228:                                        .get(ARG_REALMS)));
0229:
0230:                        do {
0231:                            String realmstr = in.readLine();
0232:                            if (realmstr == null)
0233:                                break;
0234:                            StringTokenizer rt = new StringTokenizer(realmstr,
0235:                                    "=,:");
0236:                            String realmname = null;
0237:                            BasicAuthRealm realm = null;
0238:                            if (rt.hasMoreTokens())
0239:                                realmname = rt.nextToken();
0240:                            else
0241:                                continue;
0242:                            if (rt.hasMoreTokens()) {
0243:                                realm = new BasicAuthRealm(realmname);
0244:                                realms.put(rt.nextToken(), realm);
0245:                            } else
0246:                                continue;
0247:                            if (rt.hasMoreTokens()) {
0248:                                String user = rt.nextToken();
0249:                                if (rt.hasMoreTokens())
0250:                                    realm.put(user, rt.nextToken());
0251:                            }
0252:                        } while (true);
0253:                    } catch (IOException ioe) {
0254:                        System.err.println("Problem in reading realms file "
0255:                                + arguments.get(ARG_REALMS) + "/ " + ioe);
0256:                    }
0257:                }
0258:
0259:                // Create the server.
0260:                final Serve serve = new Serve(arguments, printstream);
0261:                final String cf = (String) arguments.get(ARG_SERVLETS);
0262:                serve.setMappingTable(mappingtable);
0263:                serve.setRealms(realms);
0264:
0265:                new Thread(new Runnable() {
0266:                    public void run() {
0267:                        serve.readServlets(cf);
0268:                    }
0269:                }).start();
0270:                // And add the standard Servlets.
0271:                String throttles = (String) arguments.get(ARG_THROTTLES);
0272:                if (throttles == null)
0273:                    serve.addDefaultServlets((String) arguments
0274:                            .get(ARG_CGI_PATH));
0275:                else
0276:                    try {
0277:                        serve.addDefaultServlets((String) arguments
0278:                                .get(ARG_CGI_PATH), throttles);
0279:                    } catch (IOException e) {
0280:                        System.err.println("Problem reading throttles file: "
0281:                                + e);
0282:                        System.exit(1);
0283:                    }
0284:
0285:                // And run.
0286:                serve.serve();
0287:
0288:                System.exit(0);
0289:            }
0290:
0291:            private static void usage() {
0292:                System.err
0293:                        .println("usage:  "
0294:                                + progName
0295:                                + " [-p port] [-s servletpropertiesfile] [-a aliasmappingfile] [-l[a][r]] [-c cgi-bin-dir] [-e [-]duration_in_minutes] [-socketFactory class name and other parameters}");
0296:                System.exit(1);
0297:            }
0298:
0299:            private void readServlets(String cfgfile) {
0300:                /** servlet.properties file format
0301:                servlet.<servletname>.code=<servletclass>
0302:                servlet.<servletname>.initArgs=<name=value>,<name=value>
0303:                 */
0304:                Hashtable servletstbl, parameterstbl;
0305:                servletstbl = new Hashtable();
0306:                parameterstbl = new Hashtable();
0307:                if (cfgfile != null) {
0308:                    File file = new File(cfgfile);
0309:                    if (file.exists() && file.canRead()) {
0310:                        try {
0311:                            DataInputStream in = new DataInputStream(
0312:                                    new FileInputStream(file));
0313:                            /** format of servlet.cfg file
0314:                            servlet_name;servlet_class;init_parameter1=value1;init_parameter2=value2...
0315:                             */
0316:                            do {
0317:                                String servletdsc = in.readLine();
0318:                                if (servletdsc == null)
0319:                                    break;
0320:                                StringTokenizer dsctokenzr = new StringTokenizer(
0321:                                        servletdsc, ".=,", false);
0322:                                if (dsctokenzr.hasMoreTokens()) {
0323:                                    if (!dsctokenzr.nextToken()
0324:                                            .equalsIgnoreCase("servlet")) {
0325:                                        System.err
0326:                                                .println("No leading 'servlet' keyword, the sentence is skipped");
0327:                                        break;
0328:                                    }
0329:                                    if (dsctokenzr.hasMoreTokens()) {
0330:                                        String servletname = dsctokenzr
0331:                                                .nextToken();
0332:
0333:                                        if (dsctokenzr.hasMoreTokens()) {
0334:                                            String lt = dsctokenzr.nextToken();
0335:                                            if (lt.equalsIgnoreCase("code")) {
0336:                                                if (dsctokenzr.hasMoreTokens())
0337:                                                    servletstbl
0338:                                                            .put(
0339:                                                                    servletname,
0340:                                                                    dsctokenzr
0341:                                                                            .nextToken("="));
0342:                                            } else if (lt
0343:                                                    .equalsIgnoreCase("initArgs")) {
0344:                                                Hashtable initparams = new Hashtable();
0345:                                                while (dsctokenzr
0346:                                                        .hasMoreTokens()) {
0347:                                                    String key = dsctokenzr
0348:                                                            .nextToken("=,");
0349:                                                    if (dsctokenzr
0350:                                                            .hasMoreTokens())
0351:                                                        initparams
0352:                                                                .put(
0353:                                                                        key,
0354:                                                                        dsctokenzr
0355:                                                                                .nextToken(",="));
0356:                                                }
0357:                                                parameterstbl.put(servletname,
0358:                                                        initparams);
0359:                                            } else
0360:                                                System.err
0361:                                                        .println("Unrecognized token "
0362:                                                                + lt
0363:                                                                + " in "
0364:                                                                + servletdsc
0365:                                                                + ", the line's skipped");
0366:                                        }
0367:                                    }
0368:                                }
0369:                            } while (true);
0370:                        } catch (IOException e) {
0371:                            System.err
0372:                                    .println("Problem reading cfg file: " + e);
0373:                        }
0374:                        Enumeration se = servletstbl.keys();
0375:                        String servletname;
0376:                        while (se.hasMoreElements()) {
0377:                            servletname = (String) se.nextElement();
0378:                            addServlet(servletname, (String) servletstbl
0379:                                    .get(servletname),
0380:                                    (Hashtable) parameterstbl.get(servletname));
0381:                        }
0382:                    }
0383:                }
0384:            }
0385:
0386:            int port;
0387:            String hostName;
0388:            private PrintStream logStream;
0389:            private boolean useAccLog;
0390:            private boolean showUserAgent;
0391:            private boolean showReferer;
0392:            protected PathTreeDictionary registry;
0393:            protected PathTreeDictionary realms;
0394:            private PathTreeDictionary mappingtable;
0395:            private Hashtable attributes;
0396:            sun.misc.BASE64Decoder base64Dec = new sun.misc.BASE64Decoder();
0397:            // for sessions
0398:            int uniqer;
0399:            HttpSessionContextImpl sessions;
0400:            static int expiredIn;
0401:            protected Hashtable arguments;
0402:
0403:            /// Constructor.
0404:            public Serve(Hashtable arguments, PrintStream logStream) {
0405:                this .arguments = arguments;
0406:                this .logStream = logStream;
0407:                registry = new PathTreeDictionary();
0408:                realms = new PathTreeDictionary();
0409:                attributes = new Hashtable();
0410:                sessions = new HttpSessionContextImpl();
0411:                setAccessLogged();
0412:                expiredIn = arguments.get(ARG_SESSION_TIMEOUT) != null ? ((Integer) arguments
0413:                        .get(ARG_SESSION_TIMEOUT)).intValue()
0414:                        : DEF_SESSION_TIMEOUT;
0415:                port = arguments.get(ARG_PORT) != null ? ((Integer) arguments
0416:                        .get(ARG_PORT)).intValue() : DEF_PORT;
0417:            }
0418:
0419:            public Serve() {
0420:                this (new Hashtable(), System.err);
0421:            }
0422:
0423:            void setAccessLogged() {
0424:                String logflags = (String) arguments.get(ARG_LOG_OPTIONS);
0425:                if (logflags != null) {
0426:                    useAccLog = true;
0427:                    showUserAgent = logflags.indexOf('A') >= 0;
0428:                    showReferer = logflags.indexOf('R') >= 0;
0429:                }
0430:            }
0431:
0432:            boolean isAccessLogged() {
0433:                return useAccLog;
0434:            }
0435:
0436:            boolean isShowReferer() {
0437:                return showReferer;
0438:            }
0439:
0440:            boolean isShowUserAgent() {
0441:                return showUserAgent;
0442:            }
0443:
0444:            /// Register a Servlet by class name.  Registration consists of a URL
0445:            // pattern, which can contain wildcards, and the class name of the Servlet
0446:            // to launch when a matching URL comes in.  Patterns are checked for
0447:            // matches in the order they were added, and only the first match is run.
0448:            public void addServlet(String urlPat, String className) {
0449:                addServlet(urlPat, className, (Hashtable) null);
0450:            }
0451:
0452:            public void addServlet(String urlPat, String className,
0453:                    Hashtable initParams) {
0454:                // Check if we're allowed to make one of these.
0455:                SecurityManager security = System.getSecurityManager();
0456:                if (security != null) {
0457:                    int i = className.lastIndexOf('.');
0458:                    if (i != -1) {
0459:                        security.checkPackageAccess(className.substring(0, i));
0460:                        security.checkPackageDefinition(className.substring(0,
0461:                                i));
0462:                    }
0463:                }
0464:
0465:                // Make a new one.
0466:                try {
0467:                    addServlet(urlPat, (Servlet) Class.forName(className)
0468:                            .newInstance(), initParams);
0469:                    return;
0470:                } catch (ClassNotFoundException e) {
0471:                    log("Class not found: " + className);
0472:                } catch (ClassCastException e) {
0473:                    log("Class cast problem: " + e.getMessage());
0474:                } catch (InstantiationException e) {
0475:                    log("Instantiation problem: " + e.getMessage());
0476:                } catch (IllegalAccessException e) {
0477:                    log("Illegal class access: " + e.getMessage());
0478:                } catch (Exception e) {
0479:                    log("Unexpected problem creating servlet: " + e, e);
0480:                }
0481:            }
0482:
0483:            /// Register a Servlet.  Registration consists of a URL pattern,
0484:            // which can contain wildcards, and the Servlet to
0485:            // launch when a matching URL comes in.  Patterns are checked for
0486:            // matches in the order they were added, and only the first match is run.
0487:            public void addServlet(String urlPat, Servlet servlet) {
0488:                addServlet(urlPat, servlet, (Hashtable) null);
0489:            }
0490:
0491:            public void addServlet(String urlPat, Servlet servlet,
0492:                    Hashtable initParams) {
0493:                try {
0494:                    servlet.init(new ServeConfig((ServletContext) this ,
0495:                            initParams, urlPat));
0496:                    registry.put(urlPat, servlet);
0497:                } catch (ServletException e) {
0498:                    log("Problem initializing servlet: " + e);
0499:                }
0500:            }
0501:
0502:            /// Register a standard set of Servlets.  These will return
0503:            // files or directory listings, and run CGI programs, much like a
0504:            // standard HTTP server.
0505:            // <P>
0506:            // Because of the pattern checking order, this should be called
0507:            // <B>after</B> you've added any custom Servlets.
0508:            // <P>
0509:            // The current set of default servlet mappings:
0510:            // <UL>
0511:            // <LI> If enabled, *.cgi goes to CgiServlet, and gets run as a CGI program.
0512:            // <LI> * goes to FileServlet, and gets served up as a file or directory.
0513:            // </UL>
0514:            // @param cgi whether to run CGI programs
0515:            // TODO: provide user specified CGI directory
0516:            public void addDefaultServlets(String cgi) {
0517:                if (cgi != null)
0518:                    addServlet("/" + cgi, new Acme.Serve.CgiServlet());
0519:                addServlet("/", new Acme.Serve.FileServlet());
0520:            }
0521:
0522:            /// Register a standard set of Servlets, with throttles.
0523:            // @param cgi whether to run CGI programs
0524:            // @param throttles filename to read FileServlet throttle settings from
0525:            public void addDefaultServlets(String cgi, String throttles)
0526:                    throws IOException {
0527:                if (cgi != null)
0528:                    addServlet("/" + cgi, new Acme.Serve.CgiServlet());
0529:                addServlet("/", new Acme.Serve.FileServlet(throttles));
0530:            }
0531:
0532:            // Run the server.  Returns only on errors.
0533:            boolean running = true;
0534:
0535:            public void serve() {
0536:                final ServerSocket serverSocket;
0537:                try {
0538:                    serverSocket = createServerSocket();
0539:                } catch (IOException e) {
0540:                    log("Server socket: " + e);
0541:                    return;
0542:                }
0543:                hostName = serverSocket.getInetAddress().getHostName();
0544:                new Thread(new Runnable() {
0545:                    public void run() {
0546:                        BufferedReader in = new BufferedReader(
0547:                                new InputStreamReader(System.in));
0548:                        String line;
0549:                        while (true) {
0550:                            try {
0551:                                System.out
0552:                                        .print("Press \"q\" <ENTER>, for gracefully stopping the server ");
0553:                                line = in.readLine();
0554:                                if (line != null && line.length() > 0
0555:                                        && line.charAt(0) == 'q') {
0556:                                    running = false;
0557:                                    serverSocket.close();
0558:                                    break;
0559:                                }
0560:                            } catch (IOException e) {
0561:                            }
0562:                        }
0563:                    }
0564:                }, "Stop Monitor").start();
0565:                if (expiredIn > 0) {
0566:                    Thread t = new Thread(new Runnable() {
0567:                        public void run() {
0568:                            while (running) {
0569:                                try {
0570:                                    Thread.sleep(expiredIn * 60 * 1000);
0571:                                } catch (InterruptedException ie) {
0572:                                }
0573:                                Enumeration e = sessions.keys();
0574:                                while (e.hasMoreElements()) {
0575:                                    Object sid = e.nextElement();
0576:                                    if (sid != null) {
0577:                                        AcmeSession as = (AcmeSession) sessions
0578:                                                .get(sid);
0579:                                        if (as != null
0580:                                                && (as.getMaxInactiveInterval() * 1000 < System
0581:                                                        .currentTimeMillis()
0582:                                                        - as
0583:                                                                .getLastAccessedTime() || !as
0584:                                                        .isValid())) { //log("sesion is timeouted, last accessed " + new Date(as.getLastAccessedTime()));
0585:                                            // hashtable is synchronized impl
0586:                                            as = (AcmeSession) sessions
0587:                                                    .remove(sid);
0588:                                            if (as != null && as.isValid())
0589:                                                try {
0590:                                                    as.invalidate();
0591:                                                } catch (IllegalStateException ise) {
0592:
0593:                                                }
0594:                                        }
0595:                                    }
0596:                                }
0597:                            }
0598:                        }
0599:                    }, "Session cleaner");
0600:                    t.setPriority(Thread.MIN_PRIORITY);
0601:                    t.start();
0602:                } else
0603:                    expiredIn = -expiredIn;
0604:                System.out.println("WebServer :" + port + " is ready.");
0605:                try {
0606:                    while (running) {
0607:                        Socket socket = serverSocket.accept();
0608:                        new ServeConnection(socket, this );
0609:                    }
0610:                } catch (IOException e) {
0611:                    log("Accept: " + e);
0612:                } finally {
0613:                    try {
0614:                        serverSocket.close();
0615:                    } catch (IOException e) {
0616:                    }
0617:                    destroyAllServlets();
0618:                }
0619:            }
0620:
0621:            public static interface SocketFactory {
0622:                public ServerSocket createSocket(Hashtable arguments)
0623:                        throws IOException, IllegalArgumentException;
0624:            }
0625:
0626:            protected ServerSocket createServerSocket() throws IOException {
0627:                String socketFactoryClass = (String) arguments
0628:                        .get(ARG_SOCKET_FACTORY);
0629:                if (socketFactoryClass != null)
0630:                    try {
0631:                        return ((SocketFactory) Class.forName(
0632:                                socketFactoryClass).newInstance())
0633:                                .createSocket(arguments);
0634:                    } catch (Exception e) {
0635:                        System.err
0636:                                .println("Couldn't create custom socket factory "
0637:                                        + socketFactoryClass
0638:                                        + " or call creation method. Standard socket will be created. "
0639:                                        + e);
0640:                    }
0641:                return new ServerSocket(port, 1000);
0642:            }
0643:
0644:            // Methods from ServletContext.
0645:
0646:            /// Gets a servlet by name.
0647:            // @param name the servlet name
0648:            // @return null if the servlet does not exist
0649:            public Servlet getServlet(String name) {
0650:                try {
0651:                    return (Servlet) ((Object[]) registry.get(name))[0];
0652:                } catch (NullPointerException npe) {
0653:                    return null;
0654:                }
0655:            }
0656:
0657:            /// Enumerates the servlets in this context (server). Only servlets that
0658:            // are accesible will be returned.  This enumeration always includes the
0659:            // servlet itself.
0660:            public Enumeration getServlets() {
0661:                return registry.elements();
0662:            }
0663:
0664:            /// Enumerates the names of the servlets in this context (server). Only
0665:            // servlets that are accesible will be returned.  This enumeration always
0666:            // includes the servlet itself.
0667:            public Enumeration getServletNames() {
0668:                return registry.keys();
0669:            }
0670:
0671:            /// Destroys all currently-loaded servlets.
0672:            public void destroyAllServlets() {
0673:                Enumeration en = registry.elements();
0674:                while (en.hasMoreElements()) {
0675:                    Servlet servlet = (Servlet) en.nextElement();
0676:                    servlet.destroy();
0677:                }
0678:                registry = new PathTreeDictionary();
0679:                // invalidate all sessions?
0680:            }
0681:
0682:            public void setMappingTable(PathTreeDictionary mappingtable) {
0683:                this .mappingtable = mappingtable;
0684:            }
0685:
0686:            public void setRealms(PathTreeDictionary realms) {
0687:                this .realms = realms;
0688:            }
0689:
0690:            Object getSession(String id) {
0691:                return sessions.get(id);
0692:            }
0693:
0694:            HttpSession createSession() {
0695:                HttpSession result = new AcmeSession(generateSessionId(),
0696:                        expiredIn * 60, this , sessions);
0697:                sessions.put(result.getId(), result);
0698:                return result;
0699:            }
0700:
0701:            void removeSession(String id) {
0702:                sessions.remove(id);
0703:            }
0704:
0705:            /// Write information to the servlet log.
0706:            // @param message the message to log
0707:            public void log(String message) {
0708:                Date date = new Date(System.currentTimeMillis());
0709:                logStream.println("[" + date.toString() + "] " + message);
0710:            }
0711:
0712:            public void log(String message, Throwable throwable) {
0713:                StringWriter sw = new StringWriter();
0714:                throwable.printStackTrace(new PrintWriter(sw));
0715:                log(message + '\n' + sw);
0716:            }
0717:
0718:            /// Write a stack trace to the servlet log.
0719:            // @param exception where to get the stack trace
0720:            // @param message the message to log
0721:            public void log(Exception exception, String message) {
0722:                StringWriter sw = new StringWriter();
0723:                exception.printStackTrace(new PrintWriter(sw));
0724:                log("" + sw + '\n' + message);
0725:            }
0726:
0727:            /// Applies alias rules to the specified virtual path and returns the
0728:            // corresponding real path.  It returns null if the translation
0729:            // cannot be performed.
0730:            // @param path the path to be translated
0731:            public String getRealPath(String path) {
0732:                //System.err.print("["+path+"]->[");
0733:                try { // this code only for debug purpose
0734:                    // check if it absolute URL
0735:                    URL url = new URL(path);
0736:                    path = url.getFile();
0737:                    new Exception("URL " + path + " specified in getRealPath")
0738:                            .printStackTrace();
0739:                    path = null;
0740:                } catch (MalformedURLException mfue) {
0741:                }
0742:                if (mappingtable != null) {
0743:                    // try find first sub-path
0744:                    Object[] os = mappingtable.get(path);
0745:                    if (os[0] == null)
0746:                        return null;
0747:                    int slpos = ((Integer) os[1]).intValue();
0748:                    if (path.length() > slpos && slpos > 0) {
0749:                        path = path.substring(slpos + 1);
0750:                    } else if (path.length() > 0) {
0751:                        char s = path.charAt(0);
0752:                        if (s == '/' || s == '\\')
0753:                            path = path.substring(1);
0754:                    }
0755:                    //System.err.println("Base:"+((String)os[0])+"\npath="+path+"\n pos="+slpos+']');
0756:
0757:                    return ((String) os[0]) + File.separatorChar + path;
0758:                }
0759:                return path;
0760:            }
0761:
0762:            /// Returns the MIME type of the specified file.
0763:            // @param file file name whose MIME type is required
0764:            public String getMimeType(String file) {
0765:                file = file.toUpperCase();
0766:
0767:                if (file.endsWith(".HTML") || file.endsWith(".HTM"))
0768:                    return "text/html";
0769:                if (file.endsWith(".TXT"))
0770:                    return "text/plain";
0771:                if (file.endsWith(".XML"))
0772:                    return "text/xml";
0773:                if (file.endsWith(".CSS"))
0774:                    return "text/css";
0775:                if (file.endsWith(".SGML") || file.endsWith(".SGM"))
0776:                    return "text/x-sgml";
0777:                // Image
0778:                if (file.endsWith(".GIF"))
0779:                    return "image/gif";
0780:                if (file.endsWith(".JPG") || file.endsWith(".JPEG")
0781:                        || file.endsWith(".JPE"))
0782:                    return "image/jpeg";
0783:                if (file.endsWith(".PNG"))
0784:                    return "image/png";
0785:                if (file.endsWith(".TIF") || file.endsWith(".TIFF"))
0786:                    return "image/tiff";
0787:                if (file.endsWith(".RGB"))
0788:                    return "image/x-rgb";
0789:                if (file.endsWith(".XPM"))
0790:                    return "image/x-xpixmap";
0791:                if (file.endsWith(".XBM"))
0792:                    return "image/x-xbitmap";
0793:                if (file.endsWith(".SVG"))
0794:                    return "image/svg-xml ";
0795:                if (file.endsWith(".SVGZ"))
0796:                    return "image/svg-xml ";
0797:                // Audio
0798:                if (file.endsWith(".AU") || file.endsWith(".SND"))
0799:                    return "audio/basic";
0800:                if (file.endsWith(".MID") || file.endsWith(".MIDI")
0801:                        || file.endsWith(".RMI") || file.endsWith(".KAR"))
0802:                    return "audio/mid";
0803:                if (file.endsWith(".MPGA") || file.endsWith(".MP2")
0804:                        || file.endsWith(".MP3"))
0805:                    return "audio/mpeg";
0806:                if (file.endsWith(".WAV"))
0807:                    return "audio/wav";
0808:                if (file.endsWith(".AIFF") || file.endsWith(".AIFC"))
0809:                    return "audio/aiff";
0810:                if (file.endsWith(".AIF"))
0811:                    return "audio/x-aiff";
0812:                if (file.endsWith(".RA"))
0813:                    return "audio/x-realaudio";
0814:                if (file.endsWith(".RPM"))
0815:                    return "audio/x-pn-realaudio-plugin";
0816:                if (file.endsWith(".RAM"))
0817:                    return "audio/x-pn-realaudio";
0818:                if (file.endsWith(".SD2"))
0819:                    return "audio/x-sd2";
0820:                // Application
0821:                if (file.endsWith(".BIN") || file.endsWith(".DMS")
0822:                        || file.endsWith(".LHA") || file.endsWith(".LZH")
0823:                        || file.endsWith(".EXE") || file.endsWith(".CLASS"))
0824:                    return "application/octet-stream";
0825:                if (file.endsWith(".HQX"))
0826:                    return "application/mac-binhex40";
0827:                if (file.endsWith(".PS") || file.endsWith(".AI")
0828:                        || file.endsWith(".EPS"))
0829:                    return "application/postscript";
0830:                if (file.endsWith(".PDF"))
0831:                    return "application/pdf";
0832:                if (file.endsWith(".RTF"))
0833:                    return "application/rtf";
0834:                if (file.endsWith(".DOC"))
0835:                    return "application/msword";
0836:                if (file.endsWith(".PPT"))
0837:                    return "application/powerpoint";
0838:                if (file.endsWith(".FIF"))
0839:                    return "application/fractals";
0840:                if (file.endsWith(".P7C"))
0841:                    return "application/pkcs7-mime";
0842:                // Application/x
0843:                if (file.endsWith(".JS"))
0844:                    return "application/x-javascript";
0845:                if (file.endsWith(".Z"))
0846:                    return "application/x-compress";
0847:                if (file.endsWith(".GZ"))
0848:                    return "application/x-gzip";
0849:                if (file.endsWith(".TAR"))
0850:                    return "application/x-tar";
0851:                if (file.endsWith(".TGZ"))
0852:                    return "application/x-compressed";
0853:                if (file.endsWith(".ZIP"))
0854:                    return "application/x-zip-compressed";
0855:                if (file.endsWith(".DIR") || file.endsWith(".DCR")
0856:                        || file.endsWith(".DXR"))
0857:                    return "application/x-director";
0858:                if (file.endsWith(".DVI"))
0859:                    return "application/x-dvi";
0860:                if (file.endsWith(".TEX"))
0861:                    return "application/x-tex";
0862:                if (file.endsWith(".LATEX"))
0863:                    return "application/x-latex";
0864:                if (file.endsWith(".TCL"))
0865:                    return "application/x-tcl";
0866:                if (file.endsWith(".CER") || file.endsWith(".CRT")
0867:                        || file.endsWith(".DER"))
0868:                    return "application/x-x509-ca-cert";
0869:                // Video
0870:                if (file.endsWith(".MPG") || file.endsWith(".MPE")
0871:                        || file.endsWith(".MPEG"))
0872:                    return "video/mpeg";
0873:                if (file.endsWith(".QT") || file.endsWith(".MOV"))
0874:                    return "video/quicktime";
0875:                if (file.endsWith(".AVI"))
0876:                    return "video/x-msvideo";
0877:                if (file.endsWith(".MOVIE"))
0878:                    return "video/x-sgi-movie";
0879:                // Chemical
0880:                if (file.endsWith(".PDB") || file.endsWith(".XYZ"))
0881:                    return "chemical/x-pdb";
0882:                // X-
0883:                if (file.endsWith(".ICE"))
0884:                    return "x-conference/x-cooltalk";
0885:                if (file.endsWith(".WRL") || file.endsWith(".VRML"))
0886:                    return "x-world/x-vrml";
0887:                if (file.endsWith(".WML"))
0888:                    return "text/vnd.wap.wml";
0889:                if (file.endsWith(".WMLC"))
0890:                    return "application/vnd.wap.wmlc";
0891:                if (file.endsWith(".WMLS"))
0892:                    return "text/vnd.wap.wmlscript";
0893:                if (file.endsWith(".WMLSC"))
0894:                    return "application/vnd.wap.wmlscriptc";
0895:                if (file.endsWith(".WBMP"))
0896:                    return "image/vnd.wap.wbmp";
0897:
0898:                return null;
0899:            }
0900:
0901:            /// Returns the name and version of the web server under which the servlet
0902:            // is running.
0903:            // Same as the CGI variable SERVER_SOFTWARE.
0904:            public String getServerInfo() {
0905:                return Serve.Identification.serverName + " "
0906:                        + Serve.Identification.serverVersion + " ("
0907:                        + Serve.Identification.serverUrl + ")";
0908:            }
0909:
0910:            /// Returns the value of the named attribute of the network service, or
0911:            // null if the attribute does not exist.  This method allows access to
0912:            // additional information about the service, not already provided by
0913:            // the other methods in this interface.
0914:            public Object getAttribute(String name) {
0915:                // This server does not support attributes.
0916:                return attributes.get(name);
0917:            }
0918:
0919:            /////////////////// JSDK 2.1 extensions //////////////////////////
0920:            public void removeAttribute(String name) {
0921:                attributes.remove(name);
0922:            }
0923:
0924:            public void setAttribute(String name, Object object) {
0925:                attributes.put(name, object);
0926:            }
0927:
0928:            public Enumeration getAttributeNames() {
0929:                return attributes.keys();
0930:            }
0931:
0932:            public ServletContext getContext(String uripath) {
0933:                return this ; // only root context supported
0934:            }
0935:
0936:            public int getMajorVersion() {
0937:                return 2; // support 2.x
0938:            }
0939:
0940:            public int getMinorVersion() {
0941:                return 3; // support 2.3
0942:            }
0943:
0944:            // 2.3
0945:
0946:            /**
0947:             * Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path matches the supplied path argument. Paths indicating subdirectory paths end with a '/'. The returned paths are all relative to the root
0948:             *  of the web application and have a leading '/'. For example, for a web application containing
0949:             * <p>
0950:             * /welcome.html <br>
0951:             * /catalog/index.html<br>
0952:             * /catalog/products.html<br>
0953:             * /catalog/offers/books.html<br>
0954:             * /catalog/offers/music.html<br>
0955:             * /customer/login.jsp<br>
0956:             * /WEB-INF/web.xml<br>
0957:             * /WEB-INF/classes/com.acme.OrderServlet.class,
0958:             * <p>
0959:             * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}<br>
0960:             * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}.
0961:             * <p>
0962:             * 
0963:             * @param the - partial path used to match the resources, which must start with a /
0964:             * @return a Set containing the directory listing, or null if there are no resources in the web application whose path begins with the supplied path.
0965:             * @since Servlet 2.3 
0966:             * 
0967:             */
0968:            public java.util.Set getResourcePaths(java.lang.String path) {
0969:                // TODO: implement
0970:                return null;
0971:            }
0972:
0973:            /**
0974:             * Returns the name of this web application correponding to this ServletContext as specified in the deployment descriptor for this web application by the display-name element.
0975:             * @return The name of the web application or null if no name has been declared in the deployment descriptor.
0976:             *
0977:             * @since Servlet 2.3 
0978:             */
0979:            public java.lang.String getServletContextName() {
0980:                return null;//"ROOT";
0981:            }
0982:
0983:            // only root relative in this implementation
0984:            public URL getResource(String path) throws MalformedURLException {
0985:                return new URL("http", hostName, port, path);
0986:            }
0987:
0988:            public InputStream getResourceAsStream(String path) {
0989:                return null; // we don't provide resources in this way
0990:            }
0991:
0992:            public RequestDispatcher getRequestDispatcher(String urlpath) {
0993:                return this ; // we don't provide resource dispatching in this way
0994:            }
0995:
0996:            // no way to specify parameters for context
0997:            public String getInitParameter(String param) {
0998:                return null;
0999:            }
1000:
1001:            public Enumeration getInitParameterNames() {
1002:                return null;
1003:            }
1004:
1005:            public RequestDispatcher getNamedDispatcher(String name) {
1006:                return this ;
1007:            }
1008:
1009:            synchronized String generateSessionId() {
1010:                return "-" + System.currentTimeMillis() + '-' + (uniqer++)
1011:                        + '-' + Math.round(Math.random() * 1000);
1012:            }
1013:
1014:            public void forward(ServletRequest _request,
1015:                    ServletResponse _response) throws ServletException,
1016:                    java.io.IOException {
1017:            }
1018:
1019:            public void include(ServletRequest _request,
1020:                    ServletResponse _response) throws ServletException,
1021:                    java.io.IOException {
1022:            }
1023:
1024:            final static class Identification {
1025:                public static final String serverName = "Rogatkin's JWS based on Acme.Serve";
1026:                public static final String serverVersion = "$Revision: 1.1 $";
1027:                public static final String serverUrl = "http://tjws.sourceforge.net";
1028:
1029:                /// Write a standard-format HTML address for this server.
1030:                public static void writeAddress(OutputStream o)
1031:                        throws IOException {
1032:                    PrintStream p = new PrintStream(o);
1033:                    p.println("<ADDRESS><A HREF=\"" + serverUrl + "\">"
1034:                            + serverName + " " + serverVersion
1035:                            + "</A></ADDRESS>");
1036:                }
1037:
1038:                public static void writeAddress(StringBuffer sb)
1039:                        throws IOException {
1040:                    sb.append("<ADDRESS><A HREF=\"" + serverUrl + "\">"
1041:                            + serverName + " " + serverVersion
1042:                            + "</A></ADDRESS>");
1043:                }
1044:            }
1045:        }
1046:
1047:        class ServeConfig implements  ServletConfig {
1048:
1049:            private ServletContext context;
1050:            private Hashtable init_params;
1051:            private String servletName;
1052:
1053:            public ServeConfig(ServletContext context) {
1054:                this (context, null, "undefined");
1055:            }
1056:
1057:            public ServeConfig(ServletContext context, Hashtable initParams,
1058:                    String servletName) {
1059:                this .context = context;
1060:                this .init_params = initParams;
1061:                this .servletName = servletName;
1062:            }
1063:
1064:            // Methods from ServletConfig.
1065:
1066:            /// Returns the context for the servlet.
1067:            public ServletContext getServletContext() {
1068:                return context;
1069:            }
1070:
1071:            /// Gets an initialization parameter of the servlet.
1072:            // @param name the parameter name
1073:            public String getInitParameter(String name) {
1074:                // This server supports servlet init params. :)
1075:                if (init_params != null)
1076:                    return (String) init_params.get(name);
1077:                return null;
1078:            }
1079:
1080:            /// Gets the names of the initialization parameters of the servlet.
1081:            // @param name the parameter name
1082:            public Enumeration getInitParameterNames() {
1083:                // This server does:) support servlet init params.
1084:                if (init_params != null)
1085:                    return init_params.keys();
1086:                return new Vector().elements();
1087:            }
1088:
1089:            // 2.2
1090:            public String getServletName() {
1091:                return servletName;
1092:            }
1093:        }
1094:
1095:        ///////////////////////////////////////////////////////////////////////
1096:        /**
1097:         * provides request/response
1098:         */
1099:        class ServeConnection implements  Runnable, HttpServletRequest,
1100:                HttpServletResponse {
1101:
1102:            private Socket socket;
1103:            private Serve serve;
1104:
1105:            private ServletInputStream in;
1106:            private ServletOutputStream out;
1107:
1108:            private Hashtable formParameters;
1109:            private Hashtable attributes = new Hashtable();
1110:
1111:            public final static String WWWFORMURLENCODE = "application/x-www-form-urlencoded";
1112:            public final static String TRANSFERENCODING = "Transfer-Encoding";
1113:            public final static String CHUNKED = "chunked";
1114:            public final static String CONTENTLENGTH = "Content-Length";
1115:            public final static String CONTENTTYPE = "Content-Type";
1116:            public final static String SETCOOKIE = "Set-Cookie";
1117:            public final static String COOKIE = "Cookie";
1118:
1119:            public final static String SESSION_COOKIE_NAME = "JSESSIONID";
1120:            // URL rewriting http://www.myserver.com/catalog/index.html;jsessionid=mysession1928
1121:            // like: http://www.sun.com/2001-0227/sunblade/;$sessionid$AD5RQ0IAADJAZAMTA1LU5YQ
1122:
1123:            private String reqMethod; // == null by default
1124:            private String reqUriPath;
1125:            private String reqProtocol;
1126:            private String reqCharEncoding;
1127:            private String remoteUser;
1128:            private String authType;
1129:            private boolean oneOne; // HTTP/1.1 or better
1130:            private boolean reqMime;
1131:            String reqQuery = null;
1132:            private Vector reqHeaderNames = new Vector();
1133:            private Vector reqHeaderValues = new Vector();
1134:            private Locale locale; // = java.util.Locale.getDefault();
1135:            private int uriLen;
1136:            private static final Hashtable EMPTYHASHTABLE = new Hashtable();
1137:
1138:            private Vector outCookies;
1139:            private Vector inCookies;
1140:
1141:            private String sessionCookieValue;
1142:
1143:            /// Constructor.
1144:            public ServeConnection(Socket socket, Serve serve) {
1145:                // Save arguments.
1146:                this .socket = socket;
1147:                this .serve = serve;
1148:
1149:                // Start a separate thread to read and handle the request.
1150:                Thread thread = new Thread(this , "Request handler");
1151:                thread.start();
1152:            }
1153:
1154:            // Methods from Runnable.
1155:            public void run() {
1156:                try {
1157:                    // Get the streams.
1158:                    in = new ServeInputStream(socket.getInputStream());
1159:                    out = new ServeOutputStream(socket.getOutputStream(), this );
1160:                } catch (IOException e) {
1161:                    problem("Getting streams: " + e.getMessage(),
1162:                            SC_BAD_REQUEST);
1163:                }
1164:
1165:                parseRequest();
1166:
1167:                if (serve.isAccessLogged()) {
1168:                    serve.log(socket.getInetAddress().toString()
1169:                            + ' '
1170:                            + reqMethod
1171:                            + ' '
1172:                            + reqUriPath
1173:                            + ' '
1174:                            + resCode
1175:                            + (serve.isShowReferer() ? "| "
1176:                                    + getHeader("Referer") : "")
1177:                            + (serve.isShowUserAgent() ? "| "
1178:                                    + getHeader("User-Agent") : ""));
1179:                }
1180:
1181:                try {
1182:                    socket.close();
1183:                } catch (IOException e) { /* ignore */
1184:                }
1185:            }
1186:
1187:            private void parseRequest() {
1188:                byte[] lineBytes = new byte[4096];
1189:                int len;
1190:                String line;
1191:
1192:                try {
1193:                    // Read the first line of the request.
1194:                    len = in.readLine(lineBytes, 0, lineBytes.length);
1195:                    if (len == -1 || len == 0) {
1196:                        problem("Empty request", SC_BAD_REQUEST);
1197:                        return;
1198:                    }
1199:                    line = new String(lineBytes, 0, len);
1200:                    StringTokenizer ust = new StringTokenizer(line);
1201:                    reqProtocol = null;
1202:                    if (ust.hasMoreTokens()) {
1203:                        reqMethod = ust.nextToken();
1204:                        if (ust.hasMoreTokens()) {
1205:                            reqUriPath = Acme.Utils.urlDecoder(ust.nextToken());
1206:                            if (ust.hasMoreTokens()) {
1207:                                reqProtocol = ust.nextToken();
1208:                                oneOne = !reqProtocol.toUpperCase().equals(
1209:                                        "HTTP/1.0");
1210:                                reqMime = true;
1211:                                // Read the rest of the lines.
1212:                                String s;
1213:                                while ((s = ((ServeInputStream) in).readLine()) != null) {
1214:                                    if (s.length() == 0)
1215:                                        break;
1216:
1217:                                    int c = s.indexOf(':', 0);
1218:                                    if (c > 0) {
1219:                                        String key = s.substring(0, c).trim();
1220:                                        String value = s.substring(c + 1,
1221:                                                s.length()).trim();
1222:                                        reqHeaderNames.addElement(key
1223:                                                .toLowerCase());
1224:                                        reqHeaderValues.addElement(value);
1225:                                    } else
1226:                                        serve.log("header field without ':'");
1227:                                }
1228:                            } else {
1229:                                reqProtocol = "HTTP/0.9";
1230:                                oneOne = false;
1231:                                reqMime = false;
1232:                            }
1233:                        }
1234:                    }
1235:                    if (reqProtocol == null) {
1236:                        problem("Malformed request line", SC_BAD_REQUEST);
1237:                        return;
1238:                    }
1239:                    // Check Host: header in HTTP/1.1 requests.
1240:                    if (oneOne) {
1241:                        String host = getHeader("host");
1242:                        if (host == null) {
1243:                            problem("Host header missing on HTTP/1.1 request",
1244:                                    SC_BAD_REQUEST);
1245:                            return;
1246:                        }
1247:                    }
1248:
1249:                    // Decode %-sequences.
1250:                    //reqUriPath = decode( reqUriPath );
1251:                    // Split off query string, if any.
1252:                    int qmark = reqUriPath.indexOf('?');
1253:                    if (qmark > -1) {
1254:                        reqQuery = reqUriPath.substring(qmark + 1);
1255:                        reqUriPath = reqUriPath.substring(0, qmark);
1256:                    }
1257:                    if (CHUNKED.equals(getHeader(TRANSFERENCODING))) {
1258:                        setHeader(CONTENTLENGTH, null);
1259:                        ((ServeInputStream) in).chunking(true);
1260:                    }
1261:
1262:                    Object[] os = serve.registry.get(reqUriPath);
1263:                    if (os != null) {
1264:                        uriLen = ((Integer) os[1]).intValue();
1265:                        runServlet((HttpServlet) os[0]);
1266:                    }
1267:                } catch (IOException e) {
1268:                    problem("Reading request: " + e.getMessage(),
1269:                            SC_BAD_REQUEST);
1270:                }
1271:            }
1272:
1273:            private void runServlet(HttpServlet servlete) {
1274:                // Set default response fields.
1275:                setStatus(SC_OK);
1276:                setDateHeader("Date", System.currentTimeMillis());
1277:                setHeader("Server", Serve.Identification.serverName + "/"
1278:                        + Serve.Identification.serverVersion);
1279:                setHeader("MIME-Version", "1.0");
1280:                try {
1281:                    parseCookies();
1282:                    authenificate();
1283:                    if (servlete instanceof  SingleThreadModel)
1284:                        synchronized (servlete) {
1285:                            servlete.service((ServletRequest) this ,
1286:                                    (ServletResponse) this );
1287:                        }
1288:                    else
1289:                        servlete.service((ServletRequest) this ,
1290:                                (ServletResponse) this );
1291:                } catch (IOException e) {
1292:                    e.printStackTrace();
1293:                    problem("IO problem running servlet: " + e.toString(),
1294:                            SC_BAD_REQUEST);
1295:                } catch (ServletException e) {
1296:                    problem("problem running servlet: " + e.toString(),
1297:                            SC_BAD_REQUEST);
1298:                } catch (Exception e) {
1299:                    problem("unexpected problem running servlet: "
1300:                            + e.toString(), SC_INTERNAL_SERVER_ERROR);
1301:                    e.printStackTrace();
1302:                }
1303:            }
1304:
1305:            private boolean authenificate() throws IOException {
1306:                Object[] o = serve.realms.get(getPathInfo());
1307:                BasicAuthRealm realm = null;
1308:                if (o == null)
1309:                    realm = (BasicAuthRealm) o[0];
1310:                String credentials = getHeader("Authorization");
1311:
1312:                if (credentials != null) {
1313:                    credentials = credentials.substring(credentials
1314:                            .indexOf(' ') + 1);
1315:                    try {
1316:                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1317:                        serve.base64Dec.decodeBuffer(
1318:                                new StringBufferInputStream(credentials), baos);
1319:                        credentials = baos.toString();
1320:                    } catch (IOException e) {
1321:                        e.printStackTrace();
1322:                    }
1323:                    int i = credentials.indexOf(':');
1324:                    String user = credentials.substring(0, i);
1325:                    String password = credentials.substring(i + 1);
1326:                    remoteUser = user;
1327:                    authType = "Basic"; // support only basic authenification
1328:                    if (realm == null)
1329:                        return true;
1330:                    String realPassword = (String) realm.get(user);
1331:                    System.err.println("User " + user + " Password " + password
1332:                            + " real " + realPassword);
1333:                    if (realPassword != null && realPassword.equals(password))
1334:                        return true;
1335:                }
1336:                if (realm == null)
1337:                    return true;
1338:
1339:                setStatus(SC_UNAUTHORIZED);
1340:                setHeader("WWW-Authenticate", "basic realm=\"" + realm.name()
1341:                        + '"');
1342:                writeHeaders();
1343:                return false;
1344:            }
1345:
1346:            private void problem(String logMessage, int resCode) {
1347:                serve.log(logMessage);
1348:                try {
1349:                    sendError(resCode);
1350:                } catch (IllegalStateException e) { /* ignore */
1351:                } catch (IOException e) { /* ignore */
1352:                }
1353:            }
1354:
1355:            private String decode(String str) {
1356:                StringBuffer result = new StringBuffer();
1357:                int l = str.length();
1358:                for (int i = 0; i < l; ++i) {
1359:                    char c = str.charAt(i);
1360:                    if (c == '%' && i + 2 < l) {
1361:                        char c1 = str.charAt(i + 1);
1362:                        char c2 = str.charAt(i + 2);
1363:                        if (isHexit(c1) && isHexit(c2)) {
1364:                            result.append((char) (hexit(c1) * 16 + hexit(c2)));
1365:                            i += 2;
1366:                        } else
1367:                            result.append(c);
1368:                    } else if (c == '+')
1369:                        result.append(' ');
1370:                    else
1371:                        result.append(c);
1372:                }
1373:                return result.toString();
1374:            }
1375:
1376:            private boolean isHexit(char c) {
1377:                String legalChars = "0123456789abcdefABCDEF";
1378:                return (legalChars.indexOf(c) != -1);
1379:            }
1380:
1381:            private int hexit(char c) {
1382:                if (c >= '0' && c <= '9')
1383:                    return c - '0';
1384:                if (c >= 'a' && c <= 'f')
1385:                    return c - 'a' + 10;
1386:                if (c >= 'A' && c <= 'F')
1387:                    return c - 'A' + 10;
1388:                return 0; // shouldn't happen, we're guarded by isHexit()
1389:            }
1390:
1391:            void parseCookies() {
1392:                if (inCookies == null)
1393:                    inCookies = new Vector();
1394:                try {
1395:                    String cookie_name;
1396:                    String cookie_value;
1397:                    String cookie_path;
1398:                    String cookies = getHeader(COOKIE);
1399:                    if (cookies == null)
1400:                        return;
1401:                    //Enumeration e = getHeaders(COOKIE);
1402:                    //while(e.hasMoreElements())
1403:                    //	cookies += (String)e.nextElement();
1404:                    StringTokenizer st = new StringTokenizer(cookies, ";", true);
1405:                    // TODO: write a parser to avoid tokenizers
1406:                    while (st.hasMoreTokens()) {
1407:                        StringTokenizer st2 = new StringTokenizer(st
1408:                                .nextToken(), "=");
1409:                        if (st2.hasMoreTokens()) {
1410:                            cookie_name = st2.nextToken().trim();
1411:                            if (st2.hasMoreTokens()) {
1412:                                cookie_value = st2.nextToken(",").trim();
1413:                                if (cookie_value.length() > 0
1414:                                        && cookie_value.charAt(0) == '=')
1415:                                    cookie_value = cookie_value.substring(1);
1416:                                cookie_path = "/";
1417:                                while (st2.hasMoreTokens()) {
1418:                                    String cookie_atr = st2.nextToken();
1419:                                    if ("$Version".equalsIgnoreCase(cookie_atr)
1420:                                            || "$Path"
1421:                                                    .equalsIgnoreCase(cookie_atr)
1422:                                            || "$Domain"
1423:                                                    .equalsIgnoreCase(cookie_atr))
1424:                                        continue;
1425:                                    cookie_path = st2.nextToken();
1426:                                }
1427:                                Cookie cookie = new Cookie(cookie_name,
1428:                                        cookie_value);
1429:                                //System.err.println("Cookie set:"+cookie_name+':'+cookie_value);
1430:                                cookie.setPath(cookie_path);
1431:                                inCookies.addElement(cookie);
1432:                                if (SESSION_COOKIE_NAME.equals(cookie_name)
1433:                                        && sessionCookieValue == null) {
1434:                                    sessionCookieValue = cookie_value;
1435:                                    try {
1436:                                        ((AcmeSession) serve
1437:                                                .getSession(sessionCookieValue))
1438:                                                .userTouch();
1439:                                    } catch (Throwable t) {
1440:                                    }
1441:                                }
1442:                            }
1443:                        }
1444:                    }
1445:                } catch (Throwable e) {
1446:                    System.err.println("prepareCookies(): " + e);
1447:                    e.printStackTrace();
1448:                }
1449:            }
1450:
1451:            // Methods from ServletRequest.
1452:
1453:            /// Returns the size of the request entity data, or -1 if not known.
1454:            // Same as the CGI variable CONTENT_LENGTH.
1455:            public int getContentLength() {
1456:                return getIntHeader(CONTENTLENGTH, -1);
1457:            }
1458:
1459:            /// Returns the MIME type of the request entity data, or null if
1460:            // not known.
1461:            // Same as the CGI variable CONTENT_TYPE.
1462:            public String getContentType() {
1463:                return getHeader(CONTENTTYPE);
1464:            }
1465:
1466:            /// Returns the protocol and version of the request as a string of
1467:            // the form <protocol>/<major version>.<minor version>.
1468:            // Same as the CGI variable SERVER_PROTOCOL.
1469:            public String getProtocol() {
1470:                return reqProtocol;
1471:            }
1472:
1473:            ///  Returns the scheme of the URL used in this request, for example
1474:            // "http", "https", or "ftp".  Different schemes have different rules
1475:            // for constructing URLs, as noted in RFC 1738.  The URL used to create
1476:            // a request may be reconstructed using this scheme, the server name
1477:            // and port, and additional information such as URIs.
1478:            public String getScheme() {
1479:                if (socket.getClass().getName().toUpperCase().indexOf("SSL") < 0)
1480:                    return "http";
1481:                else
1482:                    return "https";
1483:            }
1484:
1485:            /// Returns the host name of the server as used in the <host> part of
1486:            // the request URI.
1487:            // Same as the CGI variable SERVER_NAME.
1488:            public String getServerName() {
1489:                String serverName;
1490:                int serverPort = 80;
1491:                serverName = getHeader("Host");
1492:                if (serverName != null && serverName.length() > 0) {
1493:                    int colon = serverName.indexOf(':');
1494:                    if (colon >= 0) {
1495:                        if (colon < serverName.length())
1496:                            serverPort = Integer.parseInt(serverName
1497:                                    .substring(colon + 1));
1498:                        serverName = serverName.substring(0, colon);
1499:                    }
1500:                }
1501:
1502:                if (serverName == null) {
1503:                    try {
1504:                        serverName = InetAddress.getLocalHost().getHostName();
1505:                    } catch (java.net.UnknownHostException ignore) {
1506:                        serverName = "127.0.0.0";
1507:                    }
1508:                }
1509:
1510:                int slash = serverName.indexOf("/");
1511:                if (slash >= 0)
1512:                    serverName = serverName.substring(slash + 1);
1513:                return serverName;
1514:            }
1515:
1516:            /// Returns the port number on which this request was received as used in
1517:            // the <port> part of the request URI.
1518:            // Same as the CGI variable SERVER_PORT.
1519:            public int getServerPort() {
1520:                return socket.getLocalPort();
1521:            }
1522:
1523:            /// Returns the IP address of the agent that sent the request.
1524:            // Same as the CGI variable REMOTE_ADDR.
1525:            public String getRemoteAddr() {
1526:                return socket.getInetAddress().toString();
1527:            }
1528:
1529:            /// Returns the fully qualified host name of the agent that sent the
1530:            // request.
1531:            // Same as the CGI variable REMOTE_HOST.
1532:            public String getRemoteHost() {
1533:                String result = socket.getInetAddress().getHostName();
1534:                return result != null ? result : getRemoteAddr();
1535:            }
1536:
1537:            /// Applies alias rules to the specified virtual path and returns the
1538:            // corresponding real path, or null if the translation can not be
1539:            // performed for any reason.  For example, an HTTP servlet would
1540:            // resolve the path using the virtual docroot, if virtual hosting is
1541:            // enabled, and with the default docroot otherwise.  Calling this
1542:            // method with the string "/" as an argument returns the document root.
1543:            public String getRealPath(String path) {
1544:                return serve.getRealPath(path);
1545:            }
1546:
1547:            /// Returns an input stream for reading request data.
1548:            // @exception IllegalStateException if getReader has already been called
1549:            // @exception IOException on other I/O-related errors
1550:            public ServletInputStream getInputStream() throws IOException {
1551:                synchronized (in) {
1552:                    if (((ServeInputStream) in).isReturnedAsReader())
1553:                        throw new IllegalStateException(
1554:                                "Already returned as a reader.");
1555:                    ((ServeInputStream) in).setReturnedAsReader(true);
1556:                }
1557:                return in;
1558:            }
1559:
1560:            /// Returns a buffered reader for reading request data.
1561:            // @exception UnsupportedEncodingException if the character set encoding isn't supported
1562:            // @exception IllegalStateException if getInputStream has already been called
1563:            // @exception IOException on other I/O-related errors
1564:            public BufferedReader getReader() {
1565:                synchronized (in) {
1566:                    if (((ServeInputStream) in).isReturnedAsStream())
1567:                        throw new IllegalStateException(
1568:                                "Already returned as a stream.");
1569:                    ((ServeInputStream) in).setReturnedAsStream(true);
1570:                }
1571:                if (reqCharEncoding != null)
1572:                    try {
1573:                        return new BufferedReader(new InputStreamReader(in,
1574:                                reqCharEncoding));
1575:                    } catch (UnsupportedEncodingException uee) {
1576:                    }
1577:                return new BufferedReader(new InputStreamReader(in));
1578:            }
1579:
1580:            private Hashtable getParametersFromRequest() {
1581:                Hashtable result = null;
1582:                //System.out.println("Req:"+reqMethod+" con:"+getContentType()+" eq "+WWWFORMURLENCODE.equals(getContentType()));
1583:                if ("GET".equals(reqMethod)) {
1584:                    if (reqQuery != null)
1585:                        try {
1586:                            result = HttpUtils.parseQueryString(reqQuery);
1587:                        } catch (IllegalArgumentException ex) {
1588:                        }
1589:                } else if ("POST".equals(reqMethod))
1590:                    if (WWWFORMURLENCODE.equals(getContentType()))
1591:                        try {
1592:                            result = HttpUtils.parsePostData(
1593:                                    getContentLength(), getInputStream());
1594:                            if (reqQuery != null && reqQuery.length() > 0) {
1595:                                Acme.Utils.putAll(result, HttpUtils
1596:                                        .parseQueryString(reqQuery));
1597:                            }
1598:                        } catch (Exception ex) {
1599:                            serve.log("Exception " + ex
1600:                                    + " at parsing post data of length "
1601:                                    + getContentLength());
1602:                        }
1603:                    else
1604:                        try {
1605:                            if (reqQuery != null)
1606:                                result = HttpUtils.parseQueryString(reqQuery);
1607:                        } catch (Exception ex) {
1608:                        }
1609:                return result != null ? result : EMPTYHASHTABLE;
1610:            }
1611:
1612:            /// Returns the parameter names for this request.
1613:            public Enumeration getParameterNames() {
1614:                if (formParameters == null)
1615:                    formParameters = getParametersFromRequest();
1616:                return formParameters.keys();
1617:            }
1618:
1619:            /// Returns the value of the specified query string parameter, or null
1620:            // if not found.
1621:            // @param name the parameter name
1622:            public String getParameter(String name) {
1623:                String[] params = getParameterValues(name);
1624:                if (params == null || params.length == 0)
1625:                    return null;
1626:
1627:                return params[0];
1628:            }
1629:
1630:            /// Returns the values of the specified parameter for the request as an
1631:            // array of strings, or null if the named parameter does not exist.
1632:            public String[] getParameterValues(String name) {
1633:                if (formParameters == null)
1634:                    getParameterNames();
1635:
1636:                return (String[]) formParameters.get(name);
1637:            }
1638:
1639:            /// Returns the value of the named attribute of the request, or null if
1640:            // the attribute does not exist.  This method allows access to request
1641:            // information not already provided by the other methods in this interface.
1642:            public Object getAttribute(String name) {
1643:                return attributes.get(name);
1644:            }
1645:
1646:            // Methods from HttpServletRequest.
1647:
1648:            /// Gets the array of cookies found in this request.
1649:            public Cookie[] getCookies() {
1650:                Cookie[] cookieArray = new Cookie[inCookies.size()];
1651:                inCookies.copyInto(cookieArray);
1652:                return cookieArray;
1653:            }
1654:
1655:            /// Returns the method with which the request was made. This can be "GET",
1656:            // "HEAD", "POST", or an extension method.
1657:            // Same as the CGI variable REQUEST_METHOD.
1658:            public String getMethod() {
1659:                return reqMethod;
1660:            }
1661:
1662:            /***
1663:              Returns the part of this request's URL from the protocol name up to
1664:              the query string in the first line of the HTTP request.
1665:              To reconstruct an URL with a scheme and host,
1666:              use HttpUtils.getRequestURL(javax.servlet.http.HttpServletRequest).
1667:             */
1668:            /// Returns the full request URI.
1669:            public String getRequestURI() {
1670:                return reqUriPath;
1671:            }
1672:
1673:            /** Reconstructs the URL the client used to make the request.
1674:             *  The returned URL contains a protocol, server name, port number,
1675:             *  and server path, but it does not include query string parameters. <br>
1676:             *  Because this method returns a StringBuffer, not a string, you can modify the
1677:             *  URL easily, for example, to append query parameters. 
1678:             * <p>
1679:             * This method is useful for creating redirect messages and for reporting errors.
1680:             *
1681:             * @return a StringBuffer object containing the reconstructed URL
1682:             * @since 2.3
1683:             */
1684:            public java.lang.StringBuffer getRequestURL() {
1685:                return new StringBuffer().append(getScheme()).append("://")
1686:                        .append(serve.hostName).append(
1687:                                serve.port == 80 ? "" : String
1688:                                        .valueOf(serve.port)).append(
1689:                                getRequestURI());
1690:            }
1691:
1692:            /// Returns the part of the request URI that referred to the servlet being
1693:            // invoked.
1694:            // Analogous to the CGI variable SCRIPT_NAME.
1695:            public String getServletPath() {
1696:                // In this server, the entire path is regexp-matched against the
1697:                // servlet pattern, so there's no good way to distinguish which
1698:                // part refers to the servlet.
1699:                return uriLen > 0 ? reqUriPath.substring(0, uriLen) : "";
1700:            }
1701:
1702:            /// Returns optional extra path information following the servlet path, but
1703:            // immediately preceding the query string.  Returns null if not specified.
1704:            // Same as the CGI variable PATH_INFO.
1705:            public String getPathInfo() {
1706:                // In this server, the entire path is regexp-matched against the
1707:                // servlet pattern, so there's no good way to distinguish which
1708:                // part refers to the servlet.
1709:                return uriLen >= reqUriPath.length() ? null : reqUriPath
1710:                        .substring(uriLen);
1711:            }
1712:
1713:            /// Returns extra path information translated to a real path.  Returns
1714:            // null if no extra path information was specified.
1715:            // Same as the CGI variable PATH_TRANSLATED.
1716:            public String getPathTranslated() {
1717:                // In this server, the entire path is regexp-matched against the
1718:                // servlet pattern, so there's no good way to distinguish which
1719:                // part refers to the servlet.
1720:                return getRealPath(getPathInfo());
1721:            }
1722:
1723:            /// Returns the query string part of the servlet URI, or null if not known.
1724:            // Same as the CGI variable QUERY_STRING.
1725:            public String getQueryString() {
1726:                return reqQuery;
1727:            }
1728:
1729:            /// Returns the name of the user making this request, or null if not known.
1730:            // Same as the CGI variable REMOTE_USER.
1731:            public String getRemoteUser() {
1732:                return remoteUser;
1733:            }
1734:
1735:            /// Returns the authentication scheme of the request, or null if none.
1736:            // Same as the CGI variable AUTH_TYPE.
1737:            public String getAuthType() {
1738:                return authType;
1739:            }
1740:
1741:            /// Returns the value of a header field, or null if not known.
1742:            // Same as the information passed in the CGI variabled HTTP_*.
1743:            // @param name the header field name
1744:            public String getHeader(String name) {
1745:                int i = reqHeaderNames.indexOf(name.toLowerCase());
1746:                if (i == -1)
1747:                    return null;
1748:                return (String) reqHeaderValues.elementAt(i);
1749:            }
1750:
1751:            public int getIntHeader(String name) {
1752:                return getIntHeader(name, 0);
1753:            }
1754:
1755:            /// Returns the value of an integer header field.
1756:            // @param name the header field name
1757:            // @param def the integer value to return if header not found or invalid
1758:            public int getIntHeader(String name, int def) {
1759:                String val = getHeader(name);
1760:                if (val == null)
1761:                    return def;
1762:                try {
1763:                    return Integer.parseInt(val);
1764:                } catch (Exception e) {
1765:                    return def;
1766:                }
1767:            }
1768:
1769:            /// Returns the value of a long header field.
1770:            // @param name the header field name
1771:            // @param def the long value to return if header not found or invalid
1772:            public long getLongHeader(String name, long def) {
1773:                String val = getHeader(name);
1774:                if (val == null)
1775:                    return def;
1776:                try {
1777:                    return Long.parseLong(val);
1778:                } catch (Exception e) {
1779:                    return def;
1780:                }
1781:            }
1782:
1783:            public long getDateHeader(String name) {
1784:                String val = getHeader(name);
1785:                if (val == null)
1786:                    return 0;
1787:                try {
1788:                    return headerdateformat.parse(val).getTime();
1789:                } catch (Exception e) {
1790:                    throw new IllegalArgumentException("Value " + val
1791:                            + " can't be converted to Date using "
1792:                            + headerdateformat.toPattern());
1793:                }
1794:
1795:            }
1796:
1797:            /// Returns the value of a date header field.
1798:            // @param name the header field name
1799:            // @param def the date value to return if header not found or invalid
1800:            public long getDateHeader(String name, long def) {
1801:                String val = getHeader(name);
1802:                if (val == null)
1803:                    return def;
1804:                try {
1805:                    return DateFormat.getDateInstance().parse(val).getTime();
1806:                } catch (Exception e) {
1807:                    return def;
1808:                }
1809:            }
1810:
1811:            /// Returns an Enumeration of the header names.
1812:            public Enumeration getHeaderNames() {
1813:                return reqHeaderNames.elements();
1814:            }
1815:
1816:            /// Gets the current valid session associated with this request, if
1817:            // create is false or, if necessary, creates a new session for the
1818:            // request, if create is true.
1819:            // <P>
1820:            // Note: to ensure the session is properly maintained, the servlet
1821:            // developer must call this method (at least once) before any output
1822:            // is written to the response.
1823:            // <P>
1824:            // Additionally, application-writers need to be aware that newly
1825:            // created sessions (that is, sessions for which HttpSession.isNew
1826:            // returns true) do not have any application-specific state.
1827:            public HttpSession getSession(boolean create) {
1828:                // look for session
1829:                // get session cookie
1830:                HttpSession result = getSession();
1831:                if (result == null && create) {
1832:                    result = serve.createSession();
1833:                }
1834:                if (result != null)
1835:                    sessionCookieValue = result.getId();
1836:                return result;
1837:            }
1838:
1839:            // JSDK 2.1
1840:            public HttpSession getSession() {
1841:                AcmeSession result = null;
1842:                if (sessionCookieValue != null) {
1843:                    result = (AcmeSession) serve.getSession(sessionCookieValue);
1844:                    if (result != null && !result.isValid()) {
1845:                        serve.removeSession(sessionCookieValue);
1846:                        result = null;
1847:                    }
1848:                }
1849:                return result;
1850:            }
1851:
1852:            public boolean isRequestedSessionIdFromURL() {
1853:                return false;
1854:            }
1855:
1856:            // from ServletRequest
1857:            public Enumeration getAttributeNames() {
1858:                return attributes.keys();
1859:            }
1860:
1861:            public void setAttribute(String key, Object o) {
1862:                attributes.put(key, o);
1863:            }
1864:
1865:            /// Gets the session id specified with this request. This may differ
1866:            // from the actual session id.  For example, if the request specified
1867:            // an id for an invalid session, then this will get a new session with
1868:            // a new id.
1869:            public String getRequestedSessionId() {
1870:                return sessionCookieValue;
1871:            }
1872:
1873:            /// Checks whether this request is associated with a session that is
1874:            // valid in the current session context.  If it is not valid, the
1875:            // requested session will never be returned from the getSession
1876:            // method.
1877:            public boolean isRequestedSessionIdValid() {
1878:                if (sessionCookieValue != null) {
1879:                    AcmeSession session = (AcmeSession) serve
1880:                            .getSession(sessionCookieValue);
1881:                    if (session != null && session.isValid()) {
1882:                        return true;
1883:                    }
1884:                }
1885:                return false;
1886:            }
1887:
1888:            /** Checks whether the session id specified by this request came in as
1889:             * a cookie.  (The requested session may not be one returned by the
1890:             * getSession method.) */
1891:            public boolean isRequestedSessionIdFromCookie() {
1892:                return true;
1893:            }
1894:
1895:            /// Checks whether the session id specified by this request came in as
1896:            // part of the URL.  (The requested session may not be the one returned
1897:            // by the getSession method.)
1898:            public boolean isRequestedSessionIdFromUrl() {
1899:                return false;
1900:            }
1901:
1902:            // Methods from ServletResponse.
1903:
1904:            /// Sets the content length for this response.
1905:            // @param length the content length
1906:            public void setContentLength(int length) {
1907:                setIntHeader(CONTENTLENGTH, length);
1908:            }
1909:
1910:            /// Sets the content type for this response.
1911:            // @param type the content type
1912:            public void setContentType(String type) {
1913:                setHeader(CONTENTTYPE, type != null ? type : "Unknown");
1914:            }
1915:
1916:            /// Returns an output stream for writing response data.
1917:            public ServletOutputStream getOutputStream() {
1918:                synchronized (out) {
1919:                    if (((ServeOutputStream) out).isReturnedAsWriter())
1920:                        throw new IllegalStateException(
1921:                                "Already returned as a writer");
1922:                    ((ServeOutputStream) out).setReturnedAsStream(true);
1923:                }
1924:                return out;
1925:            }
1926:
1927:            /// Returns a print writer for writing response data.  The MIME type of
1928:            // the response will be modified, if necessary, to reflect the character
1929:            // encoding used, through the charset=... property.  This means that the
1930:            // content type must be set before calling this method.
1931:            // @exception UnsupportedEncodingException if no such encoding can be provided
1932:            // @exception IllegalStateException if getOutputStream has been called
1933:            // @exception IOException on other I/O errors
1934:            public PrintWriter getWriter() throws IOException {
1935:                synchronized (out) {
1936:                    if (((ServeOutputStream) out).isReturnedAsStream())
1937:                        throw new IllegalStateException(
1938:                                "Already was returned as servlet output stream");
1939:                    ((ServeOutputStream) out).setReturnedAsWriter(true);
1940:                }
1941:                String encoding = getCharacterEncoding();
1942:                if (encoding != null)
1943:                    return new PrintWriter(
1944:                            new OutputStreamWriter(out, encoding));
1945:                else
1946:                    return new PrintWriter(out);
1947:            }
1948:
1949:            /// Returns the character set encoding used for this MIME body.  The
1950:            // character encoding is either the one specified in the assigned
1951:            // content type, or one which the client understands.  If no content
1952:            // type has yet been assigned, it is implicitly set to text/plain.
1953:            public String getCharacterEncoding() {
1954:                String ct = (String) resHeaderNames.get(CONTENTTYPE);
1955:                if (ct != null) {
1956:                    int scp = ct.indexOf(';');
1957:                    if (scp > 0) {
1958:                        scp = ct.toLowerCase().indexOf("charset=", scp);
1959:                        if (scp >= 0) {
1960:                            ct = ct.substring(scp + 8);
1961:                            scp = ct.indexOf(' ');
1962:                            if (scp > 0)
1963:                                ct = ct.substring(0, scp);
1964:                            scp = ct.indexOf(';');
1965:                            if (scp > 0)
1966:                                ct = ct.substring(0, scp);
1967:                            return ct;
1968:                        }
1969:                    }
1970:                }
1971:                return null;
1972:            }
1973:
1974:            // 2.2
1975:            // do not use buffer
1976:            public void flushBuffer() {
1977:            }
1978:
1979:            /**
1980:             * Clears the content of the underlying buffer in the response without clearing
1981:             * headers or status code. If the response has been committed,
1982:             * this method throws an IllegalStateException.
1983:             * @since 2.3 
1984:             */
1985:            public void resetBuffer() {
1986:                throw new IllegalStateException("The method not implemented");
1987:            }
1988:
1989:            public int getBufferSize() {
1990:                return 0;
1991:            }
1992:
1993:            public void setBufferSize(int size) {
1994:            }
1995:
1996:            /**
1997:             * Returns a boolean indicating if the response has been committed.
1998:             *  A commited response has already had its status code and headers written.
1999:             * @return
2000:             * a boolean indicating if the response has been committed
2001:             * @see 
2002:             * setBufferSize(int), getBufferSize(), flushBuffer(), reset()
2003:             */
2004:            // a caller should think about syncronization 
2005:            public boolean isCommitted() {
2006:                return headersWritten;
2007:            }
2008:
2009:            /** Clears any data that exists in the buffer as well as the status code and headers.
2010:             *  If the response has been committed, this method throws an IllegalStateException.
2011:             *  @throws java.lang.IllegalStateException - if the response has already been committed
2012:             *  @see  
2013:             *     setBufferSize(int), getBufferSize(), flushBuffer(), isCommitted()
2014:             */
2015:            public void reset() throws IllegalStateException {
2016:                if (!isCommitted()) {
2017:                    outCookies.removeAllElements();
2018:                    resHeaderNames.clear();
2019:                } else
2020:                    throw new IllegalStateException(
2021:                            "Header have already been committed.");
2022:            }
2023:
2024:            /**
2025:             * Sets the locale of the response, setting the headers (including the Content-Type's charset)
2026:             *  as appropriate. This method should be called before a call to getWriter().
2027:             *  By default, the response locale is the default locale for the server.
2028:             * @param loc - the locale of the response
2029:             * @see  
2030:             * getLocale()
2031:             */
2032:            public void setLocale(java.util.Locale locale) {
2033:                this .locale = locale;
2034:            }
2035:
2036:            public java.util.Locale getLocale() {
2037:                return locale;
2038:            }
2039:
2040:            // should decide about supported locales and charsets, no a good decision yet
2041:            public Enumeration getLocales() {
2042:                // TODO: get locales from Accept-Language (RFC 2616)
2043:                //Locale.getAvailableLocales() 
2044:                return null;
2045:            }
2046:
2047:            /**
2048:             * Overrides the name of the character encoding used in the body of this request.
2049:             *  This method must be called prior to reading request parameters or reading input using getReader().
2050:             * @param a - String containing the name of the chararacter encoding.
2051:             * @throws java.io.UnsupportedEncodingException - if this is not a valid encoding
2052:             * @since JSDK 2.3
2053:             */
2054:            public void setCharacterEncoding(String _enc)
2055:                    throws java.io.UnsupportedEncodingException {
2056:                reqCharEncoding = _enc;
2057:            }
2058:
2059:            public void addDateHeader(String header, long date) {
2060:                addHeader(header, expdatefmt.format(new Date(date)));
2061:            }
2062:
2063:            public void addHeader(String header, String value) {
2064:                Object o = resHeaderNames.get(header);
2065:                if (o == null)
2066:                    setHeader(header, value);
2067:                else {
2068:                    if (o instanceof  String[]) {
2069:                        String[] oldVal = (String[]) o;
2070:                        String[] newVal = new String[oldVal.length + 1];
2071:                        System.arraycopy(oldVal, 0, newVal, 0, oldVal.length);
2072:                        newVal[oldVal.length] = value;
2073:                        resHeaderNames.put(header, newVal);
2074:                    } else if (o instanceof  String) {
2075:                        String[] newVal = new String[2];
2076:                        newVal[0] = (String) o;
2077:                        newVal[1] = value;
2078:                        resHeaderNames.put(header, newVal);
2079:                    } else
2080:                        throw new RuntimeException(
2081:                                "Invalid content of header hash - "
2082:                                        + o.getClass().getName());
2083:                }
2084:            }
2085:
2086:            public void addIntHeader(String header, int value) {
2087:                addHeader(header, Integer.toString(value));
2088:            }
2089:
2090:            public RequestDispatcher getRequestDispatcher(String urlpath) {
2091:                // TODO: calculate dispacter relatively the current path
2092:                return null; // we don't provide resource dispatching in this way
2093:            }
2094:
2095:            public boolean isSecure() {
2096:                return false;
2097:            }
2098:
2099:            public void removeAttribute(String name) {
2100:            }
2101:
2102:            // only root context supported
2103:            public String getContextPath() {
2104:                return "";
2105:            }
2106:
2107:            public Enumeration getHeaders(String header) {
2108:                Vector result = new Vector();
2109:                int i = -1;
2110:                while ((i = reqHeaderNames.indexOf(header.toLowerCase(), i + 1)) >= 0)
2111:                    result.addElement(reqHeaderValues.elementAt(i));
2112:                return result.elements();
2113:            }
2114:
2115:            public java.security.Principal getUserPrincipal() {
2116:                return null;
2117:            }
2118:
2119:            public boolean isUserInRole(String user) {
2120:                return true;
2121:            }
2122:
2123:            /** 
2124:             * Returns a java.util.Map of the parameters of this request.
2125:             * Request parameters are extra information sent with the request.
2126:             * For HTTP servlets, parameters are contained in the query string or posted form data.
2127:             * @return an immutable java.util.Map containing parameter names as keys
2128:             *  and parameter values as map values. The keys in the parameter map are of type String.
2129:             *  The values in the parameter map are of type String array.
2130:             * @since 2.3
2131:             */
2132:            public java.util.Map getParameterMap() {
2133:                return (java.util.Map) formParameters;
2134:            }
2135:
2136:            // Methods from HttpServletResponse.
2137:
2138:            /// Adds the specified cookie to the response.  It can be called
2139:            // multiple times to set more than one cookie.
2140:            public void addCookie(Cookie cookie) {
2141:                if (outCookies == null)
2142:                    outCookies = new Vector();
2143:
2144:                outCookies.addElement(cookie);
2145:            }
2146:
2147:            /// Checks whether the response message header has a field with the
2148:            // specified name.
2149:            public boolean containsHeader(String name) {
2150:                return resHeaderNames.contains(name);
2151:            }
2152:
2153:            // JSDK 2.1 extension
2154:            public String encodeURL(String url) {
2155:                return url; // as is
2156:            }
2157:
2158:            public String encodeRedirectURL(String url) {
2159:                return url; // as is
2160:            }
2161:
2162:            private int resCode = -1;
2163:            private String resMessage = null;
2164:            private Hashtable resHeaderNames = new Hashtable();
2165:
2166:            protected static final SimpleDateFormat expdatefmt = new SimpleDateFormat(
2167:                    "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'");
2168:            protected static final SimpleDateFormat headerdateformat = new SimpleDateFormat(
2169:                    "EEE, dd MMM yyyy HH:mm:ss z");
2170:            static {
2171:                TimeZone tz = TimeZone.getTimeZone("GMT");
2172:                tz.setID("GMT");
2173:                expdatefmt.setTimeZone(tz);
2174:            }
2175:
2176:            /// Sets the status code and message for this response.
2177:            // @param resCode the status code
2178:            // @param resMessage the status message
2179:            public void setStatus(int resCode, String resMessage) {
2180:                //	if (this.resCode > 0 && this.resCode != SC_OK)
2181:                //		throw new IllegalStateException("Result code "+this.resCode+" was already set.");
2182:                this .resCode = resCode;
2183:                this .resMessage = resMessage;
2184:            }
2185:
2186:            /// Sets the status code and a default message for this response.
2187:            // @param resCode the status code
2188:            public void setStatus(int resCode) {
2189:                switch (resCode) {
2190:                case SC_CONTINUE:
2191:                    setStatus(resCode, "Continue");
2192:                    break;
2193:                case SC_SWITCHING_PROTOCOLS:
2194:                    setStatus(resCode, "Switching protocols");
2195:                    break;
2196:                case SC_OK:
2197:                    setStatus(resCode, "Ok");
2198:                    break;
2199:                case SC_CREATED:
2200:                    setStatus(resCode, "Created");
2201:                    break;
2202:                case SC_ACCEPTED:
2203:                    setStatus(resCode, "Accepted");
2204:                    break;
2205:                case SC_NON_AUTHORITATIVE_INFORMATION:
2206:                    setStatus(resCode, "Non-authoritative");
2207:                    break;
2208:                case SC_NO_CONTENT:
2209:                    setStatus(resCode, "No content");
2210:                    break;
2211:                case SC_RESET_CONTENT:
2212:                    setStatus(resCode, "Reset content");
2213:                    break;
2214:                case SC_PARTIAL_CONTENT:
2215:                    setStatus(resCode, "Partial content");
2216:                    break;
2217:                case SC_MULTIPLE_CHOICES:
2218:                    setStatus(resCode, "Multiple choices");
2219:                    break;
2220:                case SC_MOVED_PERMANENTLY:
2221:                    setStatus(resCode, "Moved permanentently");
2222:                    break;
2223:                case SC_MOVED_TEMPORARILY:
2224:                    setStatus(resCode, "Moved temporarily");
2225:                    break;
2226:                case SC_SEE_OTHER:
2227:                    setStatus(resCode, "See other");
2228:                    break;
2229:                case SC_NOT_MODIFIED:
2230:                    setStatus(resCode, "Not modified");
2231:                    break;
2232:                case SC_USE_PROXY:
2233:                    setStatus(resCode, "Use proxy");
2234:                    break;
2235:                case SC_BAD_REQUEST:
2236:                    setStatus(resCode, "Bad request");
2237:                    break;
2238:                case SC_UNAUTHORIZED:
2239:                    setStatus(resCode, "Unauthorized");
2240:                    break;
2241:                case SC_PAYMENT_REQUIRED:
2242:                    setStatus(resCode, "Payment required");
2243:                    break;
2244:                case SC_FORBIDDEN:
2245:                    setStatus(resCode, "Forbidden");
2246:                    break;
2247:                case SC_NOT_FOUND:
2248:                    setStatus(resCode, "Not found");
2249:                    break;
2250:                case SC_METHOD_NOT_ALLOWED:
2251:                    setStatus(resCode, "Method not allowed");
2252:                    break;
2253:                case SC_NOT_ACCEPTABLE:
2254:                    setStatus(resCode, "Not acceptable");
2255:                    break;
2256:                case SC_PROXY_AUTHENTICATION_REQUIRED:
2257:                    setStatus(resCode, "Proxy auth required");
2258:                    break;
2259:                case SC_REQUEST_TIMEOUT:
2260:                    setStatus(resCode, "Request timeout");
2261:                    break;
2262:                case SC_CONFLICT:
2263:                    setStatus(resCode, "Conflict");
2264:                    break;
2265:                case SC_GONE:
2266:                    setStatus(resCode, "Gone");
2267:                    break;
2268:                case SC_LENGTH_REQUIRED:
2269:                    setStatus(resCode, "Length required");
2270:                    break;
2271:                case SC_PRECONDITION_FAILED:
2272:                    setStatus(resCode, "Precondition failed");
2273:                    break;
2274:                case SC_REQUEST_ENTITY_TOO_LARGE:
2275:                    setStatus(resCode, "Request entity too large");
2276:                    break;
2277:                case SC_REQUEST_URI_TOO_LONG:
2278:                    setStatus(resCode, "Request URI too large");
2279:                    break;
2280:                case SC_UNSUPPORTED_MEDIA_TYPE:
2281:                    setStatus(resCode, "Unsupported media type");
2282:                    break;
2283:                case SC_INTERNAL_SERVER_ERROR:
2284:                    setStatus(resCode, "Internal server error");
2285:                    break;
2286:                case SC_NOT_IMPLEMENTED:
2287:                    setStatus(resCode, "Not implemented");
2288:                    break;
2289:                case SC_BAD_GATEWAY:
2290:                    setStatus(resCode, "Bad gateway");
2291:                    break;
2292:                case SC_SERVICE_UNAVAILABLE:
2293:                    setStatus(resCode, "Service unavailable");
2294:                    break;
2295:                case SC_GATEWAY_TIMEOUT:
2296:                    setStatus(resCode, "Gateway timeout");
2297:                    break;
2298:                case SC_HTTP_VERSION_NOT_SUPPORTED:
2299:                    setStatus(resCode, "HTTP version not supported");
2300:                    break;
2301:                default:
2302:                    setStatus(resCode, "");
2303:                    break;
2304:                }
2305:            }
2306:
2307:            /// Sets the value of a header field.
2308:            // @param name the header field name
2309:            // @param value the header field value
2310:            public void setHeader(String name, String value) {
2311:                resHeaderNames.put(name, value);
2312:            }
2313:
2314:            /// Sets the value of an integer header field.
2315:            // @param name the header field name
2316:            // @param value the header field integer value
2317:            public void setIntHeader(String name, int value) {
2318:                setHeader(name, Integer.toString(value));
2319:            }
2320:
2321:            /// Sets the value of a long header field.
2322:            // @param name the header field name
2323:            // @param value the header field long value
2324:            public void setLongHeader(String name, long value) {
2325:                setHeader(name, Long.toString(value));
2326:            }
2327:
2328:            /// Sets the value of a date header field.
2329:            // @param name the header field name
2330:            // @param value the header field date value
2331:            public void setDateHeader(String name, long value) {
2332:                setHeader(name, expdatefmt.format(new Date(value)));
2333:            }
2334:
2335:            private static final String[] weekdays = { "Sun", "Mon", "Tue",
2336:                    "Wed", "Thu", "Fri", "Sat" };
2337:            /*
2338:            /// Converts a Date into an RFC-1123 string.
2339:            private static String to1123String( Date date )
2340:            {
2341:            // We have to go through some machinations here to get the
2342:            // correct day of the week in GMT.  getDay() gives the day in
2343:            // local time.  getDate() gives the day of the month in local
2344:            // time.  toGMTString() gives a formatted string in GMT.  So, we
2345:            // extract the day of the month from the GMT string, and if it
2346:            // doesn't match the local one we change the local day of the
2347:            // week accordingly.
2348:            //
2349:            // The Date class sucks.
2350:            int localDay = date.getDay();
2351:            int localDate = date.getDate();
2352:            String gmtStr = date.toGMTString();
2353:            int blank = gmtStr.indexOf( ' ' );
2354:            int gmtDate = Integer.parseInt( gmtStr.substring( 0, blank ) );
2355:            int gmtDay;
2356:            if ( gmtDate > localDate || ( gmtDate < localDate && gmtDate == 1 ) )
2357:            gmtDay = ( localDay + 1 ) % 7;
2358:            else if ( localDate > gmtDate || ( localDate < gmtDate && localDate == 1 ) )
2359:            gmtDay = ( localDay + 6 ) % 7;
2360:            else
2361:            gmtDay = localDay;
2362:            return weekdays[gmtDay] + ( gmtDate < 10 ? ", 0" : ", " ) + gmtStr;
2363:            }
2364:             */
2365:            private boolean headersWritten = false;
2366:
2367:            /// Writes the status line and message headers for this response to the
2368:            // output stream.
2369:            // @exception IOException if an I/O error has occurred
2370:            void writeHeaders() throws IOException {
2371:                synchronized (this ) {
2372:                    if (headersWritten)
2373:                        return;
2374:
2375:                    headersWritten = true;
2376:                }
2377:                if (reqMime) {
2378:                    //boolean chunked_out = false;
2379:                    out.println(reqProtocol + " " + resCode + " " + resMessage);
2380:
2381:                    Enumeration he = resHeaderNames.keys();
2382:                    while (he.hasMoreElements()) {
2383:                        String name = (String) he.nextElement();
2384:                        Object o = resHeaderNames.get(name);
2385:                        if (o instanceof  String) {
2386:                            String value = (String) o;
2387:                            if (value != null) // just in case
2388:                                out.println(name + ": " + value);
2389:                            /* moved to servlet
2390:                            if (TRANSFERENCODING.equals(name) && CHUNKED.equals(value))
2391:                            chunked_out = true;*/
2392:                        } else if (o instanceof  String[]) {
2393:                            String[] values = (String[]) o;
2394:                            out.println(name + ": " + values[0]);
2395:                            for (int i = 0; i < values.length; i++)
2396:                                out.print("," + values[i]);
2397:                            out.println();
2398:                        }
2399:                    }
2400:                    StringBuffer sb = null;
2401:                    Cookie cc = null;
2402:                    // add session cookie
2403:                    // if cookie based session
2404:                    if (sessionCookieValue != null) {
2405:                        if (outCookies == null)
2406:                            outCookies = new Vector();
2407:                        cc = new Cookie(SESSION_COOKIE_NAME, sessionCookieValue);
2408:                        cc.setMaxAge(Math.abs(Serve.expiredIn) * 60);
2409:                        outCookies.addElement(cc);
2410:                    }
2411:
2412:                    // how to remove a cookie
2413:                    //	cc = new Cookie(cookieName, "");
2414:                    //	cc.setMaxAge(0);
2415:                    //
2416:                    for (int i = 0; outCookies != null && i < outCookies.size(); i++) {
2417:                        if (sb == null)
2418:                            sb = new StringBuffer(SETCOOKIE + ": ");
2419:                        else
2420:                            //sb.append(',');
2421:                            sb.append("\r\n" + SETCOOKIE + ": "); // for IE not understanding the standard
2422:                        cc = (Cookie) outCookies.elementAt(i);
2423:                        sb.append(cc.getName());
2424:                        sb.append('=');
2425:                        sb.append(cc.getValue());
2426:                        if (cc.getComment() != null) {
2427:                            sb.append("; Comment=" + cc.getComment());
2428:                        }
2429:                        if (cc.getDomain() != null) {
2430:                            sb.append("; Domain=" + cc.getDomain());
2431:                        }
2432:
2433:                        if (cc.getMaxAge() >= 0) {
2434:                            sb.append("; expires=");
2435:                            sb.append(expdatefmt.format(new Date(System
2436:                                    .currentTimeMillis()
2437:                                    + 1000 * cc.getMaxAge())));
2438:                        }
2439:                        if (cc.getPath() != null) {
2440:                            sb.append("; Path=" + cc.getPath());
2441:                        }
2442:                        if (cc.getSecure()) {
2443:                            sb.append("; Secure");
2444:                        }
2445:                        if (cc.getVersion() > 0) {
2446:                            sb.append("; Version=" + cc.getVersion());
2447:                        }
2448:                    }
2449:                    if (sb != null) {
2450:                        out.println(sb.toString());
2451:                        //System.err.println("We sent cookies: "+sb);
2452:                    }
2453:                    out.println("");
2454:                    out.flush();
2455:                    //if (chunked_out) ((ServeOutputStream)out).setChunked(true);
2456:                }
2457:            }
2458:
2459:            /// Writes an error response using the specified status code and message.
2460:            // @param resCode the status code
2461:            // @param resMessage the status message
2462:            // @exception IOException if an I/O error has occurred
2463:            public void sendError(int resCode, String resMessage)
2464:                    throws IOException {
2465:                setStatus(resCode, resMessage);
2466:                realSendError();
2467:            }
2468:
2469:            /// Writes an error response using the specified status code and a default
2470:            // message.
2471:            // @param resCode the status code
2472:            // @exception IOException if an I/O error has occurred
2473:            public void sendError(int resCode) throws IOException {
2474:                setStatus(resCode);
2475:                realSendError();
2476:            }
2477:
2478:            private void realSendError() throws IOException {
2479:                if (isCommitted())
2480:                    throw new IllegalStateException(
2481:                            "Can not send error, headers have been already written");
2482:                synchronized (out) {
2483:                    // no more out after error
2484:                    ((ServeOutputStream) out).setReturnedAsStream(true);
2485:                    ((ServeOutputStream) out).setReturnedAsWriter(true);
2486:                }
2487:                setContentType("text/html");
2488:                StringBuffer sb = new StringBuffer(100);
2489:                sb.append("<HTML><HEAD>").append(
2490:                        "<TITLE>" + resCode + " " + resMessage + "</TITLE>")
2491:                        .append("</HEAD><BODY BGCOLOR=\"#F1D0F2\">").append(
2492:                                "<H2>" + resCode + " " + resMessage + "</H2>")
2493:                        .append("<HR>");
2494:                Serve.Identification.writeAddress(sb);
2495:                sb.append("</BODY></HTML>");
2496:                setContentLength(sb.length());
2497:                out.print(sb.toString());
2498:                out.flush();
2499:            }
2500:
2501:            /// Sends a redirect message to the client using the specified redirect
2502:            // location URL.
2503:            // @param location the redirect location URL
2504:            // @exception IOException if an I/O error has occurred
2505:            public void sendRedirect(String location) throws IOException {
2506:                if (isCommitted())
2507:                    throw new IllegalStateException(
2508:                            "Can not redirect, headers have been already written");
2509:                synchronized (out) {
2510:                    // no more out after redirect
2511:                    ((ServeOutputStream) out).setReturnedAsStream(true);
2512:                    ((ServeOutputStream) out).setReturnedAsWriter(true);
2513:                }
2514:                setHeader("Location", location);
2515:                setStatus(SC_MOVED_TEMPORARILY);
2516:                setContentType("text/html");
2517:                StringBuffer sb = new StringBuffer(200);
2518:                sb.append("<HTML><HEAD>" + "<TITLE>" + SC_MOVED_TEMPORARILY
2519:                        + " Moved</TITLE>"
2520:                        + "</HEAD><BODY BGCOLOR=\"#F1D0F2\">" + "<H2>"
2521:                        + SC_MOVED_TEMPORARILY + " Moved</H2>"
2522:                        + "This document has moved <a href=" + location
2523:                        + ">here.<HR>");
2524:                Serve.Identification.writeAddress(sb);
2525:                sb.append("</BODY></HTML>");
2526:                setContentLength(sb.length());
2527:                // to avoid further out
2528:                out.print(sb.toString());
2529:                out.flush();
2530:            }
2531:
2532:            // URL session-encoding stuff.  Not implemented, but the API is here
2533:            // for compatibility.
2534:
2535:            /// Encodes the specified URL by including the session ID in it, or, if
2536:            // encoding is not needed, returns the URL unchanged. The
2537:            // implementation of this method should include the logic to determine
2538:            // whether the session ID needs to be encoded in the URL. For example,
2539:            // if the browser supports cookies, or session tracking is turned off,
2540:            // URL encoding is unnecessary.
2541:            // <P>
2542:            // All URLs emitted by a Servlet should be run through this method.
2543:            // Otherwise, URL rewriting cannot be used with browsers which do not
2544:            // support cookies.
2545:            public String encodeUrl(String url) {
2546:                return url;
2547:            }
2548:
2549:            /// Encodes the specified URL for use in the sendRedirect method or, if
2550:            // encoding is not needed, returns the URL unchanged. The
2551:            // implementation of this method should include the logic to determine
2552:            // whether the session ID needs to be encoded in the URL.  Because the
2553:            // rules for making this determination differ from those used to
2554:            // decide whether to encode a normal link, this method is seperate
2555:            // from the encodeUrl method.
2556:            // <P>
2557:            // All URLs sent to the HttpServletResponse.sendRedirect method should be
2558:            // run through this method.  Otherwise, URL rewriting cannot be used with
2559:            // browsers which do not support cookies.
2560:            public String encodeRedirectUrl(String url) {
2561:                return url;
2562:            }
2563:
2564:        }
2565:
2566:        class BasicAuthRealm extends Hashtable {
2567:            String name;
2568:
2569:            BasicAuthRealm(String name) {
2570:                this .name = name;
2571:            }
2572:
2573:            String name() {
2574:                return name;
2575:            }
2576:        }
2577:
2578:        class ServeInputStream extends ServletInputStream {
2579:            /* ------------------------------------------------------------ */
2580:            /** The actual input stream.
2581:             */
2582:            private BufferedInputStream in;
2583:            private int chunksize = 0;
2584:            private boolean chunking = false;
2585:            private boolean returnedAsReader, returnedAsStream;
2586:
2587:            /* ------------------------------------------------------------ */
2588:            /** Constructor
2589:             */
2590:            public ServeInputStream(InputStream in) {
2591:                this .in = new BufferedInputStream(in);
2592:            }
2593:
2594:            /* ------------------------------------------------------------ */
2595:            /** 
2596:             * @param chunking 
2597:             */
2598:            public void chunking(boolean chunking) {
2599:                this .chunking = chunking;
2600:            }
2601:
2602:            /* ------------------------------------------------------------ */
2603:            /** Read a line ended by CR or CRLF or LF.
2604:             * More forgiving of line termination than ServletInputStream.readLine().
2605:             * This method only read raw data, that may be chunked.  Calling
2606:             * ServletInputStream.readLine() will always return unchunked data.
2607:             */
2608:            // TODO: won't work with encoding
2609:            public String readLine() throws IOException {
2610:                StringBuffer buf = new StringBuffer(1024);
2611:
2612:                int c;
2613:                boolean cr = false;
2614:                boolean lf = false;
2615:
2616:                LineLoop: while ((c = chunking ? read() : in.read()) != -1) {
2617:                    switch (c) {
2618:                    case 10:
2619:                        lf = true;
2620:                        break LineLoop;
2621:
2622:                    case 13:
2623:                        cr = true;
2624:                        if (!chunking)
2625:                            in.mark(2);
2626:                        break;
2627:
2628:                    default:
2629:                        if (cr) {
2630:                            //if (chunking)
2631:                            //log("Cannot handle CR in chunking mode");
2632:                            in.reset();
2633:                            break LineLoop;
2634:                        } else
2635:                            buf.append((char) c);
2636:                        break;
2637:                    }
2638:                }
2639:
2640:                if (c == -1 && buf.length() == 0)
2641:                    return null;
2642:                //System.err.println(buf.toString()); //###
2643:
2644:                return buf.toString();
2645:            }
2646:
2647:            /* ------------------------------------------------------------ */
2648:            public int read() throws IOException {
2649:                if (chunking) {
2650:                    int b = -1;
2651:                    if (chunksize <= 0 && getChunkSize() <= 0)
2652:                        return -1;
2653:                    b = in.read();
2654:                    chunksize = (b < 0) ? -1 : (chunksize - 1);
2655:                    return b;
2656:                }
2657:
2658:                return in.read();
2659:            }
2660:
2661:            /* ------------------------------------------------------------ */
2662:            public int read(byte b[]) throws IOException {
2663:                return read(b, 0, b.length);
2664:            }
2665:
2666:            /* ------------------------------------------------------------ */
2667:            public int read(byte b[], int off, int len) throws IOException {
2668:                if (chunking) {
2669:                    if (chunksize <= 0 && getChunkSize() <= 0)
2670:                        return -1;
2671:                    if (len > chunksize)
2672:                        len = chunksize;
2673:                    len = in.read(b, off, len);
2674:                    chunksize = (len < 0) ? -1 : (chunksize - len);
2675:                } else
2676:                    len = in.read(b, off, len);
2677:                //System.err.println(new String(b,off,len)); //###        
2678:
2679:                return len;
2680:            }
2681:
2682:            /* ------------------------------------------------------------ */
2683:            public long skip(long len) throws IOException {
2684:                if (chunking) {
2685:                    if (chunksize <= 0 && getChunkSize() <= 0)
2686:                        return -1;
2687:                    if (len > chunksize)
2688:                        len = chunksize;
2689:                    len = in.skip(len);
2690:                    chunksize = (len < 0) ? -1 : (chunksize - (int) len);
2691:                } else
2692:                    len = in.skip(len);
2693:                return len;
2694:            }
2695:
2696:            /* ------------------------------------------------------------ */
2697:            /** Available bytes to read without blocking.
2698:             * If you are unlucky may return 0 when there are more
2699:             */
2700:            public int available() throws IOException {
2701:                if (chunking) {
2702:                    int len = in.available();
2703:                    if (len <= chunksize)
2704:                        return len;
2705:                    return chunksize;
2706:                }
2707:
2708:                return in.available();
2709:            }
2710:
2711:            /* ------------------------------------------------------------ */
2712:            public void close() throws IOException {
2713:                in.close();
2714:                chunksize = -1;
2715:            }
2716:
2717:            /* ------------------------------------------------------------ */
2718:            /** Mark is not supported
2719:             * @return false
2720:             */
2721:            public boolean markSupported() {
2722:                return false;
2723:            }
2724:
2725:            /* ------------------------------------------------------------ */
2726:            /** Not Implemented
2727:             */
2728:            public void reset() {
2729:            }
2730:
2731:            /* ------------------------------------------------------------ */
2732:            /** Not Implemented
2733:             * @param readlimit 
2734:             */
2735:            public void mark(int readlimit) {
2736:            }
2737:
2738:            /* ------------------------------------------------------------ */
2739:            private int getChunkSize() throws IOException {
2740:                if (chunksize < 0)
2741:                    return -1;
2742:
2743:                chunksize = -1;
2744:
2745:                // Get next non blank line
2746:                chunking = false;
2747:                String line = readLine();
2748:                while (line != null && line.length() == 0)
2749:                    line = readLine();
2750:                chunking = true;
2751:
2752:                // Handle early EOF or error in format
2753:                if (line == null)
2754:                    return -1;
2755:
2756:                // Get chunksize
2757:                int i = line.indexOf(';');
2758:                if (i > 0)
2759:                    line = line.substring(0, i).trim();
2760:                chunksize = Integer.parseInt(line, 16);
2761:
2762:                // check for EOF
2763:                if (chunksize == 0) {
2764:                    chunksize = -1;
2765:                    // Look for footers
2766:                    chunking = false;
2767:                }
2768:                return chunksize;
2769:            }
2770:
2771:            boolean isReturnedAsStream() {
2772:                return returnedAsStream;
2773:            }
2774:
2775:            void setReturnedAsStream(boolean _on) {
2776:                returnedAsStream = _on;
2777:            }
2778:
2779:            boolean isReturnedAsReader() {
2780:                return returnedAsReader;
2781:            }
2782:
2783:            void setReturnedAsReader(boolean _on) {
2784:                returnedAsReader = _on;
2785:            }
2786:
2787:        }
2788:
2789:        class ServeOutputStream extends ServletOutputStream {
2790:
2791:            // underneath stream
2792:            private OutputStream out;
2793:            //private BufferedWriter writer; // for top speed
2794:            private ServeConnection conn;
2795:            private boolean returnedAsStream, returnedAsWriter;
2796:
2797:            public ServeOutputStream(OutputStream out, ServeConnection conn) {
2798:
2799:                this .out = out;
2800:                this .conn = conn;
2801:            }
2802:
2803:            public void print(String s) throws IOException {
2804:                write(s.getBytes());
2805:            }
2806:
2807:            public void write(int b) throws IOException {
2808:                conn.writeHeaders();
2809:                out.write(b);
2810:            }
2811:
2812:            public void write(byte[] b) throws IOException {
2813:                write(b, 0, b.length);
2814:            }
2815:
2816:            public void write(byte[] b, int off, int len) throws IOException {
2817:                conn.writeHeaders();
2818:                out.write(b, off, len);
2819:            }
2820:
2821:            public void flush() throws IOException {
2822:                conn.writeHeaders();
2823:                out.flush();
2824:            }
2825:
2826:            public void close() throws IOException {
2827:                conn.writeHeaders();
2828:                out.close();
2829:            }
2830:
2831:            boolean isReturnedAsStream() {
2832:                return returnedAsStream;
2833:            }
2834:
2835:            void setReturnedAsStream(boolean _set) {
2836:                returnedAsStream = _set;
2837:            }
2838:
2839:            boolean isReturnedAsWriter() {
2840:                return returnedAsWriter;
2841:            }
2842:
2843:            void setReturnedAsWriter(boolean _set) {
2844:                returnedAsWriter = _set;
2845:            }
2846:        }
2847:
2848:        /**
2849:         * Class PathTreeDictionary - this class allows to put path elements
2850:         * in format n1/n2/n2[/*.ext]
2851:         * and get match to a pattern and a unmatched tail
2852:         */
2853:        class PathTreeDictionary {
2854:            Node root_node;
2855:
2856:            PathTreeDictionary() {
2857:                root_node = new Node();
2858:            }
2859:
2860:            void put(String path, Object value) {
2861:                StringTokenizer st = new StringTokenizer(path, "\\/");
2862:                Node cur_node = root_node;
2863:                while (st.hasMoreTokens()) {
2864:                    String nodename = st.nextToken();
2865:                    Node node = (Node) cur_node.get(nodename);
2866:                    if (node == null) {
2867:                        node = new Node();
2868:                        cur_node.put(nodename, node);
2869:                    }
2870:                    cur_node = node;
2871:                }
2872:                cur_node.object = value;
2873:            }
2874:
2875:            /**
2876:             * This function looks up in the directory to find the perfect match
2877:             * and remove matching part from path, so if you need to keep
2878:             * original path, save it somewhere
2879:             */
2880:            Object[] get(String path) {
2881:                Object[] result = new Object[2];
2882:                if (path == null)
2883:                    return result;
2884:                char[] ps = path.toCharArray();
2885:                Node cur_node = root_node;
2886:                int p0 = 0, lm = 0; // last match
2887:                result[0] = cur_node.object;
2888:                boolean div_state = true;
2889:                for (int i = 0; i < ps.length; i++) {
2890:                    if (ps[i] == '/' || ps[i] == '\\') {
2891:                        if (div_state)
2892:                            continue;
2893:                        Node node = (Node) cur_node.get(new String(ps, p0, i
2894:                                - p0));
2895:                        if (node == null) {
2896:                            result[1] = new Integer(lm);
2897:                            return result;
2898:                        }
2899:                        if (node.object != null) {
2900:                            result[0] = node.object;
2901:                            lm = i;
2902:                        }
2903:                        cur_node = node;
2904:                        div_state = true;
2905:                    } else {
2906:                        if (div_state) {
2907:                            p0 = i;
2908:                            div_state = false;
2909:                        }
2910:                    }
2911:                }
2912:                cur_node = (Node) cur_node.get(new String(ps, p0, ps.length
2913:                        - p0));
2914:                if (cur_node != null && cur_node.object != null) {
2915:                    result[0] = cur_node.object;
2916:                    lm = ps.length;
2917:                }
2918:                result[1] = new Integer(lm);
2919:                return result;
2920:            }
2921:
2922:            Enumeration keys() {
2923:                Vector result = new Vector();
2924:                addSiblingNames(root_node, result, "");
2925:                return result.elements();
2926:            }
2927:
2928:            void addSiblingNames(Node node, Vector result, String path) {
2929:                Enumeration e = node.keys();
2930:                while (e.hasMoreElements()) {
2931:                    String pc = (String) e.nextElement();
2932:                    Node childNode = (Node) node.get(pc);
2933:                    pc = path + '/' + pc;
2934:                    if (childNode.object != null)
2935:                        result.addElement(pc);
2936:                    addSiblingNames(childNode, result, pc);
2937:                }
2938:            }
2939:
2940:            Enumeration elements() {
2941:                Vector result = new Vector();
2942:                addSiblingObjects(root_node, result);
2943:                return result.elements();
2944:            }
2945:
2946:            void addSiblingObjects(Node node, Vector result) {
2947:                Enumeration e = node.keys();
2948:                while (e.hasMoreElements()) {
2949:                    Node childNode = (Node) node.get(e.nextElement());
2950:                    if (childNode.object != null)
2951:                        result.addElement(childNode.object);
2952:                    addSiblingObjects(childNode, result);
2953:                }
2954:            }
2955:
2956:            class Node extends Hashtable {
2957:                Object object;
2958:            }
2959:        }
2960:
2961:        /**
2962:         * Http session support
2963:         */
2964:        class AcmeSession extends Hashtable implements  HttpSession {
2965:            private long createTime;
2966:            private long lastAccessTime;
2967:            private String id;
2968:            private int inactiveInterval; // in seconds
2969:            private boolean expired;
2970:            private ServletContext servletContext;
2971:            private HttpSessionContext sessionContext;
2972:
2973:            // TODO: check in documentation what is default inactive interval and what means 0  
2974:            // and what is mesurement unit
2975:            AcmeSession(String id, ServletContext servletContext,
2976:                    HttpSessionContext sessionContext) {
2977:                this (id, 0, servletContext, sessionContext);
2978:            }
2979:
2980:            AcmeSession(String id, int inactiveInterval,
2981:                    ServletContext servletContext,
2982:                    HttpSessionContext sessionContext) {
2983:                createTime = System.currentTimeMillis();
2984:                this .id = id;
2985:                this .inactiveInterval = inactiveInterval;
2986:                this .servletContext = servletContext;
2987:                this .sessionContext = sessionContext;
2988:            }
2989:
2990:            public long getCreationTime() {
2991:                return createTime;
2992:            }
2993:
2994:            public String getId() {
2995:                return id;
2996:            }
2997:
2998:            public long getLastAccessedTime() {
2999:                return lastAccessTime;
3000:            }
3001:
3002:            public void setMaxInactiveInterval(int interval) {
3003:                inactiveInterval = interval;
3004:            }
3005:
3006:            public int getMaxInactiveInterval() {
3007:                return inactiveInterval;
3008:            }
3009:
3010:            /**
3011:             * @deprecated 
3012:             */
3013:            public HttpSessionContext getSessionContext() {
3014:
3015:                return sessionContext;
3016:            }
3017:
3018:            /**
3019:             * Returns the ServletContext to which this session belongs.
3020:             * @return The ServletContext object for the web application
3021:             * @ince 2.3 
3022:             */
3023:            public ServletContext getServletContext() {
3024:                return servletContext;
3025:            }
3026:
3027:            public java.lang.Object getAttribute(java.lang.String name)
3028:                    throws IllegalStateException {
3029:                if (expired)
3030:                    throw new IllegalStateException();
3031:                return get((Object) name);
3032:            }
3033:
3034:            public java.lang.Object getValue(java.lang.String name)
3035:                    throws IllegalStateException {
3036:                return getAttribute(name);
3037:            }
3038:
3039:            public java.util.Enumeration getAttributeNames()
3040:                    throws IllegalStateException {
3041:                if (expired)
3042:                    throw new IllegalStateException();
3043:                return keys();
3044:            }
3045:
3046:            public java.lang.String[] getValueNames()
3047:                    throws IllegalStateException {
3048:                Enumeration e = getAttributeNames();
3049:                Vector names = new Vector();
3050:                while (e.hasMoreElements())
3051:                    names.addElement(e.nextElement());
3052:                String[] result = new String[names.size()];
3053:                names.copyInto(result);
3054:                return result;
3055:            }
3056:
3057:            public void setAttribute(String name, Object value)
3058:                    throws IllegalStateException {
3059:                if (expired)
3060:                    throw new IllegalStateException();
3061:                Object oldValue = put((Object) name, value);
3062:                if (oldValue != null
3063:                        && oldValue instanceof  HttpSessionBindingListener)
3064:                    ((HttpSessionBindingListener) oldValue)
3065:                            .valueUnbound(new HttpSessionBindingEvent(this ,
3066:                                    name));
3067:                if (value instanceof  HttpSessionBindingListener)
3068:                    ((HttpSessionBindingListener) value)
3069:                            .valueBound(new HttpSessionBindingEvent(this , name));
3070:            }
3071:
3072:            public void putValue(String name, Object value)
3073:                    throws IllegalStateException {
3074:                setAttribute(name, value);
3075:            }
3076:
3077:            public void removeAttribute(java.lang.String name)
3078:                    throws IllegalStateException {
3079:                if (expired)
3080:                    throw new IllegalStateException();
3081:                Object value = remove((Object) name);
3082:                if (value != null
3083:                        && value instanceof  HttpSessionBindingListener)
3084:                    ((HttpSessionBindingListener) value)
3085:                            .valueUnbound(new HttpSessionBindingEvent(this ,
3086:                                    name));
3087:            }
3088:
3089:            public void removeValue(java.lang.String name)
3090:                    throws IllegalStateException {
3091:                removeAttribute(name);
3092:            }
3093:
3094:            public synchronized void invalidate() throws IllegalStateException {
3095:                if (expired)
3096:                    throw new IllegalStateException();
3097:                Enumeration e = getAttributeNames();
3098:                while (e.hasMoreElements()) {
3099:                    removeAttribute((String) e.nextElement());
3100:                }
3101:                setExpired(true);
3102:                // would be nice remove it from hash table also
3103:            }
3104:
3105:            public boolean isNew() throws IllegalStateException {
3106:                if (expired)
3107:                    throw new IllegalStateException();
3108:                return lastAccessTime == 0;
3109:            }
3110:
3111:            private void setExpired(boolean expired) {
3112:                this .expired = expired;
3113:            }
3114:
3115:            boolean isValid() {
3116:                return !expired;
3117:            }
3118:
3119:            void userTouch() {
3120:                lastAccessTime = System.currentTimeMillis();
3121:            }
3122:        }
3123:
3124:        // TODO: reconsider implementation by providing
3125:        // inner class implementing HttpSessionContext
3126:        // and returning it on request
3127:        // to avoid casting this class to Hashtable
3128:        class HttpSessionContextImpl extends Hashtable implements 
3129:                HttpSessionContext {
3130:
3131:            public java.util.Enumeration getIds() {
3132:                return keys();
3133:            }
3134:
3135:            public HttpSession getSession(java.lang.String sessionId) {
3136:                return (HttpSession) get(sessionId);
3137:            }
3138:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.