You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/01/30 05:22:48 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/servlets WarFileServlet.java DefaultServlet.java
costin 00/01/29 20:22:48
Modified: src/etc server.xml
src/share/org/apache/tomcat/context DefaultCMSetter.java
WebXmlInterceptor.java
src/share/org/apache/tomcat/core Context.java
ContextManager.java RequestInterceptor.java
src/share/org/apache/tomcat/deployment
WebApplicationReader.java
src/share/org/apache/tomcat/request SessionInterceptor.java
SimpleMapper.java
src/share/org/apache/tomcat/servlets DefaultServlet.java
Added: src/share/org/apache/tomcat/context
WarWebXmlInterceptor.java
src/share/org/apache/tomcat/servlets WarFileServlet.java
Removed: src/share/org/apache/tomcat/context WarInterceptor.java
src/share/org/apache/tomcat/request
ContextMapperInterceptor.java
MapperInterceptor.java
Log:
- Started to move "serve-from-war" code in different modules.
That will make tomcat a bit faster ( since we don't have to check
if the context is from war for each request ) and probably a bit simpler
( for serve-from-war you just need to set the right interceptors and
default servlet in the context, and the request processing will be the
same, with war enabled modules doing the processing)
- Removed the "getContextPath()" hack. Now the requestInterceptor has
2 methods, one will parse the context path and second will parse the rest.
( not final - but it's an improvement vs. getContextPath() ).
- moved all code that depends on tomcat.deploy into that package, now
there is only one method call to read a web.xml into a context.
Other changes:
- removed adminPort and context comments from server.xml - admin will
probably have a special tag and section, and we need to reorg. the
context tag
Revision Changes Path
1.3 +1 -10 jakarta-tomcat/src/etc/server.xml
Index: server.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/etc/server.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- server.xml 2000/01/29 05:52:33 1.2
+++ server.xml 2000/01/30 04:22:45 1.3
@@ -1,16 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
-<Server adminPort="-1" workDir="work">
+<Server>
<ContextManager port="8080" hostName="" inet="">
-
-<!--
- Defaults:
- defaultSessionTimeOut="30"
- isWARExpanded="true"
- isWARValidated="false"
- isInvokerEnabled="true"
- isWorkDirPersistent="false"
--->
<Connector className="org.apache.tomcat.service.http.HttpAdapter">
</Connector>
1.2 +5 -4 jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java
Index: DefaultCMSetter.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultCMSetter.java 2000/01/29 05:51:28 1.1
+++ DefaultCMSetter.java 2000/01/30 04:22:45 1.2
@@ -100,12 +100,13 @@
if( ! riE.hasMoreElements() ) {
// nothing set up by starter, add default ones
if(cm.getDebug()>0) cm.log("Setting default interceptors ");
- cm.addRequestInterceptor(new ContextMapperInterceptor( cm ));
- cm.addRequestInterceptor(new SessionInterceptor());
- // addRequestInterceptor(new MapperInterceptor());
// Use the simplified mapper - revert if too many bugs and
- cm.addRequestInterceptor(new SimpleMapper());
+ SimpleMapper smap=new SimpleMapper();
+ smap.setContextManager( cm );
+ cm.addRequestInterceptor(smap);
+
+ cm.addRequestInterceptor(new SessionInterceptor());
}
return 0;
1.6 +9 -238 jakarta-tomcat/src/share/org/apache/tomcat/context/WebXmlInterceptor.java
Index: WebXmlInterceptor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/WebXmlInterceptor.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- WebXmlInterceptor.java 2000/01/29 05:51:28 1.5
+++ WebXmlInterceptor.java 2000/01/30 04:22:45 1.6
@@ -82,255 +82,26 @@
}
public int handleContextInit(Context ctx) {
+ System.out.println("Context(" + ctx.getPath() + "): " + ctx.getDocBase());
+
// process base configuration
+ WebApplicationReader webXmlReader=new WebApplicationReader();
+
+ // read default web.xml
try {
- Class webApplicationDescriptor = Class.forName(
- "org.apache.tomcat.deployment.WebApplicationDescriptor");
- InputStream is =
- webApplicationDescriptor.getResourceAsStream("web.xml");
- String msg = sm.getString("context.getConfig.msg", "default");
-
- // No message for default !! System.out.println(msg);
+ webXmlReader.processDefaultWebApp( ctx );
- processWebApp(ctx, is, true);
+ InputStream is= new FileInputStream( ctx.getDocBase() + "/WEB-INF/web.xml");
+ webXmlReader.processWebApp(ctx, is);
} catch (Exception e) {
- String msg = sm.getString("context.getConfig.e", "default");
+ String msg = sm.getString("context.getConfig.e",ctx.getPath() + " " + ctx.getDocBase());
System.out.println(msg);
}
-
- // process webApp configuration
- String s = ctx.getDocumentBase().toString();
- if (ctx.getDocumentBase().getProtocol().equalsIgnoreCase("war")) {
- if (s.endsWith("/")) {
- s = s.substring(0, s.length() - 1);
- }
-
- s += "!/";
- }
-
- URL webURL = null;
- try {
- webURL = new URL(s + "/" + Constants.Context.ConfigFile);
-
- InputStream is = webURL.openConnection().getInputStream();
- // String msg = sm.getString("context.getConfig.msg",
- // webURL.toString());
-
- System.out.println("Context(" + ctx.getPath() + "): " + webURL.getFile());
-
- processWebApp(ctx, is, false);
- } catch (Exception e) {
- String msg = sm.getString("context.getConfig.e",
- (webURL != null) ? webURL.toString() : "not available");
-
- // go silent on this one
- // System.out.println(msg);
- }
return 0;
}
public int handleContextShutdown(Context ctx) {
return OK;
- }
-
- private void processWebApp(Context ctx, InputStream is, boolean internal) {
- if (is != null) {
- try {
- WebApplicationDescriptor webDescriptor =
- (new WebApplicationReader()).getDescriptor(is,
- new WebDescriptorFactoryImpl(),
- ctx.isWARValidated());
-
- ctx.setDescription( webDescriptor.getDescription());
- ctx.setDistributable( webDescriptor.isDistributable());
-
- Enumeration contextParameters=webDescriptor.getContextParameters();
- while (contextParameters.hasMoreElements()) {
- ContextParameter contextParameter =
- (ContextParameter)contextParameters.nextElement();
- ctx.setInitParameter(contextParameter.getName(),
- contextParameter.getValue());
- }
- ctx.setSessionTimeOut( webDescriptor.getSessionTimeout());
-
- processServlets(ctx, webDescriptor.getWebComponentDescriptors());
- processMimeMaps(ctx, webDescriptor.getMimeMappings());
- processWelcomeFiles(ctx, webDescriptor.getWelcomeFiles(),
- internal);
- processErrorPages(ctx, webDescriptor.getErrorPageDescriptors());
- } catch (Throwable e) {
- String msg = "config parse: " + e.getMessage();
-
- System.out.println(msg);
- }
- }
- }
-
- private void processServlets(Context ctx, Enumeration servlets) {
- // XXX
- // oh my ... this has suddenly turned rather ugly
- // perhaps the reader should do this normalization work
-
- while (servlets.hasMoreElements()) {
- WebComponentDescriptor webComponentDescriptor =
- (WebComponentDescriptor)servlets.nextElement();
- String name = webComponentDescriptor.getCanonicalName();
- String description = webComponentDescriptor.getDescription();
- String resourceName = null;
- boolean removeResource = false;
-
- if (webComponentDescriptor instanceof ServletDescriptor) {
- resourceName =
- ((ServletDescriptor)webComponentDescriptor).getClassName();
-
- if ( ctx.containsServletByName(name)) {
- String msg = sm.getString("context.dd.dropServlet",
- name + "(" + resourceName + ")" );
-
- System.out.println(msg);
-
- removeResource = true;
- ctx.removeServletByName(name);
- }
-
- ctx.addServlet(name, resourceName, description);
- } else if (webComponentDescriptor instanceof JspDescriptor) {
- resourceName =
- ((JspDescriptor)webComponentDescriptor).getJspFileName();
-
- if (! resourceName.startsWith("/")) {
- resourceName = "/" + resourceName;
- }
-
- if (ctx.containsJSP(resourceName)) {
- String msg = sm.getString("context.dd.dropServlet",
- resourceName);
-
- System.out.println(msg);
-
- removeResource = true;
- ctx.removeJSP(resourceName);
- }
-
- ctx.addJSP(name, resourceName, description);
- }
-
-
- // XXX ugly, but outside of context - the whole thing will be
- // rewriten, so don't worry
-
- // if the resource was already defined, override with the new definition
- // XXX I have very little ideea about what it does !
- if (removeResource) {
-
- Enumeration levels = ctx.getInitLevels();
-
- while (levels.hasMoreElements()) {
- Integer level = (Integer)levels.nextElement();
- Enumeration servletsOnLevel=ctx.getLoadableServlets( level );
-
- Vector buf = new Vector();
- while (servletsOnLevel.hasMoreElements()) {
- String servletName = (String)servletsOnLevel.nextElement();
-
- if (ctx.containsServletByName(servletName)) {
- buf.addElement(servletName);
- }
- }
- ctx.setLoadableServlets(level, buf);
- }
- }
-
- int loadOnStartUp = webComponentDescriptor.getLoadOnStartUp();
-
- if (loadOnStartUp > Integer.MIN_VALUE) {
- Integer key = new Integer(loadOnStartUp);
- ctx.addLoadableServlet( key, name );
-
- }
-
- Enumeration enum =
- webComponentDescriptor.getInitializationParameters();
- Hashtable initializationParameters = new Hashtable();
-
- while (enum.hasMoreElements()) {
- InitializationParameter initializationParameter =
- (InitializationParameter)enum.nextElement();
-
- initializationParameters.put(
- initializationParameter.getName(),
- initializationParameter.getValue());
- }
-
- ctx.setServletInitParams( webComponentDescriptor.getCanonicalName(),
- initializationParameters);
-
- enum = webComponentDescriptor.getUrlPatterns();
-
- while (enum.hasMoreElements()) {
- String mapping = (String)enum.nextElement();
-
- if (! mapping.startsWith("*.") &&
- ! mapping.startsWith("/")) {
- mapping = "/" + mapping;
- }
-
- if (! ctx.containsServlet(mapping) &&
- ! ctx.containsJSP(mapping)) {
- if (ctx.containsMapping(mapping)) {
- String msg = sm.getString("context.dd.dropMapping",
- mapping);
-
- System.out.println(msg);
-
- ctx.removeMapping(mapping);
- }
-
- ctx.addMapping(name, mapping);
- } else {
- String msg = sm.getString("context.dd.ignoreMapping",
- mapping);
-
- System.out.println(msg);
- }
- }
- }
- }
-
- private void processMimeMaps(Context ctx, Enumeration mimeMaps) {
- while (mimeMaps.hasMoreElements()) {
- MimeMapping mimeMapping = (MimeMapping)mimeMaps.nextElement();
-
- ctx.addContentType( mimeMapping.getExtension(),
- mimeMapping.getMimeType());
- }
- }
-
- private void processWelcomeFiles(Context ctx, Enumeration welcomeFiles,
- boolean internal) {
- if (! internal && welcomeFiles.hasMoreElements()) {
- ctx.removeWelcomeFiles();
- }
-
- while (welcomeFiles.hasMoreElements()) {
- ctx.addWelcomeFile((String)welcomeFiles.nextElement());
- }
- }
-
- private void processErrorPages(Context ctx, Enumeration errorPages) {
- while (errorPages.hasMoreElements()) {
- ErrorPageDescriptor errorPageDescriptor =
- (ErrorPageDescriptor)errorPages.nextElement();
- String key = null;
-
- if (errorPageDescriptor.getErrorCode() > -1) {
- key = String.valueOf(errorPageDescriptor.getErrorCode());
- } else {
- key = errorPageDescriptor.getExceptionType();
- }
-
- ctx.addErrorPage(key, errorPageDescriptor.getLocation());
- }
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/context/WarWebXmlInterceptor.java
Index: WarWebXmlInterceptor.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.context;
import org.apache.tomcat.core.*;
import org.apache.tomcat.core.Constants;
import org.apache.tomcat.util.*;
import org.apache.tomcat.deployment.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.http.*;
/**
* Will configure the context using the default web.xml
*
* This interceptor is used when "serving from WAR" case.
*
* @author costin@dnt.ro
*/
public class WarWebXmlInterceptor implements ContextInterceptor {
private static StringManager sm =StringManager.getManager("org.apache.tomcat.core");
public WarWebXmlInterceptor() {
}
public int handleContextInit(Context ctx) {
if (! ctx.getDocumentBase().getProtocol().equalsIgnoreCase("war")) {
return 0;
}
// process base configuration
WebApplicationReader webXmlReader=new WebApplicationReader();
try {
// read default web.xml
webXmlReader.processDefaultWebApp( ctx );
// process webApp configuration
String s = ctx.getDocumentBase().toString();
if (s.endsWith("/"))
s = s.substring(0, s.length() - 1);
URL webURL = null;
webURL = new URL(s + "!/" + Constants.Context.ConfigFile);
InputStream is = webURL.openConnection().getInputStream();
System.out.println("Context(" + ctx.getPath() + "): " + webURL.getFile());
webXmlReader.processWebApp(ctx, is);
} catch (Exception e) {
String msg = sm.getString("context.getConfig.e",
ctx.getPath() + " " + ctx.getDocBase() );
}
return 0;
}
public int handleContextShutdown(Context ctx) {
return OK;
}
}
1.36 +19 -4 jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java
Index: Context.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- Context.java 2000/01/29 05:51:31 1.35
+++ Context.java 2000/01/30 04:22:46 1.36
@@ -180,6 +180,22 @@
this.path = path;
}
+ /* NOTE: if docBase is a URL to a remote location, we should download
+ the context and unpack it. It is _very_ inefficient to serve
+ files from a remote location ( at least 2x slower )
+ */
+
+ /** DocBase points to the web application files.
+ *
+ * There is no restriction on the syntax and content of DocBase,
+ * it's up to the various modules to interpret this and use it.
+ * For example, to server from a war file you can use war: protocol,
+ * and set up War interceptors.
+ *
+ * "Basic" tomcat treats it is a file ( either absolute or relative to
+ * the CM home ). XXX Make it absolute ??
+ *
+ */
public void setDocBase( String docB ) {
this.docBase=docB;
}
@@ -325,7 +341,9 @@
// if we can't return a servlet, so it's more probable
// servlets will check for null than IllegalArgument
}
- return contextM.getContextByPath(path);
+ Request lr=contextM.createRequest( this, path );
+ getContextManager().processRequest(lr);
+ return lr.getContext();
}
public void log(String msg, Throwable t) {
@@ -525,9 +543,6 @@
// XXX who uses servletBase ???
URL servletBase = getDocumentBase();
this.setServletBase(servletBase);
-
- // expand WAR
- new WarInterceptor().handleContextInit( this );
// Read context's web.xml
new WebXmlInterceptor().handleContextInit( this );
1.29 +4 -9 jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java
Index: ContextManager.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- ContextManager.java 2000/01/29 06:08:48 1.28
+++ ContextManager.java 2000/01/30 04:22:46 1.29
@@ -397,6 +397,10 @@
if(debug>2) log("");
for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).handleRequestContextMap( req );
+ }
+
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
((RequestInterceptor)requestInterceptors.elementAt(i)).handleRequest( req );
}
@@ -405,15 +409,6 @@
if(debug>2) log("");
return 0;
}
-
- // XXX XXX hack - we need to create a new request !
- ContextMapperInterceptor contextInterceptor=new ContextMapperInterceptor( this );
- public Context getContextByPath(String path ) {
- // XXX XXX XXX need to create a sub-request !!!!
- //
- return contextInterceptor.getContextByPath( path );
- }
-
// -------------------- Sub-Request mechanism --------------------
1.2 +30 -4 jakarta-tomcat/src/share/org/apache/tomcat/core/RequestInterceptor.java
Index: RequestInterceptor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestInterceptor.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- RequestInterceptor.java 2000/01/07 19:14:11 1.1
+++ RequestInterceptor.java 2000/01/30 04:22:46 1.2
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestInterceptor.java,v 1.1 2000/01/07 19:14:11 costin Exp $
- * $Revision: 1.1 $
- * $Date: 2000/01/07 19:14:11 $
+ * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestInterceptor.java,v 1.2 2000/01/30 04:22:46 costin Exp $
+ * $Revision: 1.2 $
+ * $Date: 2000/01/30 04:22:46 $
*
* ====================================================================
*
@@ -73,5 +73,31 @@
public interface RequestInterceptor {
public static final int OK=0;
- public int handleRequest(Request request);
+ /** Will detect the context path for a request
+ */
+ // public int contextMap(Request request);
+ // XXX name will change!
+ public int handleRequestContextMap(Request request);
+
+ /** Handle mapping inside a context
+ */
+ // public int requestMap(Request request);
+
+ /** Security
+ */
+ // public int authentication(Request request);
+ // public int authorization(Request request);
+
+ /** This handle knows how to guess the session id
+ from a request ( SSL, cookie, rewriting ).
+ Note that the request need
+ */
+ // public int sessionId(Request request);
+
+ // public int preService(Request request);
+ // public int postService(Request request);
+
+ // public int log(Request request);
+
+ public int handleRequest( Request request);
}
1.3 +199 -4 jakarta-tomcat/src/share/org/apache/tomcat/deployment/WebApplicationReader.java
Index: WebApplicationReader.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/deployment/WebApplicationReader.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- WebApplicationReader.java 1999/11/13 00:50:27 1.2
+++ WebApplicationReader.java 2000/01/30 04:22:46 1.3
@@ -60,10 +60,9 @@
import org.apache.tomcat.util.XMLParser;
import org.apache.tomcat.util.XMLTree;
-import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.Vector;
-import java.util.StringTokenizer;
+import org.apache.tomcat.core.*;
+import java.io.*;
+import java.util.*;
/**
* I am a class that translates an input steram containting an
@@ -731,4 +730,200 @@
return sessionTimeOut.intValue();
}
+ // -------------------- Context setup--------------------
+ public void processDefaultWebApp(Context ctx) throws Exception {
+ Class webApplicationDescriptor = this.getClass();
+ InputStream is =
+ webApplicationDescriptor.getResourceAsStream("web.xml");
+ processWebApp(ctx, is);
+ }
+
+ public void processWebApp(Context ctx, InputStream is) throws Exception {
+ WebApplicationDescriptor webDescriptor =getDescriptor(is,
+ new WebDescriptorFactoryImpl(),
+ ctx.isWARValidated());
+
+ ctx.setDescription( webDescriptor.getDescription());
+ ctx.setDistributable( webDescriptor.isDistributable());
+
+ Enumeration contextParameters=webDescriptor.getContextParameters();
+ while (contextParameters.hasMoreElements()) {
+ ContextParameter contextParameter =
+ (ContextParameter)contextParameters.nextElement();
+ ctx.setInitParameter(contextParameter.getName(),
+ contextParameter.getValue());
+ }
+ ctx.setSessionTimeOut( webDescriptor.getSessionTimeout());
+
+ processServlets(ctx, webDescriptor.getWebComponentDescriptors());
+ processMimeMaps(ctx, webDescriptor.getMimeMappings());
+ processWelcomeFiles(ctx, webDescriptor.getWelcomeFiles());
+ processErrorPages(ctx, webDescriptor.getErrorPageDescriptors());
+ }
+
+ private void processServlets(Context ctx, Enumeration servlets) {
+ // XXX
+ // oh my ... this has suddenly turned rather ugly
+ // perhaps the reader should do this normalization work
+
+ while (servlets.hasMoreElements()) {
+ WebComponentDescriptor webComponentDescriptor =
+ (WebComponentDescriptor)servlets.nextElement();
+ String name = webComponentDescriptor.getCanonicalName();
+ String description = webComponentDescriptor.getDescription();
+ String resourceName = null;
+ boolean removeResource = false;
+
+ if (webComponentDescriptor instanceof ServletDescriptor) {
+ resourceName =
+ ((ServletDescriptor)webComponentDescriptor).getClassName();
+
+ if ( ctx.containsServletByName(name)) {
+// String msg = sm.getString("context.dd.dropServlet",
+// name + "(" + resourceName + ")" );
+
+// System.out.println(msg);
+
+ removeResource = true;
+ ctx.removeServletByName(name);
+ }
+
+ ctx.addServlet(name, resourceName, description);
+ } else if (webComponentDescriptor instanceof JspDescriptor) {
+ resourceName =
+ ((JspDescriptor)webComponentDescriptor).getJspFileName();
+
+ if (! resourceName.startsWith("/")) {
+ resourceName = "/" + resourceName;
+ }
+
+ if (ctx.containsJSP(resourceName)) {
+// String msg = sm.getString("context.dd.dropServlet",
+// resourceName);
+
+// System.out.println(msg);
+
+ removeResource = true;
+ ctx.removeJSP(resourceName);
+ }
+
+ ctx.addJSP(name, resourceName, description);
+ }
+
+
+ // XXX ugly, but outside of context - the whole thing will be
+ // rewriten, so don't worry
+
+ // if the resource was already defined, override with the new definition
+ // XXX I have very little ideea about what it does !
+ if (removeResource) {
+
+ Enumeration levels = ctx.getInitLevels();
+
+ while (levels.hasMoreElements()) {
+ Integer level = (Integer)levels.nextElement();
+ Enumeration servletsOnLevel=ctx.getLoadableServlets( level );
+
+ Vector buf = new Vector();
+ while (servletsOnLevel.hasMoreElements()) {
+ String servletName = (String)servletsOnLevel.nextElement();
+
+ if (ctx.containsServletByName(servletName)) {
+ buf.addElement(servletName);
+ }
+ }
+ ctx.setLoadableServlets(level, buf);
+ }
+ }
+
+ int loadOnStartUp = webComponentDescriptor.getLoadOnStartUp();
+
+ if (loadOnStartUp > Integer.MIN_VALUE) {
+ Integer key = new Integer(loadOnStartUp);
+ ctx.addLoadableServlet( key, name );
+
+ }
+
+ Enumeration enum =
+ webComponentDescriptor.getInitializationParameters();
+ Hashtable initializationParameters = new Hashtable();
+
+ while (enum.hasMoreElements()) {
+ InitializationParameter initializationParameter =
+ (InitializationParameter)enum.nextElement();
+
+ initializationParameters.put(
+ initializationParameter.getName(),
+ initializationParameter.getValue());
+ }
+
+ ctx.setServletInitParams( webComponentDescriptor.getCanonicalName(),
+ initializationParameters);
+
+ enum = webComponentDescriptor.getUrlPatterns();
+
+ while (enum.hasMoreElements()) {
+ String mapping = (String)enum.nextElement();
+
+ if (! mapping.startsWith("*.") &&
+ ! mapping.startsWith("/")) {
+ mapping = "/" + mapping;
+ }
+
+ if (! ctx.containsServlet(mapping) &&
+ ! ctx.containsJSP(mapping)) {
+ if (ctx.containsMapping(mapping)) {
+// String msg = sm.getString("context.dd.dropMapping",
+// mapping);
+
+// System.out.println(msg);
+
+ ctx.removeMapping(mapping);
+ }
+
+ ctx.addMapping(name, mapping);
+ } else {
+// String msg = sm.getString("context.dd.ignoreMapping",
+// mapping);
+
+// System.out.println(msg);
+ }
+ }
+ }
+ }
+
+ private void processMimeMaps(Context ctx, Enumeration mimeMaps) {
+ while (mimeMaps.hasMoreElements()) {
+ MimeMapping mimeMapping = (MimeMapping)mimeMaps.nextElement();
+
+ ctx.addContentType( mimeMapping.getExtension(),
+ mimeMapping.getMimeType());
+ }
+ }
+
+ private void processWelcomeFiles(Context ctx, Enumeration welcomeFiles ) {
+ if ( welcomeFiles.hasMoreElements()) {
+ ctx.removeWelcomeFiles();
+ }
+
+ while (welcomeFiles.hasMoreElements()) {
+ ctx.addWelcomeFile((String)welcomeFiles.nextElement());
+ }
+ }
+
+ private void processErrorPages(Context ctx, Enumeration errorPages) {
+ while (errorPages.hasMoreElements()) {
+ ErrorPageDescriptor errorPageDescriptor =
+ (ErrorPageDescriptor)errorPages.nextElement();
+ String key = null;
+
+ if (errorPageDescriptor.getErrorCode() > -1) {
+ key = String.valueOf(errorPageDescriptor.getErrorCode());
+ } else {
+ key = errorPageDescriptor.getExceptionType();
+ }
+
+ ctx.addErrorPage(key, errorPageDescriptor.getLocation());
+ }
+ }
}
1.4 +5 -0 jakarta-tomcat/src/share/org/apache/tomcat/request/SessionInterceptor.java
Index: SessionInterceptor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SessionInterceptor.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SessionInterceptor.java 2000/01/09 22:32:43 1.3
+++ SessionInterceptor.java 2000/01/30 04:22:47 1.4
@@ -110,4 +110,9 @@
return 0;
}
+
+ public int handleRequestContextMap( Request rrequest ) {
+ return 0;
+ }
+
}
1.2 +82 -1 jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper.java
Index: SimpleMapper.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SimpleMapper.java 2000/01/15 03:52:58 1.1
+++ SimpleMapper.java 2000/01/30 04:22:47 1.2
@@ -65,12 +65,24 @@
import org.apache.tomcat.util.*;
import java.util.Hashtable;
+/** Parse request URI and find ContextPath, ServletPath, PathInfo and QueryString
+ * Use a simple alghoritm - no optimizations or tricks.
+ * Also, no special features - no VirtualHost, user directories, etc.
+ *
+ * For "production" environment you should use either an optimized version
+ * or a real web server parser.
+ */
public class SimpleMapper implements RequestInterceptor {
int debug=0;
+ ContextManager cm;
public SimpleMapper() {
}
+ public void setContextManager( ContextManager cm ) {
+ this.cm=cm;
+ }
+
public void setDebug( int level ) {
debug=level;
}
@@ -78,7 +90,32 @@
void log( String msg ) {
System.out.println("SimpleMapper: " + msg );
}
-
+
+ /** First step of request porcessing is finding the Context.
+ * Advanced mappers will do only one parsing.
+ */
+ public int handleRequestContextMap( Request rrequest ) {
+ // someone else set it up, no need to worry
+ if( rrequest.getContext() != null )
+ return OK;
+
+ // resolve the server that we are for
+ String path = rrequest.getRequestURI();
+
+ Context ctx= this.getContextByPath(path);
+
+ // final fix on response & request
+ // rresponse.setServerHeader(server.getServerHeader());
+
+ String ctxPath = ctx.getPath();
+ String pathInfo =path.substring(ctxPath.length(),
+ path.length());
+ rrequest.setContext(ctx);
+ rrequest.updatePaths();
+ return OK;
+ }
+
+
public int handleRequest(Request req) {
Context context=req.getContext();
String path=req.getLookupPath();
@@ -238,6 +275,50 @@
return "/" + path;
}
+
+
+ // XXX XXX XXX need to fix this - it is used by getContext(String path) (costin)
+
+ /**
+ * Gets the context that is responsible for requests for a
+ * particular path. If no specifically assigned Context can be
+ * identified, returns the default Context.
+ *
+ * @param path The path for which a Context is requested
+ */
+ Context getContextByPath(String path) {
+ String realPath = path;
+ Context ctx = null;
+
+ // XXX
+ // needs help ... this needs to be optimized out.
+
+ lookup:
+ do {
+ ctx = cm.getContext(path);
+ if (ctx == null) {
+ int i = path.lastIndexOf('/');
+ if (i > -1 && path.length() > 1) {
+ path = path.substring(0, i);
+ if (path.length() == 0) {
+ path = "/";
+ }
+ } else {
+ // path too short
+ break lookup;
+ }
+ } else {
+ }
+ } while (ctx == null);
+
+ // no map - root context
+ if (ctx == null) {
+ ctx = cm.getContext( "" );
+ }
+
+ return ctx;
+ }
+
}
1.4 +40 -145 jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultServlet.java
Index: DefaultServlet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultServlet.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- DefaultServlet.java 2000/01/14 19:48:24 1.3
+++ DefaultServlet.java 2000/01/30 04:22:47 1.4
@@ -75,30 +75,41 @@
* @author James Todd [gonzo@eng.sun.com]
*/
public class DefaultServlet extends HttpServlet {
- private ServletContextFacade facade;
- private String servletInfo = "DefaultServlet";
+ private static final String datePattern = "EEE, dd MMM yyyyy HH:mm z";
+ private static final DateFormat dateFormat = new SimpleDateFormat(datePattern);
+
+ ServletContext contextF;
private Context context;
- private MimeMap mimeTypes;
- private String datePattern = "EEE, dd MMM yyyyy HH:mm z";
- private DateFormat dateFormat = new SimpleDateFormat(datePattern);
+ String docBase;
+ int debug=1;
public void init() throws ServletException {
- facade = (ServletContextFacade)getServletContext();
- context = facade.getRealContext();
- mimeTypes = context.getMimeMap();
+ contextF = getServletContext();
+ context = ((ServletContextFacade)getServletContext()).getRealContext();
+
+ // doesn't change - set it in init!
+ docBase = context.getDocBase();
+ if (! docBase.endsWith("/")) {
+ docBase += "/";
+ }
+
+ // debug
+ String dbg=getServletConfig().getInitParameter("debug");
+ if( dbg!=null) debug=1;
}
public String getServletInfo() {
- return this.servletInfo;
+ return "DefaultServlet";
}
public void doGet(HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
+ HttpServletResponse response)
+ throws ServletException, IOException
+ {
String pathInfo = (String)request.getAttribute(
- Constants.Attribute.PathInfo);
+ "javax.servlet.include.path_info");
String requestURI = (String)request.getAttribute(
- Constants.Attribute.RequestURI);
+ "javax.servlet.include.request_uri");
if (pathInfo == null) {
pathInfo = request.getPathInfo();
@@ -107,98 +118,20 @@
if (requestURI == null) {
requestURI = request.getRequestURI();
}
-
- // XXX XXX BAD BAD BAD - that means another request,
- // with the same informations !!!!!!!
- // It should use getMappedPath instead !!!
- URL url = getServletContext().getResource(pathInfo);
-
- // System.out.println("Resource: " + url + " PI: " + pathInfo);
- if (url != null) {
- if (url.getProtocol().equals("war") &&
- context.isWARExpanded()) {
- String s = context.getWARDir().toString() + pathInfo;
-
- url = URLUtil.resolve(s);
- }
-
- if (url.getProtocol().equalsIgnoreCase("file")) {
- // serve file
-
- File f = new File(url.getFile());
-
- // this takes care of File.getAbsolutePath()
- // and File.getName() troubles when running on
- // JDK 1.1.x/Windows
- //
- // BUT IT ALSO ALLOWS THE DREADED ".." AND "jsp." BUGS.
- // SO IT'S OUTTA HERE!
- //
- //f = new File(f.getCanonicalPath());
-
- if (f.exists()) {
- processFile(f, url, request, response);
- } else {
- response.sendError(response.SC_NOT_FOUND,
- "File Not Found: " + requestURI);
- }
- } else if (url.getProtocol().equalsIgnoreCase("war")) {
- // get content from war
-
- String documentBase = context.getDocumentBase().toString();
-
- if (documentBase.endsWith("/")) {
- documentBase = documentBase.substring(0,
- documentBase.length() - 1);
- }
-
- URL mappedURL = new URL(documentBase + "!" + pathInfo);
-
- serveURL(mappedURL, request, response);
- } else {
- // get content from url
-
- serveURL(url, request, response);
- }
- } else {
- System.out.println("Got null URL: " + url);
-
- response.sendError(response.SC_NOT_FOUND,
- "File Not Found<br>" + requestURI);
- }
- }
- private void processFile(File file, URL url,
- HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestURI = (String)request.getAttribute(
- Constants.Attribute.RequestURI);
-
- if (requestURI == null) {
- requestURI = request.getRequestURI();
- }
-
+ // Clean up pathInfo
+ File file = new File(docBase + pathInfo);
String absPath = file.getAbsolutePath();
- String docBase = "";
-
- if (context.getDocumentBase().getProtocol().equalsIgnoreCase("war") &&
- context.isWARExpanded()) {
- String s = context.getWARDir().getAbsolutePath();
-
- docBase = FileUtil.patch(s);
- } else {
- docBase = context.getDocumentBase().getFile();
- }
+
+ if( debug > 0 ) contextF.log( "DefaultServlet: " + absPath);
// take care of File.getAbsolutePath() troubles on
// jdk1.1.x/win
+ String patchedPath = FileUtil.patch(absPath);
+ if( debug > 0 && ! absPath.equals(patchedPath) )
+ contextF.log( "DefaultServlet: patched path" + patchedPath );
+ absPath=patchedPath;
- absPath = FileUtil.patch(absPath);
-
- if (! docBase.endsWith("/")) {
- docBase += "/";
- }
-
if (isFileMasked(docBase, absPath)) {
response.sendError(response.SC_NOT_FOUND);
return;
@@ -206,9 +139,9 @@
if (file.isDirectory()) {
// check for welcome file
-
String welcomeFile = getWelcomeFile(file);
-
+ if( debug > 0 ) contextF.log( "DefaultServlet: welcome file: " + welcomeFile);
+
if (welcomeFile != null) {
if (requestURI.endsWith("/")) {
String path = requestURI;
@@ -229,6 +162,7 @@
path = "/" + path;
}
+ if( debug > 0 ) contextF.log( "DefaultServlet: forward: " + path + " " + welcomeFile);
ServletContext context =
getServletContext().getContext(contextPath);
RequestDispatcher rd = context.getRequestDispatcher(
@@ -247,6 +181,7 @@
// do a redirect so that all relative
// urls work correctly
+ if( debug > 0 ) contextF.log( "DefaultServlet: redirect: " + requestURI);
if (! inInclude) {
response.sendRedirect(requestURI + "/");
}
@@ -259,9 +194,9 @@
} else {
// serve that file
// check that .jsp/ doesn't slip through on Windows!
-
- if (! url.getFile().endsWith("/") &&
- ! url.getFile().endsWith("\\")) {
+ if( debug > 0 ) contextF.log( "DefaultServlet: serving file: " + file);
+ if (! absPath.endsWith("/") &&
+ ! absPath.endsWith("\\")) {
serveFile(file, request, response);
} else {
response.sendError(response.SC_NOT_FOUND,
@@ -292,46 +227,6 @@
return welcomeFile;
}
- private void serveURL(URL url, HttpServletRequest request,
- HttpServletResponse response)
- throws IOException {
- try {
- URLConnection con = url.openConnection();
- con.connect();
-
- // XXX
- // lot of work needed here for when reading from a war
-
- String contentType = con.getContentType();
- int contentLength = con.getContentLength();
- String lastModified = Long.toString(con.getLastModified());
-
- response.setContentType((contentType != null) ?
- contentType : "text/html");
- response.setContentLength((contentLength >= 0) ?
- contentLength : 0);
- response.setHeader("Last-Modified",
- (lastModified != null) ? lastModified : "");
-
- InputStream in = con.getInputStream();
-
- serveStream(in, request, response);
- in.close();
- } catch (IOException e) {
- // To do a good error msg, first figure out what we're serving
-
- String requestURI = (String)request.getAttribute(
- Constants.Attribute.RequestURI);
-
- if (requestURI == null) {
- requestURI = request.getRequestURI();
- }
-
- response.sendError(response.SC_NOT_FOUND,
- "File Not Found<br>" + requestURI);
- }
- }
-
private void serveFile(File file, HttpServletRequest request,
HttpServletResponse response)
throws IOException {
@@ -377,7 +272,7 @@
}
}
- String mimeType = mimeTypes.getContentTypeFor(file.getName());
+ String mimeType = contextF.getMimeType( file.getName() );
if (mimeType == null) {
mimeType = "text/plain";
1.1 jakarta-tomcat/src/share/org/apache/tomcat/servlets/WarFileServlet.java
Index: WarFileServlet.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.servlets;
import org.apache.tomcat.core.*;
import org.apache.tomcat.core.Constants;
import org.apache.tomcat.util.*;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* Serve a file from a WAR.
*
* @author James Duncan Davidson [duncan@eng.sun.com]
* @author Jason Hunter [jch@eng.sun.com]
* @author James Todd [gonzo@eng.sun.com]
*/
public class WarFileServlet extends HttpServlet {
private ServletContextFacade facade;
private String servletInfo = "DefaultServlet";
private Context context;
private MimeMap mimeTypes;
private String datePattern = "EEE, dd MMM yyyyy HH:mm z";
private DateFormat dateFormat = new SimpleDateFormat(datePattern);
public void init() throws ServletException {
facade = (ServletContextFacade)getServletContext();
context = facade.getRealContext();
mimeTypes = context.getMimeMap();
}
public String getServletInfo() {
return this.servletInfo;
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String pathInfo = (String)request.getAttribute(
Constants.Attribute.PathInfo);
String requestURI = (String)request.getAttribute(
Constants.Attribute.RequestURI);
if (pathInfo == null) {
pathInfo = request.getPathInfo();
}
if (requestURI == null) {
requestURI = request.getRequestURI();
}
// XXX XXX BAD BAD BAD - that means another request,
// with the same informations !!!!!!!
// It should use getMappedPath instead !!!
URL url = getServletContext().getResource(pathInfo);
// System.out.println("Resource: " + url + " PI: " + pathInfo);
if (url != null) {
if (url.getProtocol().equals("war") &&
context.isWARExpanded()) {
String s = context.getWARDir().toString() + pathInfo;
url = URLUtil.resolve(s);
}
if (url.getProtocol().equalsIgnoreCase("file")) {
// serve file
File f = new File(url.getFile());
// this takes care of File.getAbsolutePath()
// and File.getName() troubles when running on
// JDK 1.1.x/Windows
//
// BUT IT ALSO ALLOWS THE DREADED ".." AND "jsp." BUGS.
// SO IT'S OUTTA HERE!
//
//f = new File(f.getCanonicalPath());
if (f.exists()) {
processFile(f, url, request, response);
} else {
response.sendError(response.SC_NOT_FOUND,
"File Not Found: " + requestURI);
}
} else if (url.getProtocol().equalsIgnoreCase("war")) {
// get content from war
String documentBase = context.getDocumentBase().toString();
if (documentBase.endsWith("/")) {
documentBase = documentBase.substring(0,
documentBase.length() - 1);
}
URL mappedURL = new URL(documentBase + "!" + pathInfo);
serveURL(mappedURL, request, response);
} else {
// get content from url
serveURL(url, request, response);
}
} else {
System.out.println("Got null URL: " + url);
response.sendError(response.SC_NOT_FOUND,
"File Not Found<br>" + requestURI);
}
}
private void processFile(File file, URL url,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String requestURI = (String)request.getAttribute(
Constants.Attribute.RequestURI);
if (requestURI == null) {
requestURI = request.getRequestURI();
}
String absPath = file.getAbsolutePath();
String docBase = "";
if (context.getDocumentBase().getProtocol().equalsIgnoreCase("war") &&
context.isWARExpanded()) {
String s = context.getWARDir().getAbsolutePath();
docBase = FileUtil.patch(s);
} else {
docBase = context.getDocumentBase().getFile();
}
// take care of File.getAbsolutePath() troubles on
// jdk1.1.x/win
absPath = FileUtil.patch(absPath);
if (! docBase.endsWith("/")) {
docBase += "/";
}
if (isFileMasked(docBase, absPath)) {
response.sendError(response.SC_NOT_FOUND);
return;
}
if (file.isDirectory()) {
// check for welcome file
String welcomeFile = getWelcomeFile(file);
if (welcomeFile != null) {
if (requestURI.endsWith("/")) {
String path = requestURI;
String contextPath = context.getPath();
if (contextPath.length() == 0) {
contextPath = "/";
}
int index = requestURI.indexOf(contextPath);
if (index > -1 ) {
path = requestURI.substring(
index + contextPath.length());
}
if (! path.startsWith("/")) {
path = "/" + path;
}
ServletContext context =
getServletContext().getContext(contextPath);
RequestDispatcher rd = context.getRequestDispatcher(
path + welcomeFile);
rd.forward(request, response);
} else {
boolean inInclude = false;
Object o = request.getAttribute(
Constants.Attribute.Dispatch);
if (o != null) {
inInclude = true;
}
// do a redirect so that all relative
// urls work correctly
if (! inInclude) {
response.sendRedirect(requestURI + "/");
}
}
} else {
// XXX
// ok, see if it's okay to do this
serveDir(file, request, response);
}
} else {
// serve that file
// check that .jsp/ doesn't slip through on Windows!
if (! url.getFile().endsWith("/") &&
! url.getFile().endsWith("\\")) {
serveFile(file, request, response);
} else {
response.sendError(response.SC_NOT_FOUND,
"File Not Found<br>" + requestURI);
}
}
}
private String getWelcomeFile(File file) {
String welcomeFile = null;
Enumeration enum = context.getWelcomeFiles();
while (enum.hasMoreElements()) {
String fileName = (String)enum.nextElement();
if (fileName != null &&
fileName.trim().length() > 0) {
File f = new File(file, fileName);
if (f.exists()) {
welcomeFile = fileName;
break;
}
}
}
return welcomeFile;
}
private void serveURL(URL url, HttpServletRequest request,
HttpServletResponse response)
throws IOException {
try {
URLConnection con = url.openConnection();
con.connect();
// XXX
// lot of work needed here for when reading from a war
String contentType = con.getContentType();
int contentLength = con.getContentLength();
String lastModified = Long.toString(con.getLastModified());
response.setContentType((contentType != null) ?
contentType : "text/html");
response.setContentLength((contentLength >= 0) ?
contentLength : 0);
response.setHeader("Last-Modified",
(lastModified != null) ? lastModified : "");
InputStream in = con.getInputStream();
serveStream(in, request, response);
in.close();
} catch (IOException e) {
// To do a good error msg, first figure out what we're serving
String requestURI = (String)request.getAttribute(
Constants.Attribute.RequestURI);
if (requestURI == null) {
requestURI = request.getRequestURI();
}
response.sendError(response.SC_NOT_FOUND,
"File Not Found<br>" + requestURI);
}
}
private void serveFile(File file, HttpServletRequest request,
HttpServletResponse response)
throws IOException {
String absPath = file.getAbsolutePath();
String canPath = file.getCanonicalPath();
// take care of File.getAbsolutePath() troubles on
// jdk1.1.x/win
absPath = FileUtil.patch(absPath);
// This absPath/canPath comparison plugs security holes...
// On Windows, makes "x.jsp.", "x.Jsp", and "x.jsp%20"
// return 404 instead of the JSP source
// On all platforms, makes sure we don't let ../'s through
// Unfortunately, on Unix, it prevents symlinks from working
// So, a check for File.separatorChar='\\' ..... It hopefully
// happens on flavors of Windows.
if (File.separatorChar == '\\') {
// On Windows check ignore case....
if(!absPath.equalsIgnoreCase(canPath)) {
response.sendError(response.SC_NOT_FOUND);
return;
}
} else {
// The following code on Non Windows disallows ../
// in the path but also disallows symlinks....
//
// if(!absPath.equals(canPath)) {
// response.sendError(response.SC_NOT_FOUND);
// return;
// }
// instead lets look for ".." in the absolute path
// and disallow only that.
// Why should we loose out on symbolic links?
//
if(absPath.indexOf("..") != -1) {
// We have .. in the path...
response.sendError(response.SC_NOT_FOUND);
return;
}
}
String mimeType = mimeTypes.getContentTypeFor(file.getName());
if (mimeType == null) {
mimeType = "text/plain";
}
response.setContentType(mimeType);
response.setContentLength((int)file.length());
response.setDateHeader("Last-Modified", file.lastModified());
FileInputStream in = new FileInputStream(file);
try {
serveStream(in, request, response);
} catch (FileNotFoundException e) {
// Figure out what we're serving
String requestURI = (String)request.getAttribute(
Constants.Attribute.RequestURI);
if (requestURI == null) {
requestURI = request.getRequestURI();
}
response.sendError(response.SC_NOT_FOUND,
"File Not Found<br>" + requestURI);
} catch (SocketException e) {
return; // munch
} finally {
if (in != null) {
in.close();
}
}
}
private void serveStream(InputStream in, HttpServletRequest request,
HttpServletResponse response)
throws IOException {
// XXX
// ok, here we are trying to figure out if the response has
// already been started with a stream or a writer. We really
// need to move these flags into the Request and Response objects
// in web.core, but I don't want to suffer that big a hit right
// before code freeze.
// So, we take the preferred track (stream) first, and fall
// back to writer.
try {
ServletOutputStream out = response.getOutputStream();
serveStreamAsStream(in, out);
} catch (IllegalStateException ise) {
PrintWriter out = response.getWriter();
serveStreamAsWriter(in, out);
}
}
private void serveStreamAsStream(InputStream in, OutputStream out)
throws IOException {
byte[] buf = new byte[1024];
int read = 0;
while ((read = in.read(buf)) != -1) {
out.write(buf, 0, read);
}
}
private void serveStreamAsWriter(InputStream in, PrintWriter out)
throws IOException {
InputStreamReader r = new InputStreamReader(in);
char[] buf = new char[1024];
int read = 0;
while ((read = r.read(buf)) != -1) {
out.write(buf, 0, read);
}
}
private boolean isFileMasked(String docBase, String requestedFile) {
for (int i = 0; i < Constants.Context.MASKED_DIR.length; i++) {
String maskFile = Constants.Context.MASKED_DIR[i];
// case insensitive check
if (requestedFile.toLowerCase().startsWith(
FileUtil.patch(docBase + maskFile).toLowerCase())) {
return true;
}
}
return false;
}
private boolean isDirMasked(String basedir, String subdir) {
// In the future we could make sure to only mask the special
// directories if they're rooted in the basedir. That would
// allow a WEB-INF dir to be served if it's not *the* WEB-INF for
// example.
// But to do that would cause a security breach when one context
// contained another context, since the subcontext would have its
// hidden dirs displayed. So for now all masked dirs are masked.
//
for (int i = 0; i < Constants.Context.MASKED_DIR.length; i++) {
if (subdir.equalsIgnoreCase(Constants.Context.MASKED_DIR[i])) {
return true;
}
}
return false;
}
private void serveDir(File file, HttpServletRequest request,
HttpServletResponse response)
throws IOException {
// XXX
// genericize this! put it into another class! especially
// important as we should be able to dive into archives
// and get this same kind of information in the furture.
boolean shaderow = false;
// Make sure that we don't let ../'s through
String absPath = file.getAbsolutePath();
String canPath = file.getCanonicalPath();
// take care of File.getAbsolutePath() troubles on
// jdk1.1.x/win
absPath = FileUtil.patch(absPath);
if (File.separatorChar == '\\') {
// On Windows check ignore case....
if(!absPath.equalsIgnoreCase(canPath)) {
response.sendError(response.SC_NOT_FOUND);
return;
}
} else {
// The following code on Non Windows disallows ../
// in the path but also disallows symlinks....
//
// if(!absPath.equals(canPath)) {
// response.sendError(response.SC_NOT_FOUND);
// return;
// }
// instead lets look for ".." in the absolute path
// and disallow only that.
// Why should we loose out on symbolic links?
//
if(absPath.indexOf("..") != -1) {
// We have .. in the path...
response.sendError(response.SC_NOT_FOUND);
return;
}
}
Vector dirs = new Vector();
Vector files = new Vector();
String[] fileNames = file.list();
String docBase = "";
if (context.getDocumentBase().getProtocol().equalsIgnoreCase("war") &&
context.isWARExpanded()) {
String s = context.getWARDir().getAbsolutePath();
docBase = FileUtil.patch(s);
} else {
docBase = context.getDocumentBase().getFile();
}
if (! docBase.endsWith("/")) {
docBase += "/";
}
for (int i = 0; i < fileNames.length; i++) {
String fileName = fileNames[i];
File f = new File(file, fileName);
// Make sure dir isn't masked
if (f.isDirectory() && isDirMasked(docBase, fileName)) {
continue;
}
if (f.isDirectory()) {
dirs.addElement(f);
} else {
files.addElement(f);
}
}
// Pre-calculate the request URI for efficiency
String requestURI = request.getRequestURI();
// Make another URI that definitely ends with a /
String slashedRequestURI = null;
if (requestURI.endsWith("/")) {
slashedRequestURI = requestURI;
} else {
slashedRequestURI = requestURI + "/";
}
// see if we are in an include
boolean inInclude = false;
Object o = request.getAttribute(Constants.Attribute.Dispatch);
if (o != null) {
inInclude = true;
}
StringBuffer buf = new StringBuffer();
if (! inInclude) {
response.setContentType("text/html");
buf.append("<html>\r\n");
buf.append("<head>\r\n");
// XXX
// i18n
buf.append("<title>Directory Listing for: " + requestURI);
buf.append("</title>\r\n</head><body bgcolor=white>\r\n");
}
buf.append("<table width=90% cellspacing=0 ");
buf.append("cellpadding=5 align=center>");
buf.append("<tr><td colspan=3><font size=+2><strong>");
buf.append("Directory Listing for: " + requestURI);
buf.append("</strong></td></tr>\r\n");
if (! requestURI.equals("/")) {
buf.append("<tr><td colspan=3 bgcolor=#ffffff>");
//buf.append("<a href=\"../\">Up one directory");
String toPath = requestURI;
if (toPath.endsWith("/")) {
toPath = toPath.substring(0, toPath.length() - 1);
}
toPath = toPath.substring(0, toPath.lastIndexOf("/"));
if (toPath.length() == 0) {
toPath = "/";
}
buf.append("<a href=\"" + toPath + "\"><tt>Up to: " + toPath);
buf.append("</tt></a></td></tr>\r\n");
}
if (dirs.size() > 0) {
buf.append("<tr><td colspan=3 bgcolor=#cccccc>");
buf.append("<font size=+2><strong>Subdirectories:</strong>\r\n");
buf.append("</font></td></tr>\r\n");
Enumeration e = dirs.elements();
while (e.hasMoreElements()) {
File f = (File)e.nextElement();
String fileName = f.getName();
buf.append("<tr");
if (shaderow) {
buf.append(" bgcolor=#eeeeee");
shaderow = false;
} else {
shaderow = true;
}
buf.append("><td> ");
buf.append("<tt><a href=\"" + slashedRequestURI +
fileName + "\">" + fileName +
"/</a> " +
"</tt>\r\n");
buf.append("</td><td><tt> </tt></td>");
buf.append("<td align=right><tt>");
buf.append(dateFormat.format(new Date(f.lastModified())));
buf.append("</tt></td></tr>\r\n");
}
buf.append("\r\n");
}
shaderow = false;
buf.append("<tr><td colspan=3 bgcolor=#ffffff> </td></tr>");
if (files.size() > 0) {
buf.append("<tr><td colspan=4 bgcolor=#cccccc>");
buf.append("<font size=+2><strong>Files:</strong>");
buf.append("</font></td></tr>");
Enumeration e = files.elements();
while (e.hasMoreElements()) {
buf.append("<tr");
if (shaderow) {
buf.append(" bgcolor=#eeeeee");
shaderow = false;
} else {
shaderow = true;
}
buf.append("><td> \r\n");
File f = (File)e.nextElement();
String fileName = f.getName();
buf.append("<tt><a href=\"" + slashedRequestURI +
fileName + "\">" + fileName + "</a>");
buf.append(" <tt>");
buf.append("</td></td>\r\n<td align=right><tt>");
int filesize = (int)f.length();
int leftside = filesize / 1024;
int rightside = (filesize % 1024) / 103; // makes 1 digit
// To avoid 0.0 for non-zero file, we bump to 0.1
if (leftside == 0 && rightside == 0 && filesize != 0) {
rightside = 1;
}
buf.append(leftside + "." + rightside + " KB");
buf.append("</tt></td>");
buf.append("<td align=right><tt>");
buf.append(dateFormat.format(new Date(f.lastModified())));
buf.append("</tt></td></tr>\r\n");
}
buf.append("\r\n");
}
buf.append("<tr><td colspan=3 bgcolor=#ffffff> </td></tr>");
buf.append("<tr><td colspan=3 bgcolor=#cccccc>");
buf.append("<font size=-1>");
buf.append(Constants.TOMCAT_NAME);
buf.append(" v");
buf.append(Constants.TOMCAT_VERSION);
buf.append("</font></td></tr></table>");
if (! inInclude) {
buf.append("</body></html>\r\n");
}
String output = buf.toString();
byte[] bytes = output.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
serveStream(in, request, response);
}
}