You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Loïc Lefèvre <ll...@fivia.com> on 2001/08/01 12:13:26 UTC

MOD_REWRITE + TOMCAT 3.2.3: MAYBE A SOLUTION

Hello everybody,

If you read all the mails, you must know all the problems
I've encouter with the mod_rewrite module.

Remember... the following rules didn't work:

------

#Don't know if it is useful ?!?
#RewriteRule  ^(/.*;jsessionid=.*)$  $1 [T=jserv-servlet]

RewriteCond %{REQUEST_URI} ^/servlet* [NC]
RewriteRule ^/servlet/(.*) /lol/$1 [PT]

RewriteCond %{REQUEST_URI} !^/lol* [NC]
RewriteCond %{REQUEST_URI} !^/Image* [NC]
RewriteCond %{REQUEST_URI} !^/Elemtech* [NC]
RewriteCond %{REQUEST_URI} !^/Erreur* [NC]
RewriteCond %{REQUEST_URI} ^/.*/.*
RewriteRule ^/(.*) /lol/AdFront?access=/$1 [PT,QSA]

------

After many investigations, I decided to make my own Mapper
starting with SimpleMapper1 (look in server.xml).

So here is the code I added (line starting with a '#' are original!):

--------------------------
START --------------------------------------------------
package com.fivia.adfront;
#
#import org.apache.tomcat.core.*;
#import org.apache.tomcat.core.Constants;
#import org.apache.tomcat.util.*;
#import java.util.*;
import java.io.*;
import org.apache.oro.text.GlobCompiler;
import org.apache.oro.text.awk.AwkCompiler;
import org.apache.oro.text.awk.AwkMatcher;
import org.apache.oro.text.regex.*;
import javax.servlet.http.*;
#
#/**
# *  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.
# *
# *  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:
# *  - extract the information that is relevant to matching from the Request
# *   object. The current implementation deals with the Host header and the
# *   request URI.
# *  - 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.
# *
# *  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.
# *
# */
public class AdFrontMapper extends  BaseInterceptor
#{

...

