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/05/02 01:15:16 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/request AccessInterceptor.java SessionInterceptor.java SimpleMapper1.java
costin 00/05/01 16:15:16
Modified: src/share/org/apache/tomcat/request SessionInterceptor.java
SimpleMapper1.java
Added: src/share/org/apache/tomcat/request AccessInterceptor.java
Log:
- moved all session-related code from Mapper to SessionInterceptor (
no longer need to remove the session ID from the request in mapper).
Need to change server.xml ( SessionInterceptor have to be called before mapper,
and any other interceptor that will change the URL before context map ).
- SimpleMapper1 - a lot of cleanup, documentation. Authorization is no longer
part of this - it will have it's own interceptor. It involves the
same steps ( pattern matching) and it's more efficient to do that in one
step instead of duplicating the code, but I think it's safer to
separate them. Probably after security code is stable we can do
all pattern matching in one step.
Revision Changes Path
1.16 +50 -10 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.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- SessionInterceptor.java 2000/03/21 01:27:08 1.15
+++ SessionInterceptor.java 2000/05/01 23:15:16 1.16
@@ -95,11 +95,51 @@
this.cm=cm;
}
+ /** Extract the session id from the request.
+ * SessionInterceptor will have to be called _before_ mapper,
+ * to avoid coding session stuff inside the mapper.
+ *
+ * When we fix the interceptors we'll have to specify something
+ * similar with the priority in apache hooks, right now it's just
+ * a config issue.
+ */
+ public int contextMap(Request request ) {
+ if( request.getRequestedSessionId() != null ) {
+ // probably Apache already did that for us
+ return 0;
+ }
+
+ // fix URL rewriting
+ String sig=";jsessionid=";
+ int foundAt=-1;
+ String uri=request.getRequestURI();
+ String sessionId;
+
+ if ((foundAt=uri.indexOf(sig))!=-1){
+ sessionId=uri.substring(foundAt+sig.length()); // I hope the optimizer does it's job:-)
+
+ // rewrite URL, do I need to do anything more?
+ request.setRequestURI(uri.substring(0, foundAt));
+
+ // No validate now - we just note that this is what the user
+ // requested.
+ request.setRequestedSessionIdFromURL(true);
+ request.setRequestedSessionId( sessionId );
+ }
+ return 0;
+ }
+
+ /** This happens after context map, so we know the context.
+ * We can probably do it later too.
+ */
public int requestMap(Request request ) {
String sessionId = null;
Cookie cookies[]=request.getCookies(); // assert !=null
+ boolean fromCookie=false;
+ // Give priority to cookies. I don't know if that's part
+ // of the spec - XXX
for( int i=0; i<cookies.length; i++ ) {
Cookie cookie = cookies[i];
@@ -108,20 +148,21 @@
sessionId=validateSessionId(request, sessionId);
if (sessionId!=null){
request.setRequestedSessionIdFromCookie(true);
+ fromCookie=true;
}
}
}
-
- String sig=";jsessionid=";
- int foundAt=-1;
- if( debug>0 ) cm.log(" XXX RURI=" + request.getRequestURI());
- if ((foundAt=request.getRequestURI().indexOf(sig))!=-1){
- sessionId=request.getRequestURI().substring(foundAt+sig.length());
- // rewrite URL, do I need to do anything more?
- request.setRequestURI(request.getRequestURI().substring(0, foundAt));
+
+ if( ! fromCookie ) {
+ // we don't have the session id from cookie, maybe URL rewriting
+ // was used ?
+ sessionId=request.getRequestedSessionId();
sessionId=validateSessionId(request, sessionId);
if (sessionId!=null){
- request.setRequestedSessionIdFromURL(true);
+ // it's already done in contextMap
+ // request.setRequestedSessionIdFromURL(true);
+ // set it with load balancing removed
+ request.setRequestedSessionId( sessionId );
}
}
return 0;
@@ -163,7 +204,6 @@
return null;
}
-
public int beforeBody( Request rrequest, Response response ) {
String reqSessionId = response.getSessionId();
1.4 +87 -312 jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java
Index: SimpleMapper1.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SimpleMapper1.java 2000/04/26 18:57:36 1.3
+++ SimpleMapper1.java 2000/05/01 23:15:16 1.4
@@ -66,72 +66,42 @@
import javax.servlet.http.*;
import java.util.*;
-/** Parse request URI and find ContextPath, ServletPath, PathInfo and QueryString
- * This interceptor is an adapter between tomcat and a parsing/matching engine
- * ( the mapper ). Use normal OO programming to reuse and extend - you can
- * either start a completely new mapping interceptor or use parts of this
- * one, and you can use the simple mapper or a better one.
+/**
+ * This class will set up the data structures used by a simple patern matching
+ * alghoritm and use it to extract the path components from the request URI.
*
- * This class contains mostly support functions and implements a "bridge"
- * pattern. A different bridge can be used - but try to keep the same
- * semantics ( i.e. allow run-time changes )
- *
+ * The interceptor will be called in standalone case, for "integrated" mode
+ * we should have all the data from the web server - that means the performance
+ * of this code is not relevant for production mode if a web server is used.
+ *
* This particular implementation does the following:
- * - avoid mapping if someone already did that ( web server )
* - extract the information that is relevant to matching from the Request object.
* The current implementation deals with the Host header and the request URI.
- * If you want more complex rules - you'll need to either extend this interceptor
- * and use more of info from request ( IP, etc) OR create a more specialized mapper.
- * - Represent the information in the format understood by mapper and call the
- * right mapping methods in order to respect the servlet specs.
- *
- * The mapper we use is a generic matching alghoritm - we feed it with CharChunks (
- * in order to avoid String garbage ). This is a generic problem - probably
- * xalan have similar needs, so optimizations will be generally usefull.
- *
- * This also prepare us to deal with Adapters that are more recylcing-friendly, and
- * work with char[] instead of Strings.
+ * - Use an external mapper to find the best match.
+ * - Adjust the request paths
+ *
+ * The execution time is proportional with the number of hosts, number of context, number of
+ * mappings and with the length of the request.
*
- * A very interesting experiment would be to use a RE package instead of our simple
- * mapper - of course req-exp mapping is not supported by servlets, but using a real
- * RE engine even for the simple mapping rules defined in the API may provide benefits.
- * Again - it's the interceptor responsability to feed the right information and regexps
- * to RE engine, in order to implement the spec as is, without extensions.
+ * Security mappings are more complex ( method, transport are also part of the
+ * matching ). We can share the same mapping alghoritm or even the mapper - but
+ * until security code will be stable it's better to keep it separated.
*
- * Another interesting experiment is re-using the matching code in XPath/XSL - again
- * it's a much wider set of rules, but that also mean they are forced to be very
- * aggressive in optimizations and we can reuse more code.
*/
public class SimpleMapper1 extends BaseInterceptor {
int debug=0;
ContextManager cm;
- Mappings map;
- Hashtable vhostMaps=new Hashtable();
+
+ PrefixMapper map;
+
+ // We store the extension maps as per/context notes.
int ctExtMapNote=-1;
+
+ // Property for the PrefixMapper - cache the mapping results
boolean mapCacheEnabled=false;
- // Cache the most recent mappings
- // Disabled by default ( since we haven't implemented
- // capacity and remove ).
- SimpleHashtable mapCache=new SimpleHashtable();
- // By using TreeMap instead of SimpleMap you go from 143 to 161 RPS
- // ( at least on my machine )
- // Interesting - even if SimpleHashtable is faster than Hashtable
- // most of the time, the average is very close for both - it seems
- // that while the synchronization in Hashtable is locking, GC have
- // a chance to work, while in SimpleHashtable case GC creates big
- // peeks. That will go away with more reuse, so we should use SH.
-
- // An alternative to explore after everything works is to use specialized
- // mappers ( extending this one for example ) using 1.2 collections
- // TreeMap mapCache;
- int capacity;
- int currentL;
-
public SimpleMapper1() {
- map=new Mappings();
- mapCache=new SimpleHashtable();
- // mapCache=new TreeMap();
+ map=new PrefixMapper();
}
/* -------------------- Support functions -------------------- */
@@ -147,77 +117,36 @@
cm.log( msg );
}
+ /** Allow the mapper to cache mapping results - resulting in a
+ * faster match for frequent requests. ( treat this as experimental)
+ */
public void setMapCache( boolean v ) {
mapCacheEnabled = v;
+ map.setMapCache( v );
}
/* -------------------- Initialization -------------------- */
- /** In normal operation - it will do nothing but set cm.
- If you add the interceptor at run-time ( is it usefull ??)
- this will also set it up with the current config from other components.
- ( the feature was never tested ).
- */
+ /** Set the context manager. To keep it simple we don't support
+ * dynamic add/remove for this interceptor.
+ */
public void setContextManager( ContextManager cm ) {
this.cm=cm;
- // set-up a per/container note - will be used to keep private
- // data for this object.
+
+ // set-up a per/container note for maps
try {
- ctExtMapNote = cm.getNoteId( ContextManager.CONTAINER_NOTE, "Extension maps");
+ ctExtMapNote = cm.getNoteId( ContextManager.CONTAINER_NOTE, "map.extension");
} catch( TomcatException ex ) {
ex.printStackTrace();
throw new RuntimeException( "Invalid state ");
}
- // now "simulate" all the callbacks that we missed by
- // beeing late
-
- // Add all context that are set in CM
- Enumeration enum=cm.getContexts();
- while( enum.hasMoreElements() ) {
-
- try {
- Context ctx=(Context)enum.nextElement();
- addContext( cm, ctx );
- } catch (TomcatException ex ) {
- ex.printStackTrace();
- }
- }
}
- /** Called when a context is added - it may have all the mappings already
- in, so we need to add them too. Most of the time ( i.e. in normal
- operation ) this is a no-op, but we want to support run-time
- changes in interceptors and contexts.
+ /** Called when a context is added.
*/
public void addContext( ContextManager cm, Context ctx ) throws TomcatException
{
- // find all the mappings that are declared in context,
- // and register them.
-
- // this is called when the interceptor is added and
- // we have pre-set mappings - not very common
- // or tested. Normal operation is to set up tomcat
- // and the interceptors and then add the contexts.
- String vhost=ctx.getHost();
- if( vhost == null ) {
- map.prefixMappedServlets.put( ctx.getPath(), ctx.getContainer());
- } else {
- Mappings vmap=(Mappings)vhostMaps.get( vhost );
- if( vmap == null ) {
- vmap=new Mappings();
- vhostMaps.put( vhost, vmap );
- }
- vmap.prefixMappedServlets.put( ctx.getPath(), ctx.getContainer());
- }
-
- if(debug>0) log( "SM: default map " + vhost +":" + ctx.getPath() + " -> " + ctx.getContainer() );
-
- Enumeration ctE=ctx.getContainers();
- while( ctE.hasMoreElements() ) {
- // the internal method to add this (existing)
- // mapping.
- addContainer( (Container)ctE.nextElement() );
- }
+ map.addMapping( ctx.getHost(), ctx.getPath(), ctx.getContainer());
}
/** Called when a context is removed from a CM - we must ask the mapper to
@@ -226,14 +155,10 @@
public void removeContext( ContextManager cm, Context ctx ) throws TomcatException
{
if(debug>0) log( "Removed from maps ");
-
- // Remove all mappings associated with this context ( including the default
- // servlet associated with the context container
-
- // XXX specific to internal representation !!!
- String ctxP=ctx.getPath();
+ map.removeAllMappings( ctx.getHost(), ctx.getPath());
+ // extension mappings are local to ctx, no need to do something about that
}
-
+
/**
* Associate URL pattern to a set of propreties.
@@ -254,20 +179,16 @@
String path=ct.getPath();
String ctxP=ctx.getPath();
- Mappings myMap;
- if( vhost==null )
- myMap=map; // global contexs
- else
- myMap=(Mappings)vhostMaps.get( vhost );
- // assert myMap!= null ( we just added the context, so the map is there
-
- String vhostS=( vhost==null )? "": vhost;
+ if(ct.getHandler() == null ) {
+ // it was only a security map, no handler defined
+ return;
+ }
switch( ct.getMapType() ) {
case Container.PREFIX_MAP:
- // cut /* !
- myMap.prefixMappedServlets.put( ctxP + path.substring( 0, path.length()-2 ), ct);
- if( debug>0 ) log("SM: prefix map " + vhostS + ":" + ctxP + path + " -> " + ct + " " );
+ // cut /* ( no need to do a string concat for every match )
+ map.addMapping( vhost, ctxP + path.substring( 0, path.length()-2 ), ct);
+ if( debug>0 ) log("SM: prefix map " + vhost + ":" + ctxP + path + " -> " + ct + " " );
break;
case Container.EXTENSION_MAP:
// Add it per/defaultContainer - as spec require ( it may also be
@@ -286,12 +207,14 @@
if(debug>0) log( "SM: extension map " + ctxP + "/" + path + " " + ct + " " );
break;
case Container.PATH_MAP:
- myMap.prefixMappedServlets.put( ctxP + path, ct);
- if( debug>0 ) log("SM: exact map " + vhostS + ":" + ctxP + path + " -> " + ct + " " );
+ map.addExactMapping( vhost, ctxP + path, ct);
+ if( debug>0 ) log("SM: exact map " + vhost + ":" + ctxP + path + " -> " + ct + " " );
break;
}
}
+ // XXX not implemented - will deal with that after everything else works.
+ // Remove context will still work
public void removeContainer( Container ct )
throws TomcatException
{
@@ -307,79 +230,47 @@
/** First step of request porcessing is finding the Context.
- * Advanced mappers will do only one parsing.
*/
public int contextMap( Request req ) {
String path = req.getRequestURI();
if( path==null) throw new RuntimeException("ASSERT: null path in request URI");
if( path.indexOf("?") >=0 ) throw new RuntimeException("ASSERT: ? in requestURI");
- // strip session URL rewrite part which interferes processing
- // XXX works only if ;jsessionid= is path param for the last component
- // of the path!
- String sig=";jsessionid=";
- int foundAt=-1;
- if ((foundAt=path.indexOf(sig))!=-1){
- path=path.substring(0, foundAt);
- }
-
- String host=req.getServerName();
- cm.log("Host = " + host);
-
- // try to find a vhost with this name
- Mappings myMap=(Mappings)vhostMaps.get( host );
- if( myMap==null ) myMap = map; // default server
-
try {
+ String host=req.getServerName();
+ if(debug>0) cm.log("Host = " + host);
- Context ctx = null;
- Mappings mapC=null;
- Container container = null;
- boolean cached=false;
-
- if( mapCacheEnabled ) {
- container=(Container)getCachedResult( host + ":" + path );//XXX remove strings!
- if( container != null ) {
- cached=true;
- if(debug>0) log( "CM: cache hit " + path);
- }
- }
-
- if( ! cached )
- container=(Container)myMap.getLongestPrefixMatch( path );
-
- if( container == null ) throw new RuntimeException( "Assertion failed - container==null");
- if( container.getHandler() == null ) throw new RuntimeException( "Assertion failed - container.handler==null");
-
- if(debug>0) cm.log("SM: Prefix match " + path + " -> " + container.getPath() + " " +
- container.getHandler() + " " + container.getRoles());
-
- // Once - adjust for prefix and context path
- // If cached - we don't need to do it again ( since it is the final Container,
- // either prefix or extension )
- fixRequestPaths( path, req, container );
-
+ Context ctx = null;
+ Container container =(Container)map.getLongestPrefixMatch( host, path );
+
+ if( container == null ) throw new RuntimeException( "Assertion failed - container==null");
+ if( container.getHandler() == null ) throw new RuntimeException( "Assertion failed - container.handler==null");
+
+ if(debug>0) cm.log("SM: Prefix match " + path + " -> " + container.getPath() + " " +
+ container.getHandler() + " " + container.getRoles());
- // if it's default container - try extension match
- if ( ! cached && container.getMapType() == Container.DEFAULT_MAP ) {
- Container extC = matchExtension( req );
-
- if( extC != null ) {
- // change the handler
- if( extC.getHandler() != null ) {
- fixRequestPaths( path, req, extC );
- container=extC;
+ // Once - adjust for prefix and context path
+ // If cached - we don't need to do it again ( since it is the final Container,
+ // either prefix or extension )
+ fixRequestPaths( path, req, container );
+
+
+ // if it's default container - try extension match
+ if ( container.getMapType() == Container.DEFAULT_MAP ) {
+ Container extC = matchExtension( req );
+
+ if( extC != null ) {
+ // change the handler
+ if( extC.getHandler() != null ) {
+ fixRequestPaths( path, req, extC );
+ container=extC;
+ }
+ if( debug > 0 ) log("SM: Found extension mapping " + extC.getHandler());
+ // change security roles
}
- if( debug > 0 ) log("SM: Found extension mapping " + extC.getHandler());
- // change security roles
}
- }
-
- if( mapCacheEnabled && ! cached ) {
- addCachedResult( host + ":" + path, container );//XXX remove strings!
- }
- if(debug>0) log("SM: After mapping " + req + " " + req.getWrapper());
+ if(debug>0) log("SM: After mapping " + req + " " + req.getWrapper());
} catch(Exception ex ) {
ex.printStackTrace();
@@ -388,7 +279,8 @@
return OK;
}
- /**
+ /** No need to do that - we finished everything in the first step.
+ *
*/
public int requestMap(Request req) {
// No op. All mapping is done in the first step - it's better because the
@@ -402,43 +294,26 @@
return OK;
}
-
- void mergeSecurityInfo( ) {
- // Merge the security info into the container
- //
- // XXX merging is a very usefull optimization, but we should do it
- // at init time, it's very expensive because we need to be sure it has the same
- // pattern !!
- // if(debug>0) log("SM: Merging security constraint " + scontainer + " into " + container );
- // container.setRoles( scontainer.getRoles());
- // container.setTransport( scontainer.getTransport());
-
- // until merging is implemented, we'll just create a new container with the combined
- // properties. This code needs optimizations ( i.e. alghoritm + data, not OptimizeIt!)
-// Container ct=container.getClone();
-// ct.setRoles( scontainer.getRoles());
-// ct.setTransport( scontainer.getTransport());
-// req.setContainer( ct );
-// if(debug>0) log("SM: Set security constraings " + req + " " + container );
- }
+ // -------------------- Implementation methods --------------------
/** Will match an extension - note that Servlet API use special rules
* for mapping extension, different from what is used in existing web servers.
* That makes this code very easy ( only need to deal with the last component
* of the name ), but it's hard to integrate and you have no way to use pathInfo.
*/
- public Container matchExtension( Request req ) {
+ Container matchExtension( Request req ) {
Context ctx=req.getContext();
String ctxP=ctx.getPath();
+
String path = req.getPathInfo(); // we haven't matched any prefix,
- // we check path Info
if( path == null ) return null;
- String extension=StringUtil.getExtension( path );
- if(debug>0) cm.log("SM: Extension match " + ctxP + " " + path + " " + extension );
+ String extension=URLUtil.getExtension( path );
if( extension == null ) return null;
+ if(debug>0) cm.log("SM: Extension match " + ctxP + " " + path + " " + extension );
+
// Find extension maps for the context
SimpleHashtable extM=(SimpleHashtable)ctx.getContainer().getNote( ctExtMapNote );
if( extM==null ) return null;
@@ -457,6 +332,8 @@
return container;
}
+ /** Adjust the paths in request after matching a container
+ */
void fixRequestPaths( String path, Request req, Container container ) {
// Set servlet path and path info
// Found a match !
@@ -496,107 +373,5 @@
req.setContainer( container );
}
- /** Cache for request results - exploit the fact that few
- * request are more "popular" than other.
- * Disable it if you want to benchmark the mapper !!!
- */
- Object getCachedResult(String path) {
- // XXX make sure we don't keep too many requests in memory
- return mapCache.get( path );
- }
-
- void addCachedResult(String path, Object o) {
- // XXX make sure we don't keep too many requests in memory
- mapCache.put( path, o );
- }
-
}
-/** Mapping alghoritm.
- XXX finish factoring out the creation of the map ( right now direct field access is
- used, since the code was just cut out from SimpleMapper).
- XXX make sure the code is useable as a general path mapper - or at least a bridge
- can be created between SimpleMapper and a patern matcher like the one in XPath
- */
-class Mappings {
- SimpleHashtable prefixMappedServlets;
-
- Mappings() {
- prefixMappedServlets=new SimpleHashtable();
- }
-
- // -------------------- Implementation --------------------
-
- /** Match a prefix rule - /foo/bar/index.html/abc
- */
- public Object getLongestPrefixMatch( String path ) {
- Container container = null;
- String s = path;
- boolean exact=true;
-
- // ??/baz/== /baz ==/baz/*
- //if( s.endsWith( "/" ))
- // s=removeLast(s);
-
- while (s.length() >= 0) {
- //if(debug>8) context.log( "Prefix: " + s );
- container = (Container)prefixMappedServlets.get(s);
-
- if (container == null) {
- s=StringUtil.removeLast( s );
- exact=false;
- } else {
- if( container.getMapType() == Container.PATH_MAP &&
- ! exact ) {
- // we matched a path_map, but we have path_info,
- // so this is not a good map
- } else {
- break;
- }
-
- }
- }
- return container;
- }
-
-}
-
-/* -------------------- Caching results -------------------- */
-class StringUtil {
-
- public static String removeLast( String s) {
- int i = s.lastIndexOf("/");
-
- if (i > 0) {
- s = s.substring(0, i);
- } else if (i == 0 && ! s.equals("/")) {
- s = "/";
- } else {
- s = "";
- }
- return s;
- }
-
- public static String getFirst( String path ) {
- if (path.startsWith("/"))
- path = path.substring(1);
-
- int i = path.indexOf("/");
- if (i > -1) {
- path = path.substring(0, i);
- }
-
- return "/" + path;
- }
-
- public static String getExtension( String path ) {
- int i = path.lastIndexOf(".");
- int j = path.lastIndexOf("/");
-
- if ((i > 0) && (i > j))
- return path.substring(i);
- else
- return null;
- }
-
-}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/request/AccessInterceptor.java
Index: AccessInterceptor.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.request;
import org.apache.tomcat.core.*;
import org.apache.tomcat.core.Constants;
import org.apache.tomcat.util.*;
import javax.servlet.http.*;
import java.util.*;
// XXX maybe it's a good idea to use a different model for adding secuirty
// constraints - we use Container now because we want to generalize all
// per/URL properties.
/**
* Access control - find if a request matches any web-resource-collection
* and set the "required" attributes.
*
* The spec requires additive checking ( i.e. there is no "best match"
* defined, but "all requests that contain a request path that mathces the
* URL pattern in the resource collection are subject to the constraing" ).
*
* In "integrated" mode this interceptor will be no-op, we'll use the
* web server ( assuming we can map the security to web-server equivalent
* concepts - I think we can do that, but need to experiment with that)
*/
public class AccessInterceptor extends BaseInterceptor {
int debug=0;
ContextManager cm;
// Security mapping note
int secMapNote;
public AccessInterceptor() {
}
/* -------------------- Support functions -------------------- */
public void setDebug( int level ) {
if(level!=0) log("SM: AccessInterceptor - set debug " + level);
debug=level;
}
void log( String msg ) {
if( cm==null)
System.out.println("AccessInterceptor: " + msg );
else
cm.log( msg );
}
/* -------------------- Initialization -------------------- */
/** Set the context manager. To keep it simple we don't support
* dynamic add/remove for this interceptor.
*/
public void setContextManager( ContextManager cm ) {
this.cm=cm;
// set-up a per/container note for maps
try {
secMapNote = cm.getNoteId( ContextManager.CONTAINER_NOTE, "map.security");
} catch( TomcatException ex ) {
ex.printStackTrace();
throw new RuntimeException( "Invalid state ");
}
}
/** Called when a context is added.
*/
public void addContext( ContextManager cm, Context ctx ) throws TomcatException
{
Hashtable sec=new Hashtable();
Container ct=ctx.getContainer();
ct.setNote( secMapNote, sec );
}
/** Called when a context is removed from a CM - we must ask the mapper to
remove all the maps related with this context
*/
public void removeContext( ContextManager cm, Context ctx ) throws TomcatException
{
// nothing - will go away with the ctx
}
/**
*/
public void addContainer( Container ct )
throws TomcatException
{
Context ctx=ct.getContext();
String path=ct.getPath();
String ctxP=ctx.getPath();
if( ct.getRoles() != null ) {
return; // XXX - right now we add either security or handler,
// later we can use a more general/efficient aproach
}
if(ct.getHandler() == null ) {
// it was only a security map
return;
}
}
// XXX not implemented - will deal with that after everything else works.
public void removeContainer( Container ct )
throws TomcatException
{
}
/* -------------------- Request mapping -------------------- */
/** Check if this request requires auth, and if so check the roles.
* This interceptor needs to be "up-chain" from security check interceptor.
* It is also possible to move this check at requestMap stage.
*/
public int authorize( Request req, Response response )
{
Context ctx=req.getContext();
// first we check if this request _requires_ access control
// this could be optimized and part of the contextMap, to
// avoid double parsing and lookup - but in production mode
// both methods will be no-ops anyway ( the server has already done
// it ) - and in standalone mode it's not the biggest problem and
// we can optimize it later if needed.
String roles[]=req.getContainer().getRoles();
if( roles==null ) {
return 0;
}
return 0;
}
// -------------------- Implementation methods --------------------
}
class ResourceCollectionPattern {
String methods[];
String prefixPatterns[];
String extPatterns[];
String exactPatterns[];
}