#		if(debug>0)
#			log( "Remove mapping " + mapping );
#    }
#
#
#    /* -------------------- Request mapping -------------------- */

	private boolean checkConditions(String path, String[] sa, boolean
caseSensitiv )
	{
		org.apache.oro.text.regex.Pattern pattern;
    	PatternCompiler compiler = new Perl5Compiler();
	    PatternMatcher matcher = new Perl5Matcher();
	    boolean notPresent, result;
		int i;
		for(i=0;i<sa.length;i++)
		{
			log("Condition "+(i+1)+": "+sa[i]);

			notPresent = (sa[i].charAt(0)=='!');

			if( notPresent )
				sa[i] = sa[i].substring(1);

			try
    	    {
        	    pattern =
compiler.compile(sa[i],(caseSensitiv?Perl5Compiler.DEFAULT_MASK:Perl5Compile
r.CASE_INSENSITIVE_MASK)); // Condition
        	}
        	catch(MalformedPatternException malformedpatternexception)
        	{
            	log("\nMalformed Regular Expression:\n" +
malformedpatternexception.getMessage());
            	return false;
        	}

			result = matcher.contains(new PatternMatcherInput(path), pattern);

			if( notPresent )
				result = !result;

			if( !result )
			{
				log("Condition: "+(notPresent?"!":"")+sa[i]+" => not-matched");
				return false;
			}
			else
				log("Condition: "+(notPresent?"!":"")+sa[i]+" => matched");
		}

		return true;
	}

	private String applyRule(Request req, String path, String rule, String
substitution, String[] conditions, boolean conditionsCaseSensitivity )
	{
		String orgPath = path;
		boolean matched = true;

		org.apache.oro.text.regex.Pattern pattern;
		PatternCompiler compiler = new Perl5Compiler();
		PatternMatcher matcher = new Perl5Matcher();

		log("Applying rule: "+rule+" on "+path);

		try
        {
            pattern = compiler.compile(rule); // Rule
        }
        catch(MalformedPatternException malformedpatternexception)
        {
            log("\nMalformed Regular Expression:\n" +
malformedpatternexception.getMessage());
            return null;
        }

        MatchResult matchresult;
        int i=0, j, j1;
		PatternMatcherInput patternmatcherinput;

        for(patternmatcherinput = new PatternMatcherInput(path);
matcher.contains(patternmatcherinput, pattern);)
        {
            matchresult = matcher.getMatch();
            i++;
            log("Match " + i + ": " + matchresult.group(0) );
            j1 = matchresult.groups();
            if(j1 > 1)
            {
                if( checkConditions(path,conditions,
conditionsCaseSensitivity) )
                {
                	log("    Subgroups:");
                	for(j = j1-1; j > 0; j--)
                    {
                    	if( substitution.indexOf("$"+j) != -1 )
							substitution =
replaceString(substitution,"$"+j,matchresult.group(j));
                    }

                   	path = substitution;
                }
                else
                {
					matched = false;
                	break;
                }
            }
            else
            {
            	matched = false;
            	break;
            }
        }

		if( i==0 )
			matched = false;

		if( matched )
		{
			int pos;
			String queryParameters = null;
			if( (pos = path.indexOf("?")) != -1 )
			{
				queryParameters = path.substring(pos+1);
				path = path.substring(0,pos);
				req.setQueryString(queryParameters);
			}

			req.setRequestURI(path);

       		log("rewrite "+orgPath+" -> "+(queryParameters==null?path:"split
uri="+substitution+" -> uri="+path+",
                      args="+queryParameters+"\nlocal path result: "+path));
		}
		else
			log("pass through "+orgPath);

        return path;
	}

	private String replaceString(String string, String oldString, String
newString)
	{
		if((string==null)    || (string.length()==0)    ||
		   (oldString==null) || (oldString.length()==0) ||
		   (newString==null))
			return string;

		StringBuffer sb = new StringBuffer(string);
		int count=0;
		int index=-1;
		int nlen = newString.length();
		int olen = oldString.length();

		while(true)
		{
			index = string.indexOf(oldString,count);
			if(index<0)
				break;

			sb.replace(index,index+olen,newString);
			string = sb.toString();
			count  = index + nlen;
		}

		return sb.toString();
	}

private void info(Request request)
{

	log("##################################################################");
        log("Server Name: " + request.getServerName());
        log("Server Port: " + request.getServerPort());
        log("Remote Addr: " + request.getRemoteAddr());
        log("Remote Host: " + request.getRemoteHost());
        log("Character Encoding: " + request.getCharacterEncoding());
        log("Content Type: "+ request.getContentType());
        log("");
        log("Request Is Secure: " + request.isSecure());
        log("Auth Type: " + request.getAuthType());
        log("HTTP Method: " + request.getMethod());
        log("Request URI: " + request.getRequestURI());
        log("Servlet Path: " + request.getServletPath());
        log("Path Info: " + request.getPathInfo());
		log("Path Trans: " + request.getPathTranslated());
        log("Query String: " + request.getQueryString());
        log("");
        log("Headers in this request:");
        Enumeration e = request.getHeaderNames();
        while (e.hasMoreElements()) {
            String key = (String)e.nextElement();
            String value = request.getHeader(key);
            log("   " + key + ": " + value);
        }
        log("");
        log("Parameter names in this request:");
        e = request.getParameterNames();
        while (e.hasMoreElements()) {
            String key = (String)e.nextElement();
            String[] values = request.getParameterValues(key);
            String s = "   " + key + " = ";
            for(int i = 0; i < values.length; i++) {
                s += values[i] + " ";
            }
            log(s+"\n");
        }
}

#    /** First step of request porcessing is finding the Context.
#     */
#    public int contextMap( Request req )
#    {
		//info(req);

		log("contextMap( "+req.toString()+" )");

#		String path = req.getRequestURI();
#
#		if( path==null)
#	    	throw new RuntimeException("ASSERT: null path in request URI");

		path = applyRule(req, path,"^/servlet/(.*)","/lol/$1",new
tring[]{ "^/servlet*" },false);

		path = applyRule(req, path,"^/(.*)","/lol/AdFront?access=/$1",new
String[]{ "!^/lol*", "!^/Image*", "!^/Elemtech*", "!^/Erreur*",
"^/.*/.*" },false);

		if( path == null )
			return 404;

#		if( path.indexOf("?") >=0 )
#	    	throw new RuntimeException("ASSERT: ? in requestURI");
#
#		try
#		{
#	    	String host=req.getServerName();
#	    	if(debug>0)
#	    		cm.log("Host = " + host);
#
#	    	Container container =(Container)map.getLongestPrefixMatch( host,
path );
#
#	    	if( container == null )
#				return 404;
#
#	    	if(debug>0)
#				cm.log("SM: Prefix match " + path + " -> " + container.getPath() + " "
+ container.getHandler() + " " + container.getRoles());

...

----------------------------------------------------------------------------
---------------
-----------------------------------
END ---------------------------------------------------
----------------------------------------------------------------------------
---------------

I use the jakarta package ORO 2.0.4:

http://jakarta.apache.org/builds/jakarta-oro/release/v2.0.4/jakarta-oro-2.0.
4.tar.gz

I then compile to create the mapper.jar package, put it in %TOMCAT_HOME%/lib
and replace in server.xml:

	<RequestInterceptor
            className="org.apache.tomcat.request.SimpleMapper1"
            debug="1" />

BY

	<RequestInterceptor
            className="com.fivia.adfront.AdFrontMapper"
            debug="1" />


Please send me any comment.


Loïc Lefèvre