You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ds...@apache.org on 2002/11/25 11:15:43 UTC
cvs commit: jakarta-tomcat-4.0/tester/web/golden SSIConditional09.txt
dsandberg 2002/11/25 02:15:43
Modified: catalina/src/share/org/apache/catalina/ssi SSICommand.java
SSIConfig.java SSIEcho.java SSIExec.java
SSIFlastmod.java SSIFsize.java SSIInclude.java
SSIMediator.java SSIPrintenv.java SSIProcessor.java
SSISet.java SSIStopProcessingException.java
tester/src/bin tester.xml
Added: catalina/src/share/org/apache/catalina/ssi
ExpressionParseTree.java ExpressionTokenizer.java
SSIConditional.java SSIConditionalState.java
tester/web SSIConditional09.shtml
tester/web/golden SSIConditional09.txt
Log:
Added back Paul Speed's conditional SSI enhancement. Updated code/regression tests to better emulate Apache SSI. Fixed bug w/ expression parser's handling of literals.
Revision Changes Path
1.2 +5 -3 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
Index: SSICommand.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SSICommand.java 24 May 2002 16:35:39 -0000 1.1
+++ SSICommand.java 25 Nov 2002 10:15:42 -0000 1.2
@@ -79,12 +79,14 @@
* Write the output of the command to the writer.
*
* @param ssiMediator the ssi mediator
+ * @param commandName the name of the actual command ( ie. echo )
* @param paramNames The parameter names
* @param paramValues The parameter values
* @param writer the writer to output to
* @throws SSIStopProcessingException if SSI processing should be aborted
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) throws SSIStopProcessingException;
1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
Index: SSIConfig.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIConfig.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSIConfig.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -72,6 +72,7 @@
* Implements the Server-side #exec command
*
* @author Bip Thelin
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -80,6 +81,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer ) {
1.2 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
Index: SSIEcho.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SSIEcho.java 24 May 2002 04:38:58 -0000 1.1
+++ SSIEcho.java 25 Nov 2002 10:15:42 -0000 1.2
@@ -71,6 +71,7 @@
* Return the result associated with the supplied Server Variable.
*
* @author Bip Thelin
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -82,6 +83,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) {
1.3 +7 -5 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
Index: SSIExec.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIExec.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSIExec.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -89,6 +89,7 @@
*
* @author Bip Thelin
* @author Amy Roh
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*
@@ -101,6 +102,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) {
@@ -111,7 +113,7 @@
String substitutedValue = ssiMediator.substituteVariables( paramValue );
if ( paramName.equalsIgnoreCase("cgi") ) {
- ssiInclude.process( ssiMediator, new String[] {"virtual"}, new String[] {substitutedValue}, writer );
+ ssiInclude.process( ssiMediator, "include", new String[] {"virtual"}, new String[] {substitutedValue}, writer );
} else if ( paramName.equalsIgnoreCase("cmd") ) {
boolean foundProgram = false;
try {
1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
Index: SSIFlastmod.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIFlastmod.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSIFlastmod.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -75,6 +75,7 @@
* Implements the Server-side #flastmod command
*
* @author Bip Thelin
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -83,6 +84,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) {
1.4 +9 -7 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
Index: SSIFsize.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SSIFsize.java 24 Nov 2002 06:22:36 -0000 1.3
+++ SSIFsize.java 25 Nov 2002 10:15:42 -0000 1.4
@@ -72,6 +72,7 @@
* Implements the Server-side #fsize command
*
* @author Bip Thelin
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -83,9 +84,10 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
- String[] paramNames,
- String[] paramValues,
- PrintWriter writer) {
+ String commandName,
+ String[] paramNames,
+ String[] paramValues,
+ PrintWriter writer) {
String configErrMsg = ssiMediator.getConfigErrMsg();
for(int i=0;i<paramNames.length;i++) {
1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
Index: SSIInclude.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIInclude.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSIInclude.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -75,6 +75,7 @@
* Implements the Server-side #include command
*
* @author Bip Thelin
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -83,6 +84,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) {
1.3 +10 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
Index: SSIMediator.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIMediator.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSIMediator.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -86,6 +86,7 @@
*
* @author Bip Thelin
* @author Amy Roh
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -102,6 +103,7 @@
protected Date lastModifiedDate;
protected int debug;
protected Strftime strftime;
+ protected SSIConditionalState conditionalState = new SSIConditionalState();
static {
//We try to encode only the same characters that apache does
@@ -163,6 +165,10 @@
public String getConfigSizeFmt() {
return configSizeFmt;
+ }
+
+ public SSIConditionalState getConditionalState() {
+ return conditionalState;
}
public Collection getVariableNames() {
1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
Index: SSIPrintenv.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SSIPrintenv.java 24 May 2002 04:38:58 -0000 1.1
+++ SSIPrintenv.java 25 Nov 2002 10:15:42 -0000 1.2
@@ -79,6 +79,7 @@
* @see SSICommand
*/
public void process(SSIMediator ssiMediator,
+ String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) {
1.2 +82 -41 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
Index: SSIProcessor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SSIProcessor.java 24 May 2002 04:38:58 -0000 1.1
+++ SSIProcessor.java 25 Nov 2002 10:15:42 -0000 1.2
@@ -108,6 +108,11 @@
addCommand( "fsize", new SSIFsize() );
addCommand( "printenv", new SSIPrintenv() );
addCommand( "set", new SSISet() );
+ SSIConditional ssiConditional = new SSIConditional();
+ addCommand( "if", ssiConditional );
+ addCommand( "elif", ssiConditional );
+ addCommand( "endif", ssiConditional );
+ addCommand( "else", ssiConditional );
}
public void addCommand( String name, SSICommand command ) {
@@ -147,7 +152,9 @@
index += COMMAND_START.length();
command.setLength( 0 ); //clear the command string
} else {
- writer.write( c );
+ if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ) {
+ writer.write( c );
+ }
index++;
}
} else {
@@ -159,20 +166,29 @@
ssiExternalResolver.log( "SSIProcessor.process -- processing command: " + strCmd, null );
}
String[] paramNames = parseParamNames(command, strCmd.length());
- String[] paramValues = parseParamValues(command, strCmd.length());
+ String[] paramValues = parseParamValues(command, strCmd.length(), paramNames.length );
//We need to fetch this value each time, since it may change during the loop
String configErrMsg = ssiMediator.getConfigErrMsg();
SSICommand ssiCommand = (SSICommand) commands.get(strCmd.toLowerCase());
- if ( ssiCommand != null ) {
- if ( paramNames.length==paramValues.length ) {
- ssiCommand.process( ssiMediator, paramNames, paramValues, writer );
- } else {
- ssiExternalResolver.log( "Parameter names count does not match parameter values count on command: " + strCmd, null );
- writer.write( configErrMsg );
- }
+ String errorMessage = null;
+ if ( ssiCommand == null ) {
+ errorMessage = "Unknown command: " + strCmd;
+ } else if ( paramValues == null ) {
+ errorMessage = "Error parsing directive parameters.";
+ } else if ( paramNames.length!=paramValues.length ) {
+ errorMessage = "Parameter names count does not match parameter values count on command: " + strCmd;
} else {
- ssiExternalResolver.log( "Unknown command: " + strCmd, null);
+ // don't process the command if we are processing conditional commands only and the
+ // command is not conditional
+ if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ||
+ ssiCommand instanceof SSIConditional ) {
+ ssiCommand.process( ssiMediator, strCmd, paramNames, paramValues, writer );
+ }
+ }
+
+ if ( errorMessage != null ) {
+ ssiExternalResolver.log( errorMessage, null );
writer.write( configErrMsg );
}
} else {
@@ -214,20 +230,29 @@
bIdx++;
}
- retBuf.append('"');
+ retBuf.append('=');
inside=!inside;
quotes=0;
- while(bIdx < cmd.length()&"es!=2) {
- if(cmd.charAt(bIdx)=='"')
- quotes++;
+ boolean escaped=false;
+ for ( ; bIdx < cmd.length() && quotes != 2; bIdx++ ) {
+ char c = cmd.charAt(bIdx);
+
+ // Need to skip escaped characters
+ if (c=='\\' && !escaped) {
+ escaped = true;
+ bIdx++;
+ continue;
+ }
+ escaped = false;
- bIdx++;
+ if (c=='"')
+ quotes++;
}
}
}
- StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
+ StringTokenizer str = new StringTokenizer(retBuf.toString(), "=");
String[] retString = new String[str.countTokens()];
while(str.hasMoreTokens()) {
@@ -243,15 +268,14 @@
* @param cmd a value of type 'StringBuffer'
* @return a value of type 'String[]'
*/
- protected String[] parseParamValues(StringBuffer cmd, int start) {
- int bIdx = start;
- int i = 0;
- int quotes = 0;
+ protected String[] parseParamValues(StringBuffer cmd, int start, int count) {
+ int valIndex = 0;
boolean inside = false;
- StringBuffer retBuf = new StringBuffer();
+ String[] vals = new String[count];
+ StringBuffer sb = new StringBuffer();
- while(bIdx < cmd.length()) {
- if(!inside) {
+ for (int bIdx = start; bIdx < cmd.length(); bIdx++ ) {
+ if (!inside) {
while(bIdx < cmd.length()&&
cmd.charAt(bIdx)!='"')
bIdx++;
@@ -261,26 +285,43 @@
inside=!inside;
} else {
- while(bIdx < cmd.length() && cmd.charAt(bIdx)!='"') {
- retBuf.append(cmd.charAt(bIdx));
- bIdx++;
- }
+ boolean escaped=false;
+ for ( ; bIdx < cmd.length(); bIdx++) {
- retBuf.append('"');
- inside=!inside;
- }
+ char c = cmd.charAt(bIdx);
- bIdx++;
- }
+ // Check for escapes
+ if (c=='\\' && !escaped) {
+ escaped = true;
+ continue;
+ }
+
+ // If we reach the other " then stop
+ if (c=='"' && !escaped)
+ break;
+
+ // Since parsing of attributes and var
+ // substitution is done in separate places,
+ // we need to leave escape in the string
+ if (c=='$' && escaped)
+ sb.append( '\\' );
- StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
- String[] retString = new String[str.countTokens()];
+ escaped = false;
+ sb.append(c);
+ }
- while(str.hasMoreTokens()) {
- retString[i++] = str.nextToken();
+ // If we hit the end without seeing a quote
+ // the signal an error
+ if (bIdx == cmd.length())
+ return null;
+
+ vals[valIndex++] = sb.toString();
+ sb.delete( 0, sb.length() ); // clear the buffer
+ inside=!inside;
+ }
}
- return retString;
+ return vals;
}
/**
1.3 +10 -8 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java
Index: SSISet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSISet.java 24 Nov 2002 06:22:36 -0000 1.2
+++ SSISet.java 25 Nov 2002 10:15:42 -0000 1.3
@@ -70,6 +70,7 @@
/**
* Implements the Server-side #set command
*
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
@@ -77,10 +78,11 @@
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator,
- String[] paramNames,
- String[] paramValues,
- PrintWriter writer) throws SSIStopProcessingException {
+ public void process( SSIMediator ssiMediator,
+ String commandName,
+ String[] paramNames,
+ String[] paramValues,
+ PrintWriter writer) throws SSIStopProcessingException {
String errorMessage = ssiMediator.getConfigErrMsg();
String variableName = null;
1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java
Index: SSIStopProcessingException.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SSIStopProcessingException.java 24 May 2002 04:38:58 -0000 1.1
+++ SSIStopProcessingException.java 25 Nov 2002 10:15:42 -0000 1.2
@@ -67,6 +67,7 @@
* Exception used to tell SSIProcessor that it should stop processing SSI commands.
* This is used to mimick the Apache behavior in #set with invalid attributes.
*
+ * @author Paul Speed
* @author Dan Sandberg
* @version $Revision$, $Date$
*/
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java
Index: ExpressionParseTree.java
===================================================================
/*
* ExpressionParseTree.java
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
* $Revision: 1.1 $
* $Date: 2002/11/25 10:15:42 $
*
* ====================================================================
*
* 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.catalina.ssi;
import java.util.LinkedList;
import java.util.List;
import java.text.ParseException;
/**
* Represents a parsed expression.
*
* @version $Revision: 1.1 $
* @author Paul Speed
*/
public class ExpressionParseTree
{
/**
* Contains the current set of completed nodes. This
* is a workspace for the parser.
*/
private LinkedList nodeStack = new LinkedList();
/**
* Contains operator nodes that don't yet have values.
* This is a workspace for the parser.
*/
private LinkedList oppStack = new LinkedList();
/**
* The root node after the expression has been parsed.
*/
private Node root;
/**
* The SSIMediator to use when evaluating the expressions.
*/
private SSIMediator ssiMediator;
/**
* Creates a new parse tree for the specified expression.
*/
public ExpressionParseTree( String expr,
SSIMediator ssiMediator )
throws ParseException {
this.ssiMediator = ssiMediator;
parseExpression( expr );
}
/**
* Evaluates the tree and returns true or false. The specified
* SSIMediator is used to resolve variable references.
*/
public boolean evaluateTree() {
return root.evaluate();
}
/**
* Pushes a new operator onto the opp stack, resolving existing
* opps as needed.
*/
private void pushOpp( OppNode node ) {
// If node is null then it's just a group marker
if( node == null ) {
oppStack.add( 0, node );
return;
}
while (true) {
if (oppStack.size() == 0)
break;
OppNode top = (OppNode)oppStack.get(0);
// If the top is a spacer then don't pop
// anything
if (top == null)
break;
// If the top node has a lower precedence then
// let it stay
if (top.getPrecedence() < node.getPrecedence())
break;
// Remove the top node
oppStack.remove(0);
// Let it fill its branches
top.popValues( nodeStack );
// Stick it on the resolved node stack
nodeStack.add( 0, top );
}
// Add the new node to the opp stack
oppStack.add( 0, node );
}
/**
* Resolves all pending opp nodes on the stack until the
* next group marker is reached.
*/
private void resolveGroup() {
OppNode top = null;
while ((top=(OppNode)oppStack.remove(0)) != null ) {
// Let it fill its branches
top.popValues( nodeStack );
// Stick it on the resolved node stack
nodeStack.add( 0, top );
}
}
/**
* Parses the specified expression into a tree of
* parse nodes.
*/
private void parseExpression( String expr ) throws ParseException {
StringNode currStringNode = null;
// We cheat a little and start an artificial
// group right away. It makes finishing easier.
pushOpp( null );
ExpressionTokenizer et = new ExpressionTokenizer(expr);
while (et.hasMoreTokens()) {
int token = et.nextToken();
if (token != ExpressionTokenizer.TOKEN_STRING)
currStringNode = null;
switch (token) {
case ExpressionTokenizer.TOKEN_STRING:
if (currStringNode == null) {
currStringNode = new StringNode( et.getTokenValue() );
nodeStack.add( 0, currStringNode );
} else {
// Add to the existing
currStringNode.value.append( " " );
currStringNode.value.append( et.getTokenValue() );
}
break;
case ExpressionTokenizer.TOKEN_AND:
pushOpp( new AndNode() );
break;
case ExpressionTokenizer.TOKEN_OR:
pushOpp( new OrNode() );
break;
case ExpressionTokenizer.TOKEN_NOT:
pushOpp( new NotNode() );
break;
case ExpressionTokenizer.TOKEN_EQ:
pushOpp( new EqualNode() );
break;
case ExpressionTokenizer.TOKEN_NOT_EQ:
pushOpp( new NotNode() );
// Sneak the regular node in. The NOT will
// be resolved when the next opp comes along.
oppStack.add( 0, new EqualNode() );
break;
case ExpressionTokenizer.TOKEN_RBRACE:
// Closeout the current group
resolveGroup();
break;
case ExpressionTokenizer.TOKEN_LBRACE:
// Push a group marker
pushOpp( null );
break;
case ExpressionTokenizer.TOKEN_GE:
pushOpp( new NotNode() );
// Similar stategy to NOT_EQ above, except this
// is NOT less than
oppStack.add( 0, new LessThanNode() );
break;
case ExpressionTokenizer.TOKEN_LE:
pushOpp( new NotNode() );
// Similar stategy to NOT_EQ above, except this
// is NOT greater than
oppStack.add( 0, new GreaterThanNode() );
break;
case ExpressionTokenizer.TOKEN_GT:
pushOpp( new GreaterThanNode() );
break;
case ExpressionTokenizer.TOKEN_LT:
pushOpp( new LessThanNode() );
break;
case ExpressionTokenizer.TOKEN_END:
break;
}
}
// Finish off the rest of the opps
resolveGroup();
if (nodeStack.size() == 0) {
throw new ParseException( "No nodes created.",
et.getIndex() );
}
if (nodeStack.size() > 1) {
throw new ParseException( "Extra nodes created.",
et.getIndex() );
}
if (oppStack.size() != 0) {
throw new ParseException( "Unused opp nodes exist.",
et.getIndex() );
}
root = (Node)nodeStack.get(0);
}
/**
* A node in the expression parse tree.
*/
private abstract class Node {
/**
* Return true if the node evaluates to true.
*/
public abstract boolean evaluate();
}
/**
* A node the represents a String value
*/
private class StringNode extends Node {
StringBuffer value;
String resolved = null;
public StringNode( String value ) {
this.value = new StringBuffer(value);
}
/**
* Resolves any variable references and returns the
* value string.
*/
public String getValue() {
if (resolved == null)
resolved = ssiMediator.substituteVariables( value.toString() ) ;
return resolved;
}
/**
* Returns true if the string is not empty.
*/
public boolean evaluate() {
return !(getValue().length() == 0);
}
public String toString() {
return value.toString();
}
}
private static final int PRECEDENCE_NOT = 5;
private static final int PRECEDENCE_COMPARE = 4;
private static final int PRECEDENCE_LOGICAL = 1;
/**
* A node implementation that represents an operation.
*/
private abstract class OppNode extends Node {
/**
* The left branch.
*/
Node left;
/**
* The right branch.
*/
Node right;
/**
* Returns a preference level suitable for comparison to
* other OppNode preference levels.
*/
public abstract int getPrecedence();
/**
* Lets the node pop its own branch nodes off the front of
* the specified list. The default pulls two.
*/
public void popValues( List values ) {
right = (Node)values.remove(0);
left = (Node)values.remove(0);
}
}
private final class NotNode extends OppNode {
public boolean evaluate() {
return !left.evaluate();
}
public int getPrecedence() {
return PRECEDENCE_NOT;
}
/**
* Overridden to pop only one value.
*/
public void popValues( List values ) {
left = (Node)values.remove(0);
}
public String toString() {
return left + " NOT";
}
}
private final class AndNode extends OppNode {
public boolean evaluate() {
if (!left.evaluate()) // Short circuit
return false;
return right.evaluate();
}
public int getPrecedence() {
return PRECEDENCE_LOGICAL;
}
public String toString() {
return left + " " + right + " AND";
}
}
private final class OrNode extends OppNode {
public boolean evaluate() {
if (left.evaluate()) // Short circuit
return true;
return right.evaluate();
}
public int getPrecedence() {
return PRECEDENCE_LOGICAL;
}
public String toString() {
return left + " " + right + " OR";
}
}
private abstract class CompareNode extends OppNode {
protected int compareBranches() {
String val1 = ((StringNode)left).getValue();
String val2 = ((StringNode)right).getValue();
return val1.compareTo(val2);
}
}
private final class EqualNode extends CompareNode {
public boolean evaluate() {
return (compareBranches() == 0);
}
public int getPrecedence() {
return PRECEDENCE_COMPARE;
}
public String toString() {
return left + " " + right + " EQ";
}
}
private final class GreaterThanNode extends CompareNode {
public boolean evaluate() {
return (compareBranches() > 0);
}
public int getPrecedence() {
return PRECEDENCE_COMPARE;
}
public String toString() {
return left + " " + right + " GT";
}
}
private final class LessThanNode extends CompareNode {
public boolean evaluate() {
return (compareBranches() < 0);
}
public int getPrecedence() {
return PRECEDENCE_COMPARE;
}
public String toString() {
return left + " " + right + " LT";
}
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java
Index: ExpressionTokenizer.java
===================================================================
/*
* ExpressionTokenizer.java
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
* $Revision: 1.1 $
* $Date: 2002/11/25 10:15:42 $
*
* ====================================================================
*
* 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.catalina.ssi;
/**
* Parses an expression string to return the individual tokens.
* This is patterned similar to the StreamTokenizer in the JDK
* but customized for SSI conditional expression parsing.
*
* @version $Revision: 1.1 $
* @author Paul Speed
*/
public class ExpressionTokenizer {
public static final int TOKEN_STRING = 0;
public static final int TOKEN_AND = 1;
public static final int TOKEN_OR = 2;
public static final int TOKEN_NOT = 3;
public static final int TOKEN_EQ = 4;
public static final int TOKEN_NOT_EQ = 5;
public static final int TOKEN_RBRACE = 6;
public static final int TOKEN_LBRACE = 7;
public static final int TOKEN_GE = 8;
public static final int TOKEN_LE = 9;
public static final int TOKEN_GT = 10;
public static final int TOKEN_LT = 11;
public static final int TOKEN_END = 12;
private char[] expr;
private int tokenType = TOKEN_STRING;
private String tokenVal = null;
private int index;
private int length;
/**
* Creates a new parser for the specified expression.
*/
public ExpressionTokenizer( String expr ) {
this.expr = expr.trim().toCharArray();
this.length = this.expr.length;
}
/**
* Returns true if there are more tokens.
*/
public boolean hasMoreTokens() {
return index < length;
}
/**
* Returns the current index for error reporting purposes.
*/
public int getIndex() {
return index;
}
protected boolean isMetaChar( char c ) {
return Character.isWhitespace( c ) ||
c == '(' || c == ')' || c == '!' ||
c == '<' || c == '>' || c == '|' ||
c == '&' || c == '=';
}
/**
* Returns the next token type and initializes any
* state variables accordingly.
*/
public int nextToken() {
// Skip any leading white space
while (index<length && Character.isWhitespace(expr[index]))
index++;
// Clear the current token val
tokenVal = null;
if (index == length)
return TOKEN_END; // End of string
int start = index;
char currentChar = expr[index];
char nextChar = (char)0;
index++;
if (index < length)
nextChar = expr[index];
// Check for a known token start
switch (currentChar) {
case '(':
return TOKEN_LBRACE;
case ')':
return TOKEN_RBRACE;
case '=':
return TOKEN_EQ;
case '!':
if (nextChar == '=') {
index++;
return TOKEN_NOT_EQ;
} else {
return TOKEN_NOT;
}
case '|':
if (nextChar == '|') {
index++;
return TOKEN_OR;
}
break;
case '&':
if (nextChar == '&') {
index++;
return TOKEN_AND;
}
break;
case '>':
if (nextChar == '=') {
index++;
return TOKEN_GE; // Greater than or equal
} else {
return TOKEN_GT; // Greater than
}
case '<':
if (nextChar == '=') {
index++;
return TOKEN_LE; // Less than or equal
} else {
return TOKEN_LT; // Less than
}
default:
// Otherwise it's a string
break;
}
int end = index;
// If it's a quoted string then end is the next unescaped quote
if (currentChar == '"' || currentChar == '\'') {
char endChar = currentChar;
boolean escaped = false;
start++;
for ( ; index < length; index++) {
if (expr[index] == '\\' && !escaped) {
escaped = true;
continue;
}
if (expr[index] == endChar && !escaped)
break;
escaped = false;
}
end = index;
index++; // Skip the end quote
} else {
// End is the next whitespace character
for ( ; index < length; index++) {
if ( isMetaChar(expr[index]) )
break;
}
end = index;
}
// Extract the string from the array
this.tokenVal = new String( expr, start, end - start );
return TOKEN_STRING;
}
/**
* Returns the String value of the token if it was type
* TOKEN_STRING. Otherwise null is returned.
*/
public String getTokenValue() {
return tokenVal;
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
Index: SSIConditional.java
===================================================================
/*
* SSIConditional.java
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
* $Revision: 1.1 $
* $Date: 2002/11/25 10:15:42 $
*
* ====================================================================
*
* 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.catalina.ssi;
import java.io.PrintWriter;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletOutputStream;
/**
* SSI command that handles all conditional directives.
*
* @version $Revision: 1.1 $
* @author Paul Speed
*/
public class SSIConditional implements SSICommand {
/**
* @see SSICommand
*/
public void process( SSIMediator ssiMediator,
String commandName,
String[] paramNames,
String[] paramValues,
PrintWriter writer) throws SSIStopProcessingException {
// Retrieve the current state information
SSIConditionalState state = ssiMediator.getConditionalState();
if ( "if".equalsIgnoreCase( commandName ) ) {
// Do nothing if we are nested in a false branch
// except count it
if ( state.processConditionalCommandsOnly ) {
state.nestingCount++;
return;
}
state.nestingCount = 0;
// Evaluate the expression
if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
// No more branches can be taken for this if block
state.branchTaken = true;
} else {
// Do not process this branch
state.processConditionalCommandsOnly = true;
state.branchTaken = false;
}
} else if ( "elif".equalsIgnoreCase( commandName ) ) {
// No need to even execute if we are nested in
// a false branch
if (state.nestingCount > 0)
return;
// If a branch was already taken in this if block
// then disable output and return
if ( state.branchTaken ) {
state.processConditionalCommandsOnly = true;
return;
}
// Evaluate the expression
if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
// Turn back on output and mark the branch
state.processConditionalCommandsOnly = false;
state.branchTaken = true;
} else {
// Do not process this branch
state.processConditionalCommandsOnly = true;
state.branchTaken = false;
}
} else if ( "else".equalsIgnoreCase( commandName ) ) {
// No need to even execute if we are nested in
// a false branch
if (state.nestingCount > 0)
return;
// If we've already taken another branch then
// disable output otherwise enable it.
state.processConditionalCommandsOnly = state.branchTaken;
// And in any case, it's safe to say a branch
// has been taken.
state.branchTaken = true;
} else if ( "endif".equalsIgnoreCase( commandName ) ) {
// If we are nested inside a false branch then pop out
// one level on the nesting count
if (state.nestingCount > 0) {
state.nestingCount--;
return;
}
// Turn output back on
state.processConditionalCommandsOnly = false;
// Reset the branch status for any outer if blocks,
// since clearly we took a branch to have gotten here
// in the first place.
state.branchTaken = true;
} else {
throw new SSIStopProcessingException();
//throw new SsiCommandException( "Not a conditional command:" + cmdName );
}
}
/**
* Retrieves the expression from the specified arguments
* and peforms the necessary evaluation steps.
*/
private boolean evaluateArguments( String[] names,
String[] values,
SSIMediator ssiMediator ) throws SSIStopProcessingException {
String expr = getExpression( names, values );
if (expr == null) {
throw new SSIStopProcessingException();
//throw new SsiCommandException( "No expression specified." );
}
try {
ExpressionParseTree tree = new ExpressionParseTree( expr,
ssiMediator );
return tree.evaluateTree();
} catch (ParseException e) {
//throw new SsiCommandException( "Error parsing expression." );
throw new SSIStopProcessingException();
}
}
/**
* Returns the "expr" if the arg name is appropriate, otherwise
* returns null.
*/
private String getExpression( String[] paramNames, String[] paramValues ) {
if ( "expr".equalsIgnoreCase( paramNames[0]) )
return paramValues[0];
return null;
}
}
1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java
Index: SSIConditionalState.java
===================================================================
/*
* SSIConditionalState.java
* $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
* $Revision: 1.1 $
* $Date: 2002/11/25 10:15:42 $
*
* ====================================================================
*
* 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.catalina.ssi;
/**
* This class is used by SSIMediator and SSIConditional to keep track of state information necessary to process
* the nested conditional commands ( if, elif, else, endif ).
*
* @version $Revision: 1.1 $
* @author Dan Sandberg
* @author Paul Speed
*/
class SSIConditionalState {
/**
* Set to true if the current conditional has already been
* completed, i.e.: a branch was taken.
*/
boolean branchTaken = false;
/**
* Counts the number of nested false branches.
*/
int nestingCount = 0;
/**
* Set to true if only conditional commands ( if, elif, else, endif ) should be processed.
*/
boolean processConditionalCommandsOnly = false;
}
1.85 +36 -0 jakarta-tomcat-4.0/tester/src/bin/tester.xml
Index: tester.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat-4.0/tester/src/bin/tester.xml,v
retrieving revision 1.84
retrieving revision 1.85
diff -u -r1.84 -r1.85
--- tester.xml 24 Nov 2002 06:22:36 -0000 1.84
+++ tester.xml 25 Nov 2002 10:15:43 -0000 1.85
@@ -1849,6 +1849,42 @@
golden="${golden.path}/SSIFsize02.txt"/>
<tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional01.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional01.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional02.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional02.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional03.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional03.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional04.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional04.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional05.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional05.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional06.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional06.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional07.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional07.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional08.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional08.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
+ request="${context.path}/SSIConditional09.shtml" debug="${debug}"
+ golden="${golden.path}/SSIConditional09.txt"/>
+
+ <tester host="${host}" port="${port}" protocol="${protocol}"
request="${context.path}/SSIVarSub01.shtml" debug="${debug}"
golden="${golden.path}/SSIVarSub01.txt"/>
1.1 jakarta-tomcat-4.0/tester/web/SSIConditional09.shtml
Index: SSIConditional09.shtml
===================================================================
1
<!--#if expr="1=2" -->
a
##<!--#if expr="1=2" -->
b
##<!--#else -->
c
##<!--#endif -->
d
<!--#elif expr="2=2" -->
e
##<!--#if expr="2=2" -->
f
####<!--#if expr="1=2" -->
**11
####<!--#elif expr="2=3" -->
**22
####<!--#endif -->
**33
##<!--#else -->
g
##<!--#endif -->
h
<!--#else -->
i
##<!--#if expr="1=1" -->
j
##<!--#else -->
k
##<!--#endif -->
l
<!--#endif -->
#
now we test extra #endif commands
<!--#endif -->
n
<!--#endif -->
o
1.1 jakarta-tomcat-4.0/tester/web/golden/SSIConditional09.txt
Index: SSIConditional09.txt
===================================================================
1
e
##
f
####
**33
##
h
#
now we test extra #endif commands
n
o
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>
Re: cvs commit: jakarta-tomcat-4.0/tester/web/golden SSIConditional09.txt
Posted by Amy Roh <am...@apache.org>.
Dan,
You might want to port all SSI changes to tomcat 5 as well.
Thanks,
Amy
dsandberg@apache.org wrote:
> dsandberg 2002/11/25 02:15:43
>
> Modified: catalina/src/share/org/apache/catalina/ssi SSICommand.java
> SSIConfig.java SSIEcho.java SSIExec.java
> SSIFlastmod.java SSIFsize.java SSIInclude.java
> SSIMediator.java SSIPrintenv.java SSIProcessor.java
> SSISet.java SSIStopProcessingException.java
> tester/src/bin tester.xml
> Added: catalina/src/share/org/apache/catalina/ssi
> ExpressionParseTree.java ExpressionTokenizer.java
> SSIConditional.java SSIConditionalState.java
> tester/web SSIConditional09.shtml
> tester/web/golden SSIConditional09.txt
> Log:
> Added back Paul Speed's conditional SSI enhancement. Updated code/regression tests to better emulate Apache SSI. Fixed bug w/ expression parser's handling of literals.
>
> Revision Changes Path
> 1.2 +5 -3 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
>
> Index: SSICommand.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSICommand.java 24 May 2002 16:35:39 -0000 1.1
> +++ SSICommand.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -79,12 +79,14 @@
> * Write the output of the command to the writer.
> *
> * @param ssiMediator the ssi mediator
> + * @param commandName the name of the actual command ( ie. echo )
> * @param paramNames The parameter names
> * @param paramValues The parameter values
> * @param writer the writer to output to
> * @throws SSIStopProcessingException if SSI processing should be aborted
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) throws SSIStopProcessingException;
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
>
> Index: SSIConfig.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIConfig.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIConfig.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -72,6 +72,7 @@
> * Implements the Server-side #exec command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -80,6 +81,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer ) {
>
>
>
> 1.2 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
>
> Index: SSIEcho.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIEcho.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIEcho.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -71,6 +71,7 @@
> * Return the result associated with the supplied Server Variable.
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -82,6 +83,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.3 +7 -5 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
>
> Index: SSIExec.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIExec.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIExec.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -89,6 +89,7 @@
> *
> * @author Bip Thelin
> * @author Amy Roh
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> *
> @@ -101,6 +102,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
> @@ -111,7 +113,7 @@
> String substitutedValue = ssiMediator.substituteVariables( paramValue );
>
> if ( paramName.equalsIgnoreCase("cgi") ) {
> - ssiInclude.process( ssiMediator, new String[] {"virtual"}, new String[] {substitutedValue}, writer );
> + ssiInclude.process( ssiMediator, "include", new String[] {"virtual"}, new String[] {substitutedValue}, writer );
> } else if ( paramName.equalsIgnoreCase("cmd") ) {
> boolean foundProgram = false;
> try {
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
>
> Index: SSIFlastmod.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIFlastmod.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIFlastmod.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -75,6 +75,7 @@
> * Implements the Server-side #flastmod command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,6 +84,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.4 +9 -7 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
>
> Index: SSIFsize.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java,v
> retrieving revision 1.3
> retrieving revision 1.4
> diff -u -r1.3 -r1.4
> --- SSIFsize.java 24 Nov 2002 06:22:36 -0000 1.3
> +++ SSIFsize.java 25 Nov 2002 10:15:42 -0000 1.4
> @@ -72,6 +72,7 @@
> * Implements the Server-side #fsize command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,9 +84,10 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> - String[] paramNames,
> - String[] paramValues,
> - PrintWriter writer) {
> + String commandName,
> + String[] paramNames,
> + String[] paramValues,
> + PrintWriter writer) {
>
> String configErrMsg = ssiMediator.getConfigErrMsg();
> for(int i=0;i<paramNames.length;i++) {
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
>
> Index: SSIInclude.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIInclude.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIInclude.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -75,6 +75,7 @@
> * Implements the Server-side #include command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,6 +84,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.3 +10 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
>
> Index: SSIMediator.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIMediator.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIMediator.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -86,6 +86,7 @@
> *
> * @author Bip Thelin
> * @author Amy Roh
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -102,6 +103,7 @@
> protected Date lastModifiedDate;
> protected int debug;
> protected Strftime strftime;
> + protected SSIConditionalState conditionalState = new SSIConditionalState();
>
> static {
> //We try to encode only the same characters that apache does
> @@ -163,6 +165,10 @@
>
> public String getConfigSizeFmt() {
> return configSizeFmt;
> + }
> +
> + public SSIConditionalState getConditionalState() {
> + return conditionalState;
> }
>
> public Collection getVariableNames() {
>
>
>
> 1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
>
> Index: SSIPrintenv.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIPrintenv.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIPrintenv.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -79,6 +79,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.2 +82 -41 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
>
> Index: SSIProcessor.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIProcessor.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIProcessor.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -108,6 +108,11 @@
> addCommand( "fsize", new SSIFsize() );
> addCommand( "printenv", new SSIPrintenv() );
> addCommand( "set", new SSISet() );
> + SSIConditional ssiConditional = new SSIConditional();
> + addCommand( "if", ssiConditional );
> + addCommand( "elif", ssiConditional );
> + addCommand( "endif", ssiConditional );
> + addCommand( "else", ssiConditional );
> }
>
> public void addCommand( String name, SSICommand command ) {
> @@ -147,7 +152,9 @@
> index += COMMAND_START.length();
> command.setLength( 0 ); //clear the command string
> } else {
> - writer.write( c );
> + if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ) {
> + writer.write( c );
> + }
> index++;
> }
> } else {
> @@ -159,20 +166,29 @@
> ssiExternalResolver.log( "SSIProcessor.process -- processing command: " + strCmd, null );
> }
> String[] paramNames = parseParamNames(command, strCmd.length());
> - String[] paramValues = parseParamValues(command, strCmd.length());
> + String[] paramValues = parseParamValues(command, strCmd.length(), paramNames.length );
>
> //We need to fetch this value each time, since it may change during the loop
> String configErrMsg = ssiMediator.getConfigErrMsg();
> SSICommand ssiCommand = (SSICommand) commands.get(strCmd.toLowerCase());
> - if ( ssiCommand != null ) {
> - if ( paramNames.length==paramValues.length ) {
> - ssiCommand.process( ssiMediator, paramNames, paramValues, writer );
> - } else {
> - ssiExternalResolver.log( "Parameter names count does not match parameter values count on command: " + strCmd, null );
> - writer.write( configErrMsg );
> - }
> + String errorMessage = null;
> + if ( ssiCommand == null ) {
> + errorMessage = "Unknown command: " + strCmd;
> + } else if ( paramValues == null ) {
> + errorMessage = "Error parsing directive parameters.";
> + } else if ( paramNames.length!=paramValues.length ) {
> + errorMessage = "Parameter names count does not match parameter values count on command: " + strCmd;
> } else {
> - ssiExternalResolver.log( "Unknown command: " + strCmd, null);
> + // don't process the command if we are processing conditional commands only and the
> + // command is not conditional
> + if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ||
> + ssiCommand instanceof SSIConditional ) {
> + ssiCommand.process( ssiMediator, strCmd, paramNames, paramValues, writer );
> + }
> + }
> +
> + if ( errorMessage != null ) {
> + ssiExternalResolver.log( errorMessage, null );
> writer.write( configErrMsg );
> }
> } else {
> @@ -214,20 +230,29 @@
> bIdx++;
> }
>
> - retBuf.append('"');
> + retBuf.append('=');
> inside=!inside;
> quotes=0;
>
> - while(bIdx < cmd.length()&"es!=2) {
> - if(cmd.charAt(bIdx)=='"')
> - quotes++;
> + boolean escaped=false;
> + for ( ; bIdx < cmd.length() && quotes != 2; bIdx++ ) {
> + char c = cmd.charAt(bIdx);
> +
> + // Need to skip escaped characters
> + if (c=='\\' && !escaped) {
> + escaped = true;
> + bIdx++;
> + continue;
> + }
> + escaped = false;
>
> - bIdx++;
> + if (c=='"')
> + quotes++;
> }
> }
> }
>
> - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
> + StringTokenizer str = new StringTokenizer(retBuf.toString(), "=");
> String[] retString = new String[str.countTokens()];
>
> while(str.hasMoreTokens()) {
> @@ -243,15 +268,14 @@
> * @param cmd a value of type 'StringBuffer'
> * @return a value of type 'String[]'
> */
> - protected String[] parseParamValues(StringBuffer cmd, int start) {
> - int bIdx = start;
> - int i = 0;
> - int quotes = 0;
> + protected String[] parseParamValues(StringBuffer cmd, int start, int count) {
> + int valIndex = 0;
> boolean inside = false;
> - StringBuffer retBuf = new StringBuffer();
> + String[] vals = new String[count];
> + StringBuffer sb = new StringBuffer();
>
> - while(bIdx < cmd.length()) {
> - if(!inside) {
> + for (int bIdx = start; bIdx < cmd.length(); bIdx++ ) {
> + if (!inside) {
> while(bIdx < cmd.length()&&
> cmd.charAt(bIdx)!='"')
> bIdx++;
> @@ -261,26 +285,43 @@
>
> inside=!inside;
> } else {
> - while(bIdx < cmd.length() && cmd.charAt(bIdx)!='"') {
> - retBuf.append(cmd.charAt(bIdx));
> - bIdx++;
> - }
> + boolean escaped=false;
> + for ( ; bIdx < cmd.length(); bIdx++) {
>
> - retBuf.append('"');
> - inside=!inside;
> - }
> + char c = cmd.charAt(bIdx);
>
> - bIdx++;
> - }
> + // Check for escapes
> + if (c=='\\' && !escaped) {
> + escaped = true;
> + continue;
> + }
> +
> + // If we reach the other " then stop
> + if (c=='"' && !escaped)
> + break;
> +
> + // Since parsing of attributes and var
> + // substitution is done in separate places,
> + // we need to leave escape in the string
> + if (c=='$' && escaped)
> + sb.append( '\\' );
>
> - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
> - String[] retString = new String[str.countTokens()];
> + escaped = false;
> + sb.append(c);
> + }
>
> - while(str.hasMoreTokens()) {
> - retString[i++] = str.nextToken();
> + // If we hit the end without seeing a quote
> + // the signal an error
> + if (bIdx == cmd.length())
> + return null;
> +
> + vals[valIndex++] = sb.toString();
> + sb.delete( 0, sb.length() ); // clear the buffer
> + inside=!inside;
> + }
> }
>
> - return retString;
> + return vals;
> }
>
> /**
>
>
>
> 1.3 +10 -8 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java
>
> Index: SSISet.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSISet.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSISet.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -70,6 +70,7 @@
> /**
> * Implements the Server-side #set command
> *
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -77,10 +78,11 @@
> /**
> * @see SSICommand
> */
> - public void process(SSIMediator ssiMediator,
> - String[] paramNames,
> - String[] paramValues,
> - PrintWriter writer) throws SSIStopProcessingException {
> + public void process( SSIMediator ssiMediator,
> + String commandName,
> + String[] paramNames,
> + String[] paramValues,
> + PrintWriter writer) throws SSIStopProcessingException {
>
> String errorMessage = ssiMediator.getConfigErrMsg();
> String variableName = null;
>
>
>
> 1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java
>
> Index: SSIStopProcessingException.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIStopProcessingException.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIStopProcessingException.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -67,6 +67,7 @@
> * Exception used to tell SSIProcessor that it should stop processing SSI commands.
> * This is used to mimick the Apache behavior in #set with invalid attributes.
> *
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java
>
> Index: ExpressionParseTree.java
> ===================================================================
> /*
> * ExpressionParseTree.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> import java.util.LinkedList;
> import java.util.List;
> import java.text.ParseException;
>
> /**
> * Represents a parsed expression.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class ExpressionParseTree
> {
> /**
> * Contains the current set of completed nodes. This
> * is a workspace for the parser.
> */
> private LinkedList nodeStack = new LinkedList();
>
> /**
> * Contains operator nodes that don't yet have values.
> * This is a workspace for the parser.
> */
> private LinkedList oppStack = new LinkedList();
>
> /**
> * The root node after the expression has been parsed.
> */
> private Node root;
>
> /**
> * The SSIMediator to use when evaluating the expressions.
> */
> private SSIMediator ssiMediator;
>
> /**
> * Creates a new parse tree for the specified expression.
> */
> public ExpressionParseTree( String expr,
> SSIMediator ssiMediator )
> throws ParseException {
> this.ssiMediator = ssiMediator;
> parseExpression( expr );
> }
>
> /**
> * Evaluates the tree and returns true or false. The specified
> * SSIMediator is used to resolve variable references.
> */
> public boolean evaluateTree() {
> return root.evaluate();
> }
>
> /**
> * Pushes a new operator onto the opp stack, resolving existing
> * opps as needed.
> */
> private void pushOpp( OppNode node ) {
>
> // If node is null then it's just a group marker
> if( node == null ) {
> oppStack.add( 0, node );
> return;
> }
>
> while (true) {
> if (oppStack.size() == 0)
> break;
> OppNode top = (OppNode)oppStack.get(0);
>
> // If the top is a spacer then don't pop
> // anything
> if (top == null)
> break;
>
> // If the top node has a lower precedence then
> // let it stay
> if (top.getPrecedence() < node.getPrecedence())
> break;
>
> // Remove the top node
> oppStack.remove(0);
>
> // Let it fill its branches
> top.popValues( nodeStack );
>
> // Stick it on the resolved node stack
> nodeStack.add( 0, top );
> }
>
> // Add the new node to the opp stack
> oppStack.add( 0, node );
> }
>
> /**
> * Resolves all pending opp nodes on the stack until the
> * next group marker is reached.
> */
> private void resolveGroup() {
>
> OppNode top = null;
> while ((top=(OppNode)oppStack.remove(0)) != null ) {
> // Let it fill its branches
> top.popValues( nodeStack );
>
> // Stick it on the resolved node stack
> nodeStack.add( 0, top );
> }
> }
>
> /**
> * Parses the specified expression into a tree of
> * parse nodes.
> */
> private void parseExpression( String expr ) throws ParseException {
>
> StringNode currStringNode = null;
>
> // We cheat a little and start an artificial
> // group right away. It makes finishing easier.
> pushOpp( null );
>
> ExpressionTokenizer et = new ExpressionTokenizer(expr);
> while (et.hasMoreTokens()) {
> int token = et.nextToken();
>
> if (token != ExpressionTokenizer.TOKEN_STRING)
> currStringNode = null;
>
> switch (token) {
> case ExpressionTokenizer.TOKEN_STRING:
> if (currStringNode == null) {
> currStringNode = new StringNode( et.getTokenValue() );
> nodeStack.add( 0, currStringNode );
> } else {
> // Add to the existing
> currStringNode.value.append( " " );
> currStringNode.value.append( et.getTokenValue() );
> }
> break;
> case ExpressionTokenizer.TOKEN_AND:
> pushOpp( new AndNode() );
> break;
> case ExpressionTokenizer.TOKEN_OR:
> pushOpp( new OrNode() );
> break;
> case ExpressionTokenizer.TOKEN_NOT:
> pushOpp( new NotNode() );
> break;
> case ExpressionTokenizer.TOKEN_EQ:
> pushOpp( new EqualNode() );
> break;
> case ExpressionTokenizer.TOKEN_NOT_EQ:
> pushOpp( new NotNode() );
> // Sneak the regular node in. The NOT will
> // be resolved when the next opp comes along.
> oppStack.add( 0, new EqualNode() );
> break;
> case ExpressionTokenizer.TOKEN_RBRACE:
> // Closeout the current group
> resolveGroup();
> break;
> case ExpressionTokenizer.TOKEN_LBRACE:
> // Push a group marker
> pushOpp( null );
> break;
> case ExpressionTokenizer.TOKEN_GE:
> pushOpp( new NotNode() );
> // Similar stategy to NOT_EQ above, except this
> // is NOT less than
> oppStack.add( 0, new LessThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_LE:
> pushOpp( new NotNode() );
> // Similar stategy to NOT_EQ above, except this
> // is NOT greater than
> oppStack.add( 0, new GreaterThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_GT:
> pushOpp( new GreaterThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_LT:
> pushOpp( new LessThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_END:
> break;
> }
> }
>
> // Finish off the rest of the opps
> resolveGroup();
>
> if (nodeStack.size() == 0) {
> throw new ParseException( "No nodes created.",
> et.getIndex() );
> }
> if (nodeStack.size() > 1) {
> throw new ParseException( "Extra nodes created.",
> et.getIndex() );
> }
> if (oppStack.size() != 0) {
> throw new ParseException( "Unused opp nodes exist.",
> et.getIndex() );
> }
>
> root = (Node)nodeStack.get(0);
> }
>
> /**
> * A node in the expression parse tree.
> */
> private abstract class Node {
>
> /**
> * Return true if the node evaluates to true.
> */
> public abstract boolean evaluate();
> }
>
> /**
> * A node the represents a String value
> */
> private class StringNode extends Node {
>
> StringBuffer value;
> String resolved = null;
>
> public StringNode( String value ) {
> this.value = new StringBuffer(value);
> }
>
> /**
> * Resolves any variable references and returns the
> * value string.
> */
> public String getValue() {
> if (resolved == null)
> resolved = ssiMediator.substituteVariables( value.toString() ) ;
> return resolved;
> }
>
> /**
> * Returns true if the string is not empty.
> */
> public boolean evaluate() {
> return !(getValue().length() == 0);
> }
>
> public String toString() {
> return value.toString();
> }
> }
>
> private static final int PRECEDENCE_NOT = 5;
> private static final int PRECEDENCE_COMPARE = 4;
> private static final int PRECEDENCE_LOGICAL = 1;
>
> /**
> * A node implementation that represents an operation.
> */
> private abstract class OppNode extends Node {
>
> /**
> * The left branch.
> */
> Node left;
>
> /**
> * The right branch.
> */
> Node right;
>
> /**
> * Returns a preference level suitable for comparison to
> * other OppNode preference levels.
> */
> public abstract int getPrecedence();
>
> /**
> * Lets the node pop its own branch nodes off the front of
> * the specified list. The default pulls two.
> */
> public void popValues( List values ) {
> right = (Node)values.remove(0);
> left = (Node)values.remove(0);
> }
> }
>
> private final class NotNode extends OppNode {
>
> public boolean evaluate() {
> return !left.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_NOT;
> }
>
> /**
> * Overridden to pop only one value.
> */
> public void popValues( List values ) {
> left = (Node)values.remove(0);
> }
>
> public String toString() {
> return left + " NOT";
> }
> }
>
> private final class AndNode extends OppNode {
>
> public boolean evaluate() {
> if (!left.evaluate()) // Short circuit
> return false;
> return right.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_LOGICAL;
> }
>
> public String toString() {
> return left + " " + right + " AND";
> }
> }
>
> private final class OrNode extends OppNode {
>
> public boolean evaluate() {
> if (left.evaluate()) // Short circuit
> return true;
> return right.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_LOGICAL;
> }
>
> public String toString() {
> return left + " " + right + " OR";
> }
> }
>
> private abstract class CompareNode extends OppNode {
> protected int compareBranches() {
> String val1 = ((StringNode)left).getValue();
> String val2 = ((StringNode)right).getValue();
> return val1.compareTo(val2);
> }
> }
>
> private final class EqualNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() == 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " EQ";
> }
> }
>
> private final class GreaterThanNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() > 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " GT";
> }
> }
>
> private final class LessThanNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() < 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " LT";
> }
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java
>
> Index: ExpressionTokenizer.java
> ===================================================================
> /*
> * ExpressionTokenizer.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> /**
> * Parses an expression string to return the individual tokens.
> * This is patterned similar to the StreamTokenizer in the JDK
> * but customized for SSI conditional expression parsing.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class ExpressionTokenizer {
>
> public static final int TOKEN_STRING = 0;
> public static final int TOKEN_AND = 1;
> public static final int TOKEN_OR = 2;
> public static final int TOKEN_NOT = 3;
> public static final int TOKEN_EQ = 4;
> public static final int TOKEN_NOT_EQ = 5;
> public static final int TOKEN_RBRACE = 6;
> public static final int TOKEN_LBRACE = 7;
> public static final int TOKEN_GE = 8;
> public static final int TOKEN_LE = 9;
> public static final int TOKEN_GT = 10;
> public static final int TOKEN_LT = 11;
> public static final int TOKEN_END = 12;
>
> private char[] expr;
> private int tokenType = TOKEN_STRING;
> private String tokenVal = null;
> private int index;
> private int length;
>
> /**
> * Creates a new parser for the specified expression.
> */
> public ExpressionTokenizer( String expr ) {
> this.expr = expr.trim().toCharArray();
> this.length = this.expr.length;
> }
>
> /**
> * Returns true if there are more tokens.
> */
> public boolean hasMoreTokens() {
> return index < length;
> }
>
> /**
> * Returns the current index for error reporting purposes.
> */
> public int getIndex() {
> return index;
> }
>
> protected boolean isMetaChar( char c ) {
> return Character.isWhitespace( c ) ||
> c == '(' || c == ')' || c == '!' ||
> c == '<' || c == '>' || c == '|' ||
> c == '&' || c == '=';
> }
>
> /**
> * Returns the next token type and initializes any
> * state variables accordingly.
> */
> public int nextToken() {
> // Skip any leading white space
> while (index<length && Character.isWhitespace(expr[index]))
> index++;
>
> // Clear the current token val
> tokenVal = null;
>
> if (index == length)
> return TOKEN_END; // End of string
>
> int start = index;
> char currentChar = expr[index];
> char nextChar = (char)0;
> index++;
> if (index < length)
> nextChar = expr[index];
>
> // Check for a known token start
> switch (currentChar) {
> case '(':
> return TOKEN_LBRACE;
> case ')':
> return TOKEN_RBRACE;
> case '=':
> return TOKEN_EQ;
> case '!':
> if (nextChar == '=') {
> index++;
> return TOKEN_NOT_EQ;
> } else {
> return TOKEN_NOT;
> }
> case '|':
> if (nextChar == '|') {
> index++;
> return TOKEN_OR;
> }
> break;
> case '&':
> if (nextChar == '&') {
> index++;
> return TOKEN_AND;
> }
> break;
> case '>':
> if (nextChar == '=') {
> index++;
> return TOKEN_GE; // Greater than or equal
> } else {
> return TOKEN_GT; // Greater than
> }
> case '<':
> if (nextChar == '=') {
> index++;
> return TOKEN_LE; // Less than or equal
> } else {
> return TOKEN_LT; // Less than
> }
> default:
> // Otherwise it's a string
> break;
> }
>
> int end = index;
>
> // If it's a quoted string then end is the next unescaped quote
> if (currentChar == '"' || currentChar == '\'') {
> char endChar = currentChar;
> boolean escaped = false;
> start++;
> for ( ; index < length; index++) {
> if (expr[index] == '\\' && !escaped) {
> escaped = true;
> continue;
> }
> if (expr[index] == endChar && !escaped)
> break;
>
> escaped = false;
> }
> end = index;
> index++; // Skip the end quote
> } else {
> // End is the next whitespace character
> for ( ; index < length; index++) {
> if ( isMetaChar(expr[index]) )
> break;
> }
> end = index;
> }
>
> // Extract the string from the array
> this.tokenVal = new String( expr, start, end - start );
>
> return TOKEN_STRING;
> }
>
> /**
> * Returns the String value of the token if it was type
> * TOKEN_STRING. Otherwise null is returned.
> */
> public String getTokenValue() {
> return tokenVal;
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
>
> Index: SSIConditional.java
> ===================================================================
> /*
> * SSIConditional.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> import java.io.PrintWriter;
> import java.text.ParseException;
> import java.util.LinkedList;
> import java.util.List;
>
> import javax.servlet.ServletOutputStream;
>
> /**
> * SSI command that handles all conditional directives.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class SSIConditional implements SSICommand {
> /**
> * @see SSICommand
> */
> public void process( SSIMediator ssiMediator,
> String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) throws SSIStopProcessingException {
>
> // Retrieve the current state information
> SSIConditionalState state = ssiMediator.getConditionalState();
>
> if ( "if".equalsIgnoreCase( commandName ) ) {
> // Do nothing if we are nested in a false branch
> // except count it
> if ( state.processConditionalCommandsOnly ) {
> state.nestingCount++;
> return;
> }
>
> state.nestingCount = 0;
>
> // Evaluate the expression
> if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
> // No more branches can be taken for this if block
> state.branchTaken = true;
> } else {
> // Do not process this branch
> state.processConditionalCommandsOnly = true;
> state.branchTaken = false;
> }
>
> } else if ( "elif".equalsIgnoreCase( commandName ) ) {
> // No need to even execute if we are nested in
> // a false branch
> if (state.nestingCount > 0)
> return;
>
> // If a branch was already taken in this if block
> // then disable output and return
> if ( state.branchTaken ) {
> state.processConditionalCommandsOnly = true;
> return;
> }
>
> // Evaluate the expression
> if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
> // Turn back on output and mark the branch
> state.processConditionalCommandsOnly = false;
> state.branchTaken = true;
> } else {
> // Do not process this branch
> state.processConditionalCommandsOnly = true;
> state.branchTaken = false;
> }
>
> } else if ( "else".equalsIgnoreCase( commandName ) ) {
> // No need to even execute if we are nested in
> // a false branch
> if (state.nestingCount > 0)
> return;
>
> // If we've already taken another branch then
> // disable output otherwise enable it.
> state.processConditionalCommandsOnly = state.branchTaken;
>
> // And in any case, it's safe to say a branch
> // has been taken.
> state.branchTaken = true;
>
> } else if ( "endif".equalsIgnoreCase( commandName ) ) {
> // If we are nested inside a false branch then pop out
> // one level on the nesting count
> if (state.nestingCount > 0) {
> state.nestingCount--;
> return;
> }
>
> // Turn output back on
> state.processConditionalCommandsOnly = false;
>
> // Reset the branch status for any outer if blocks,
> // since clearly we took a branch to have gotten here
> // in the first place.
> state.branchTaken = true;
> } else {
> throw new SSIStopProcessingException();
> //throw new SsiCommandException( "Not a conditional command:" + cmdName );
> }
> }
>
> /**
> * Retrieves the expression from the specified arguments
> * and peforms the necessary evaluation steps.
> */
> private boolean evaluateArguments( String[] names,
> String[] values,
> SSIMediator ssiMediator ) throws SSIStopProcessingException {
> String expr = getExpression( names, values );
> if (expr == null) {
> throw new SSIStopProcessingException();
> //throw new SsiCommandException( "No expression specified." );
> }
>
> try {
> ExpressionParseTree tree = new ExpressionParseTree( expr,
> ssiMediator );
> return tree.evaluateTree();
> } catch (ParseException e) {
> //throw new SsiCommandException( "Error parsing expression." );
> throw new SSIStopProcessingException();
> }
> }
>
> /**
> * Returns the "expr" if the arg name is appropriate, otherwise
> * returns null.
> */
> private String getExpression( String[] paramNames, String[] paramValues ) {
> if ( "expr".equalsIgnoreCase( paramNames[0]) )
> return paramValues[0];
> return null;
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java
>
> Index: SSIConditionalState.java
> ===================================================================
> /*
> * SSIConditionalState.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> /**
> * This class is used by SSIMediator and SSIConditional to keep track of state information necessary to process
> * the nested conditional commands ( if, elif, else, endif ).
> *
> * @version $Revision: 1.1 $
> * @author Dan Sandberg
> * @author Paul Speed
> */
> class SSIConditionalState {
> /**
> * Set to true if the current conditional has already been
> * completed, i.e.: a branch was taken.
> */
> boolean branchTaken = false;
>
> /**
> * Counts the number of nested false branches.
> */
> int nestingCount = 0;
>
> /**
> * Set to true if only conditional commands ( if, elif, else, endif ) should be processed.
> */
> boolean processConditionalCommandsOnly = false;
> }
>
>
>
> 1.85 +36 -0 jakarta-tomcat-4.0/tester/src/bin/tester.xml
>
> Index: tester.xml
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/tester/src/bin/tester.xml,v
> retrieving revision 1.84
> retrieving revision 1.85
> diff -u -r1.84 -r1.85
> --- tester.xml 24 Nov 2002 06:22:36 -0000 1.84
> +++ tester.xml 25 Nov 2002 10:15:43 -0000 1.85
> @@ -1849,6 +1849,42 @@
> golden="${golden.path}/SSIFsize02.txt"/>
>
> <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional01.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional01.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional02.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional02.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional03.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional03.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional04.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional04.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional05.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional05.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional06.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional06.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional07.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional07.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional08.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional08.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional09.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional09.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> request="${context.path}/SSIVarSub01.shtml" debug="${debug}"
> golden="${golden.path}/SSIVarSub01.txt"/>
>
>
>
>
> 1.1 jakarta-tomcat-4.0/tester/web/SSIConditional09.shtml
>
> Index: SSIConditional09.shtml
> ===================================================================
> 1
> <!--#if expr="1=2" -->
> a
> ##<!--#if expr="1=2" -->
> b
> ##<!--#else -->
> c
> ##<!--#endif -->
> d
> <!--#elif expr="2=2" -->
> e
> ##<!--#if expr="2=2" -->
> f
> ####<!--#if expr="1=2" -->
> **11
> ####<!--#elif expr="2=3" -->
> **22
> ####<!--#endif -->
> **33
> ##<!--#else -->
> g
> ##<!--#endif -->
> h
> <!--#else -->
> i
> ##<!--#if expr="1=1" -->
> j
> ##<!--#else -->
> k
> ##<!--#endif -->
> l
> <!--#endif -->
> #
> now we test extra #endif commands
> <!--#endif -->
> n
> <!--#endif -->
> o
>
>
> 1.1 jakarta-tomcat-4.0/tester/web/golden/SSIConditional09.txt
>
> Index: SSIConditional09.txt
> ===================================================================
> 1
>
> e
> ##
> f
> ####
> **33
> ##
> h
>
> #
> now we test extra #endif commands
>
> n
>
> o
>
>
>
> --
> To unsubscribe, e-mail: <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
>
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>
Re: cvs commit: jakarta-tomcat-4.0/tester/web/golden
SSIConditional09.txt
Posted by Paul Speed <pa...@objectsciences.com>.
Thanks Dan. Now I have my 15 milliseconds of fame back. ;)
I'll see if I can test the updates with my site soon.
-Paul Speed
dsandberg@apache.org wrote:
>
> dsandberg 2002/11/25 02:15:43
>
> Modified: catalina/src/share/org/apache/catalina/ssi SSICommand.java
> SSIConfig.java SSIEcho.java SSIExec.java
> SSIFlastmod.java SSIFsize.java SSIInclude.java
> SSIMediator.java SSIPrintenv.java SSIProcessor.java
> SSISet.java SSIStopProcessingException.java
> tester/src/bin tester.xml
> Added: catalina/src/share/org/apache/catalina/ssi
> ExpressionParseTree.java ExpressionTokenizer.java
> SSIConditional.java SSIConditionalState.java
> tester/web SSIConditional09.shtml
> tester/web/golden SSIConditional09.txt
> Log:
> Added back Paul Speed's conditional SSI enhancement. Updated code/regression tests to better emulate Apache SSI. Fixed bug w/ expression parser's handling of literals.
>
> Revision Changes Path
> 1.2 +5 -3 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
>
> Index: SSICommand.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSICommand.java 24 May 2002 16:35:39 -0000 1.1
> +++ SSICommand.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -79,12 +79,14 @@
> * Write the output of the command to the writer.
> *
> * @param ssiMediator the ssi mediator
> + * @param commandName the name of the actual command ( ie. echo )
> * @param paramNames The parameter names
> * @param paramValues The parameter values
> * @param writer the writer to output to
> * @throws SSIStopProcessingException if SSI processing should be aborted
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) throws SSIStopProcessingException;
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
>
> Index: SSIConfig.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIConfig.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIConfig.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -72,6 +72,7 @@
> * Implements the Server-side #exec command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -80,6 +81,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer ) {
>
>
>
> 1.2 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
>
> Index: SSIEcho.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIEcho.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIEcho.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -71,6 +71,7 @@
> * Return the result associated with the supplied Server Variable.
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -82,6 +83,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.3 +7 -5 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
>
> Index: SSIExec.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIExec.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIExec.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -89,6 +89,7 @@
> *
> * @author Bip Thelin
> * @author Amy Roh
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> *
> @@ -101,6 +102,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
> @@ -111,7 +113,7 @@
> String substitutedValue = ssiMediator.substituteVariables( paramValue );
>
> if ( paramName.equalsIgnoreCase("cgi") ) {
> - ssiInclude.process( ssiMediator, new String[] {"virtual"}, new String[] {substitutedValue}, writer );
> + ssiInclude.process( ssiMediator, "include", new String[] {"virtual"}, new String[] {substitutedValue}, writer );
> } else if ( paramName.equalsIgnoreCase("cmd") ) {
> boolean foundProgram = false;
> try {
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
>
> Index: SSIFlastmod.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIFlastmod.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIFlastmod.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -75,6 +75,7 @@
> * Implements the Server-side #flastmod command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,6 +84,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.4 +9 -7 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
>
> Index: SSIFsize.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java,v
> retrieving revision 1.3
> retrieving revision 1.4
> diff -u -r1.3 -r1.4
> --- SSIFsize.java 24 Nov 2002 06:22:36 -0000 1.3
> +++ SSIFsize.java 25 Nov 2002 10:15:42 -0000 1.4
> @@ -72,6 +72,7 @@
> * Implements the Server-side #fsize command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,9 +84,10 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> - String[] paramNames,
> - String[] paramValues,
> - PrintWriter writer) {
> + String commandName,
> + String[] paramNames,
> + String[] paramValues,
> + PrintWriter writer) {
>
> String configErrMsg = ssiMediator.getConfigErrMsg();
> for(int i=0;i<paramNames.length;i++) {
>
>
>
> 1.3 +6 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
>
> Index: SSIInclude.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIInclude.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIInclude.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -75,6 +75,7 @@
> * Implements the Server-side #include command
> *
> * @author Bip Thelin
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -83,6 +84,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.3 +10 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
>
> Index: SSIMediator.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSIMediator.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSIMediator.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -86,6 +86,7 @@
> *
> * @author Bip Thelin
> * @author Amy Roh
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -102,6 +103,7 @@
> protected Date lastModifiedDate;
> protected int debug;
> protected Strftime strftime;
> + protected SSIConditionalState conditionalState = new SSIConditionalState();
>
> static {
> //We try to encode only the same characters that apache does
> @@ -163,6 +165,10 @@
>
> public String getConfigSizeFmt() {
> return configSizeFmt;
> + }
> +
> + public SSIConditionalState getConditionalState() {
> + return conditionalState;
> }
>
> public Collection getVariableNames() {
>
>
>
> 1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
>
> Index: SSIPrintenv.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIPrintenv.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIPrintenv.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -79,6 +79,7 @@
> * @see SSICommand
> */
> public void process(SSIMediator ssiMediator,
> + String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) {
>
>
>
> 1.2 +82 -41 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
>
> Index: SSIProcessor.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIProcessor.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIProcessor.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -108,6 +108,11 @@
> addCommand( "fsize", new SSIFsize() );
> addCommand( "printenv", new SSIPrintenv() );
> addCommand( "set", new SSISet() );
> + SSIConditional ssiConditional = new SSIConditional();
> + addCommand( "if", ssiConditional );
> + addCommand( "elif", ssiConditional );
> + addCommand( "endif", ssiConditional );
> + addCommand( "else", ssiConditional );
> }
>
> public void addCommand( String name, SSICommand command ) {
> @@ -147,7 +152,9 @@
> index += COMMAND_START.length();
> command.setLength( 0 ); //clear the command string
> } else {
> - writer.write( c );
> + if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ) {
> + writer.write( c );
> + }
> index++;
> }
> } else {
> @@ -159,20 +166,29 @@
> ssiExternalResolver.log( "SSIProcessor.process -- processing command: " + strCmd, null );
> }
> String[] paramNames = parseParamNames(command, strCmd.length());
> - String[] paramValues = parseParamValues(command, strCmd.length());
> + String[] paramValues = parseParamValues(command, strCmd.length(), paramNames.length );
>
> //We need to fetch this value each time, since it may change during the loop
> String configErrMsg = ssiMediator.getConfigErrMsg();
> SSICommand ssiCommand = (SSICommand) commands.get(strCmd.toLowerCase());
> - if ( ssiCommand != null ) {
> - if ( paramNames.length==paramValues.length ) {
> - ssiCommand.process( ssiMediator, paramNames, paramValues, writer );
> - } else {
> - ssiExternalResolver.log( "Parameter names count does not match parameter values count on command: " + strCmd, null );
> - writer.write( configErrMsg );
> - }
> + String errorMessage = null;
> + if ( ssiCommand == null ) {
> + errorMessage = "Unknown command: " + strCmd;
> + } else if ( paramValues == null ) {
> + errorMessage = "Error parsing directive parameters.";
> + } else if ( paramNames.length!=paramValues.length ) {
> + errorMessage = "Parameter names count does not match parameter values count on command: " + strCmd;
> } else {
> - ssiExternalResolver.log( "Unknown command: " + strCmd, null);
> + // don't process the command if we are processing conditional commands only and the
> + // command is not conditional
> + if ( !ssiMediator.getConditionalState().processConditionalCommandsOnly ||
> + ssiCommand instanceof SSIConditional ) {
> + ssiCommand.process( ssiMediator, strCmd, paramNames, paramValues, writer );
> + }
> + }
> +
> + if ( errorMessage != null ) {
> + ssiExternalResolver.log( errorMessage, null );
> writer.write( configErrMsg );
> }
> } else {
> @@ -214,20 +230,29 @@
> bIdx++;
> }
>
> - retBuf.append('"');
> + retBuf.append('=');
> inside=!inside;
> quotes=0;
>
> - while(bIdx < cmd.length()&"es!=2) {
> - if(cmd.charAt(bIdx)=='"')
> - quotes++;
> + boolean escaped=false;
> + for ( ; bIdx < cmd.length() && quotes != 2; bIdx++ ) {
> + char c = cmd.charAt(bIdx);
> +
> + // Need to skip escaped characters
> + if (c=='\\' && !escaped) {
> + escaped = true;
> + bIdx++;
> + continue;
> + }
> + escaped = false;
>
> - bIdx++;
> + if (c=='"')
> + quotes++;
> }
> }
> }
>
> - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
> + StringTokenizer str = new StringTokenizer(retBuf.toString(), "=");
> String[] retString = new String[str.countTokens()];
>
> while(str.hasMoreTokens()) {
> @@ -243,15 +268,14 @@
> * @param cmd a value of type 'StringBuffer'
> * @return a value of type 'String[]'
> */
> - protected String[] parseParamValues(StringBuffer cmd, int start) {
> - int bIdx = start;
> - int i = 0;
> - int quotes = 0;
> + protected String[] parseParamValues(StringBuffer cmd, int start, int count) {
> + int valIndex = 0;
> boolean inside = false;
> - StringBuffer retBuf = new StringBuffer();
> + String[] vals = new String[count];
> + StringBuffer sb = new StringBuffer();
>
> - while(bIdx < cmd.length()) {
> - if(!inside) {
> + for (int bIdx = start; bIdx < cmd.length(); bIdx++ ) {
> + if (!inside) {
> while(bIdx < cmd.length()&&
> cmd.charAt(bIdx)!='"')
> bIdx++;
> @@ -261,26 +285,43 @@
>
> inside=!inside;
> } else {
> - while(bIdx < cmd.length() && cmd.charAt(bIdx)!='"') {
> - retBuf.append(cmd.charAt(bIdx));
> - bIdx++;
> - }
> + boolean escaped=false;
> + for ( ; bIdx < cmd.length(); bIdx++) {
>
> - retBuf.append('"');
> - inside=!inside;
> - }
> + char c = cmd.charAt(bIdx);
>
> - bIdx++;
> - }
> + // Check for escapes
> + if (c=='\\' && !escaped) {
> + escaped = true;
> + continue;
> + }
> +
> + // If we reach the other " then stop
> + if (c=='"' && !escaped)
> + break;
> +
> + // Since parsing of attributes and var
> + // substitution is done in separate places,
> + // we need to leave escape in the string
> + if (c=='$' && escaped)
> + sb.append( '\\' );
>
> - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\"");
> - String[] retString = new String[str.countTokens()];
> + escaped = false;
> + sb.append(c);
> + }
>
> - while(str.hasMoreTokens()) {
> - retString[i++] = str.nextToken();
> + // If we hit the end without seeing a quote
> + // the signal an error
> + if (bIdx == cmd.length())
> + return null;
> +
> + vals[valIndex++] = sb.toString();
> + sb.delete( 0, sb.length() ); // clear the buffer
> + inside=!inside;
> + }
> }
>
> - return retString;
> + return vals;
> }
>
> /**
>
>
>
> 1.3 +10 -8 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java
>
> Index: SSISet.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java,v
> retrieving revision 1.2
> retrieving revision 1.3
> diff -u -r1.2 -r1.3
> --- SSISet.java 24 Nov 2002 06:22:36 -0000 1.2
> +++ SSISet.java 25 Nov 2002 10:15:42 -0000 1.3
> @@ -70,6 +70,7 @@
> /**
> * Implements the Server-side #set command
> *
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
> @@ -77,10 +78,11 @@
> /**
> * @see SSICommand
> */
> - public void process(SSIMediator ssiMediator,
> - String[] paramNames,
> - String[] paramValues,
> - PrintWriter writer) throws SSIStopProcessingException {
> + public void process( SSIMediator ssiMediator,
> + String commandName,
> + String[] paramNames,
> + String[] paramValues,
> + PrintWriter writer) throws SSIStopProcessingException {
>
> String errorMessage = ssiMediator.getConfigErrMsg();
> String variableName = null;
>
>
>
> 1.2 +5 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java
>
> Index: SSIStopProcessingException.java
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java,v
> retrieving revision 1.1
> retrieving revision 1.2
> diff -u -r1.1 -r1.2
> --- SSIStopProcessingException.java 24 May 2002 04:38:58 -0000 1.1
> +++ SSIStopProcessingException.java 25 Nov 2002 10:15:42 -0000 1.2
> @@ -67,6 +67,7 @@
> * Exception used to tell SSIProcessor that it should stop processing SSI commands.
> * This is used to mimick the Apache behavior in #set with invalid attributes.
> *
> + * @author Paul Speed
> * @author Dan Sandberg
> * @version $Revision$, $Date$
> */
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java
>
> Index: ExpressionParseTree.java
> ===================================================================
> /*
> * ExpressionParseTree.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> import java.util.LinkedList;
> import java.util.List;
> import java.text.ParseException;
>
> /**
> * Represents a parsed expression.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class ExpressionParseTree
> {
> /**
> * Contains the current set of completed nodes. This
> * is a workspace for the parser.
> */
> private LinkedList nodeStack = new LinkedList();
>
> /**
> * Contains operator nodes that don't yet have values.
> * This is a workspace for the parser.
> */
> private LinkedList oppStack = new LinkedList();
>
> /**
> * The root node after the expression has been parsed.
> */
> private Node root;
>
> /**
> * The SSIMediator to use when evaluating the expressions.
> */
> private SSIMediator ssiMediator;
>
> /**
> * Creates a new parse tree for the specified expression.
> */
> public ExpressionParseTree( String expr,
> SSIMediator ssiMediator )
> throws ParseException {
> this.ssiMediator = ssiMediator;
> parseExpression( expr );
> }
>
> /**
> * Evaluates the tree and returns true or false. The specified
> * SSIMediator is used to resolve variable references.
> */
> public boolean evaluateTree() {
> return root.evaluate();
> }
>
> /**
> * Pushes a new operator onto the opp stack, resolving existing
> * opps as needed.
> */
> private void pushOpp( OppNode node ) {
>
> // If node is null then it's just a group marker
> if( node == null ) {
> oppStack.add( 0, node );
> return;
> }
>
> while (true) {
> if (oppStack.size() == 0)
> break;
> OppNode top = (OppNode)oppStack.get(0);
>
> // If the top is a spacer then don't pop
> // anything
> if (top == null)
> break;
>
> // If the top node has a lower precedence then
> // let it stay
> if (top.getPrecedence() < node.getPrecedence())
> break;
>
> // Remove the top node
> oppStack.remove(0);
>
> // Let it fill its branches
> top.popValues( nodeStack );
>
> // Stick it on the resolved node stack
> nodeStack.add( 0, top );
> }
>
> // Add the new node to the opp stack
> oppStack.add( 0, node );
> }
>
> /**
> * Resolves all pending opp nodes on the stack until the
> * next group marker is reached.
> */
> private void resolveGroup() {
>
> OppNode top = null;
> while ((top=(OppNode)oppStack.remove(0)) != null ) {
> // Let it fill its branches
> top.popValues( nodeStack );
>
> // Stick it on the resolved node stack
> nodeStack.add( 0, top );
> }
> }
>
> /**
> * Parses the specified expression into a tree of
> * parse nodes.
> */
> private void parseExpression( String expr ) throws ParseException {
>
> StringNode currStringNode = null;
>
> // We cheat a little and start an artificial
> // group right away. It makes finishing easier.
> pushOpp( null );
>
> ExpressionTokenizer et = new ExpressionTokenizer(expr);
> while (et.hasMoreTokens()) {
> int token = et.nextToken();
>
> if (token != ExpressionTokenizer.TOKEN_STRING)
> currStringNode = null;
>
> switch (token) {
> case ExpressionTokenizer.TOKEN_STRING:
> if (currStringNode == null) {
> currStringNode = new StringNode( et.getTokenValue() );
> nodeStack.add( 0, currStringNode );
> } else {
> // Add to the existing
> currStringNode.value.append( " " );
> currStringNode.value.append( et.getTokenValue() );
> }
> break;
> case ExpressionTokenizer.TOKEN_AND:
> pushOpp( new AndNode() );
> break;
> case ExpressionTokenizer.TOKEN_OR:
> pushOpp( new OrNode() );
> break;
> case ExpressionTokenizer.TOKEN_NOT:
> pushOpp( new NotNode() );
> break;
> case ExpressionTokenizer.TOKEN_EQ:
> pushOpp( new EqualNode() );
> break;
> case ExpressionTokenizer.TOKEN_NOT_EQ:
> pushOpp( new NotNode() );
> // Sneak the regular node in. The NOT will
> // be resolved when the next opp comes along.
> oppStack.add( 0, new EqualNode() );
> break;
> case ExpressionTokenizer.TOKEN_RBRACE:
> // Closeout the current group
> resolveGroup();
> break;
> case ExpressionTokenizer.TOKEN_LBRACE:
> // Push a group marker
> pushOpp( null );
> break;
> case ExpressionTokenizer.TOKEN_GE:
> pushOpp( new NotNode() );
> // Similar stategy to NOT_EQ above, except this
> // is NOT less than
> oppStack.add( 0, new LessThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_LE:
> pushOpp( new NotNode() );
> // Similar stategy to NOT_EQ above, except this
> // is NOT greater than
> oppStack.add( 0, new GreaterThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_GT:
> pushOpp( new GreaterThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_LT:
> pushOpp( new LessThanNode() );
> break;
> case ExpressionTokenizer.TOKEN_END:
> break;
> }
> }
>
> // Finish off the rest of the opps
> resolveGroup();
>
> if (nodeStack.size() == 0) {
> throw new ParseException( "No nodes created.",
> et.getIndex() );
> }
> if (nodeStack.size() > 1) {
> throw new ParseException( "Extra nodes created.",
> et.getIndex() );
> }
> if (oppStack.size() != 0) {
> throw new ParseException( "Unused opp nodes exist.",
> et.getIndex() );
> }
>
> root = (Node)nodeStack.get(0);
> }
>
> /**
> * A node in the expression parse tree.
> */
> private abstract class Node {
>
> /**
> * Return true if the node evaluates to true.
> */
> public abstract boolean evaluate();
> }
>
> /**
> * A node the represents a String value
> */
> private class StringNode extends Node {
>
> StringBuffer value;
> String resolved = null;
>
> public StringNode( String value ) {
> this.value = new StringBuffer(value);
> }
>
> /**
> * Resolves any variable references and returns the
> * value string.
> */
> public String getValue() {
> if (resolved == null)
> resolved = ssiMediator.substituteVariables( value.toString() ) ;
> return resolved;
> }
>
> /**
> * Returns true if the string is not empty.
> */
> public boolean evaluate() {
> return !(getValue().length() == 0);
> }
>
> public String toString() {
> return value.toString();
> }
> }
>
> private static final int PRECEDENCE_NOT = 5;
> private static final int PRECEDENCE_COMPARE = 4;
> private static final int PRECEDENCE_LOGICAL = 1;
>
> /**
> * A node implementation that represents an operation.
> */
> private abstract class OppNode extends Node {
>
> /**
> * The left branch.
> */
> Node left;
>
> /**
> * The right branch.
> */
> Node right;
>
> /**
> * Returns a preference level suitable for comparison to
> * other OppNode preference levels.
> */
> public abstract int getPrecedence();
>
> /**
> * Lets the node pop its own branch nodes off the front of
> * the specified list. The default pulls two.
> */
> public void popValues( List values ) {
> right = (Node)values.remove(0);
> left = (Node)values.remove(0);
> }
> }
>
> private final class NotNode extends OppNode {
>
> public boolean evaluate() {
> return !left.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_NOT;
> }
>
> /**
> * Overridden to pop only one value.
> */
> public void popValues( List values ) {
> left = (Node)values.remove(0);
> }
>
> public String toString() {
> return left + " NOT";
> }
> }
>
> private final class AndNode extends OppNode {
>
> public boolean evaluate() {
> if (!left.evaluate()) // Short circuit
> return false;
> return right.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_LOGICAL;
> }
>
> public String toString() {
> return left + " " + right + " AND";
> }
> }
>
> private final class OrNode extends OppNode {
>
> public boolean evaluate() {
> if (left.evaluate()) // Short circuit
> return true;
> return right.evaluate();
> }
>
> public int getPrecedence() {
> return PRECEDENCE_LOGICAL;
> }
>
> public String toString() {
> return left + " " + right + " OR";
> }
> }
>
> private abstract class CompareNode extends OppNode {
> protected int compareBranches() {
> String val1 = ((StringNode)left).getValue();
> String val2 = ((StringNode)right).getValue();
> return val1.compareTo(val2);
> }
> }
>
> private final class EqualNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() == 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " EQ";
> }
> }
>
> private final class GreaterThanNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() > 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " GT";
> }
> }
>
> private final class LessThanNode extends CompareNode {
>
> public boolean evaluate() {
> return (compareBranches() < 0);
> }
>
> public int getPrecedence() {
> return PRECEDENCE_COMPARE;
> }
>
> public String toString() {
> return left + " " + right + " LT";
> }
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java
>
> Index: ExpressionTokenizer.java
> ===================================================================
> /*
> * ExpressionTokenizer.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> /**
> * Parses an expression string to return the individual tokens.
> * This is patterned similar to the StreamTokenizer in the JDK
> * but customized for SSI conditional expression parsing.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class ExpressionTokenizer {
>
> public static final int TOKEN_STRING = 0;
> public static final int TOKEN_AND = 1;
> public static final int TOKEN_OR = 2;
> public static final int TOKEN_NOT = 3;
> public static final int TOKEN_EQ = 4;
> public static final int TOKEN_NOT_EQ = 5;
> public static final int TOKEN_RBRACE = 6;
> public static final int TOKEN_LBRACE = 7;
> public static final int TOKEN_GE = 8;
> public static final int TOKEN_LE = 9;
> public static final int TOKEN_GT = 10;
> public static final int TOKEN_LT = 11;
> public static final int TOKEN_END = 12;
>
> private char[] expr;
> private int tokenType = TOKEN_STRING;
> private String tokenVal = null;
> private int index;
> private int length;
>
> /**
> * Creates a new parser for the specified expression.
> */
> public ExpressionTokenizer( String expr ) {
> this.expr = expr.trim().toCharArray();
> this.length = this.expr.length;
> }
>
> /**
> * Returns true if there are more tokens.
> */
> public boolean hasMoreTokens() {
> return index < length;
> }
>
> /**
> * Returns the current index for error reporting purposes.
> */
> public int getIndex() {
> return index;
> }
>
> protected boolean isMetaChar( char c ) {
> return Character.isWhitespace( c ) ||
> c == '(' || c == ')' || c == '!' ||
> c == '<' || c == '>' || c == '|' ||
> c == '&' || c == '=';
> }
>
> /**
> * Returns the next token type and initializes any
> * state variables accordingly.
> */
> public int nextToken() {
> // Skip any leading white space
> while (index<length && Character.isWhitespace(expr[index]))
> index++;
>
> // Clear the current token val
> tokenVal = null;
>
> if (index == length)
> return TOKEN_END; // End of string
>
> int start = index;
> char currentChar = expr[index];
> char nextChar = (char)0;
> index++;
> if (index < length)
> nextChar = expr[index];
>
> // Check for a known token start
> switch (currentChar) {
> case '(':
> return TOKEN_LBRACE;
> case ')':
> return TOKEN_RBRACE;
> case '=':
> return TOKEN_EQ;
> case '!':
> if (nextChar == '=') {
> index++;
> return TOKEN_NOT_EQ;
> } else {
> return TOKEN_NOT;
> }
> case '|':
> if (nextChar == '|') {
> index++;
> return TOKEN_OR;
> }
> break;
> case '&':
> if (nextChar == '&') {
> index++;
> return TOKEN_AND;
> }
> break;
> case '>':
> if (nextChar == '=') {
> index++;
> return TOKEN_GE; // Greater than or equal
> } else {
> return TOKEN_GT; // Greater than
> }
> case '<':
> if (nextChar == '=') {
> index++;
> return TOKEN_LE; // Less than or equal
> } else {
> return TOKEN_LT; // Less than
> }
> default:
> // Otherwise it's a string
> break;
> }
>
> int end = index;
>
> // If it's a quoted string then end is the next unescaped quote
> if (currentChar == '"' || currentChar == '\'') {
> char endChar = currentChar;
> boolean escaped = false;
> start++;
> for ( ; index < length; index++) {
> if (expr[index] == '\\' && !escaped) {
> escaped = true;
> continue;
> }
> if (expr[index] == endChar && !escaped)
> break;
>
> escaped = false;
> }
> end = index;
> index++; // Skip the end quote
> } else {
> // End is the next whitespace character
> for ( ; index < length; index++) {
> if ( isMetaChar(expr[index]) )
> break;
> }
> end = index;
> }
>
> // Extract the string from the array
> this.tokenVal = new String( expr, start, end - start );
>
> return TOKEN_STRING;
> }
>
> /**
> * Returns the String value of the token if it was type
> * TOKEN_STRING. Otherwise null is returned.
> */
> public String getTokenValue() {
> return tokenVal;
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
>
> Index: SSIConditional.java
> ===================================================================
> /*
> * SSIConditional.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> import java.io.PrintWriter;
> import java.text.ParseException;
> import java.util.LinkedList;
> import java.util.List;
>
> import javax.servlet.ServletOutputStream;
>
> /**
> * SSI command that handles all conditional directives.
> *
> * @version $Revision: 1.1 $
> * @author Paul Speed
> */
> public class SSIConditional implements SSICommand {
> /**
> * @see SSICommand
> */
> public void process( SSIMediator ssiMediator,
> String commandName,
> String[] paramNames,
> String[] paramValues,
> PrintWriter writer) throws SSIStopProcessingException {
>
> // Retrieve the current state information
> SSIConditionalState state = ssiMediator.getConditionalState();
>
> if ( "if".equalsIgnoreCase( commandName ) ) {
> // Do nothing if we are nested in a false branch
> // except count it
> if ( state.processConditionalCommandsOnly ) {
> state.nestingCount++;
> return;
> }
>
> state.nestingCount = 0;
>
> // Evaluate the expression
> if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
> // No more branches can be taken for this if block
> state.branchTaken = true;
> } else {
> // Do not process this branch
> state.processConditionalCommandsOnly = true;
> state.branchTaken = false;
> }
>
> } else if ( "elif".equalsIgnoreCase( commandName ) ) {
> // No need to even execute if we are nested in
> // a false branch
> if (state.nestingCount > 0)
> return;
>
> // If a branch was already taken in this if block
> // then disable output and return
> if ( state.branchTaken ) {
> state.processConditionalCommandsOnly = true;
> return;
> }
>
> // Evaluate the expression
> if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) {
> // Turn back on output and mark the branch
> state.processConditionalCommandsOnly = false;
> state.branchTaken = true;
> } else {
> // Do not process this branch
> state.processConditionalCommandsOnly = true;
> state.branchTaken = false;
> }
>
> } else if ( "else".equalsIgnoreCase( commandName ) ) {
> // No need to even execute if we are nested in
> // a false branch
> if (state.nestingCount > 0)
> return;
>
> // If we've already taken another branch then
> // disable output otherwise enable it.
> state.processConditionalCommandsOnly = state.branchTaken;
>
> // And in any case, it's safe to say a branch
> // has been taken.
> state.branchTaken = true;
>
> } else if ( "endif".equalsIgnoreCase( commandName ) ) {
> // If we are nested inside a false branch then pop out
> // one level on the nesting count
> if (state.nestingCount > 0) {
> state.nestingCount--;
> return;
> }
>
> // Turn output back on
> state.processConditionalCommandsOnly = false;
>
> // Reset the branch status for any outer if blocks,
> // since clearly we took a branch to have gotten here
> // in the first place.
> state.branchTaken = true;
> } else {
> throw new SSIStopProcessingException();
> //throw new SsiCommandException( "Not a conditional command:" + cmdName );
> }
> }
>
> /**
> * Retrieves the expression from the specified arguments
> * and peforms the necessary evaluation steps.
> */
> private boolean evaluateArguments( String[] names,
> String[] values,
> SSIMediator ssiMediator ) throws SSIStopProcessingException {
> String expr = getExpression( names, values );
> if (expr == null) {
> throw new SSIStopProcessingException();
> //throw new SsiCommandException( "No expression specified." );
> }
>
> try {
> ExpressionParseTree tree = new ExpressionParseTree( expr,
> ssiMediator );
> return tree.evaluateTree();
> } catch (ParseException e) {
> //throw new SsiCommandException( "Error parsing expression." );
> throw new SSIStopProcessingException();
> }
> }
>
> /**
> * Returns the "expr" if the arg name is appropriate, otherwise
> * returns null.
> */
> private String getExpression( String[] paramNames, String[] paramValues ) {
> if ( "expr".equalsIgnoreCase( paramNames[0]) )
> return paramValues[0];
> return null;
> }
> }
>
>
>
> 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java
>
> Index: SSIConditionalState.java
> ===================================================================
> /*
> * SSIConditionalState.java
> * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java,v 1.1 2002/11/25 10:15:42 dsandberg Exp $
> * $Revision: 1.1 $
> * $Date: 2002/11/25 10:15:42 $
> *
> * ====================================================================
> *
> * 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.catalina.ssi;
>
> /**
> * This class is used by SSIMediator and SSIConditional to keep track of state information necessary to process
> * the nested conditional commands ( if, elif, else, endif ).
> *
> * @version $Revision: 1.1 $
> * @author Dan Sandberg
> * @author Paul Speed
> */
> class SSIConditionalState {
> /**
> * Set to true if the current conditional has already been
> * completed, i.e.: a branch was taken.
> */
> boolean branchTaken = false;
>
> /**
> * Counts the number of nested false branches.
> */
> int nestingCount = 0;
>
> /**
> * Set to true if only conditional commands ( if, elif, else, endif ) should be processed.
> */
> boolean processConditionalCommandsOnly = false;
> }
>
>
>
> 1.85 +36 -0 jakarta-tomcat-4.0/tester/src/bin/tester.xml
>
> Index: tester.xml
> ===================================================================
> RCS file: /home/cvs/jakarta-tomcat-4.0/tester/src/bin/tester.xml,v
> retrieving revision 1.84
> retrieving revision 1.85
> diff -u -r1.84 -r1.85
> --- tester.xml 24 Nov 2002 06:22:36 -0000 1.84
> +++ tester.xml 25 Nov 2002 10:15:43 -0000 1.85
> @@ -1849,6 +1849,42 @@
> golden="${golden.path}/SSIFsize02.txt"/>
>
> <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional01.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional01.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional02.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional02.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional03.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional03.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional04.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional04.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional05.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional05.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional06.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional06.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional07.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional07.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional08.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional08.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> + request="${context.path}/SSIConditional09.shtml" debug="${debug}"
> + golden="${golden.path}/SSIConditional09.txt"/>
> +
> + <tester host="${host}" port="${port}" protocol="${protocol}"
> request="${context.path}/SSIVarSub01.shtml" debug="${debug}"
> golden="${golden.path}/SSIVarSub01.txt"/>
>
>
>
>
> 1.1 jakarta-tomcat-4.0/tester/web/SSIConditional09.shtml
>
> Index: SSIConditional09.shtml
> ===================================================================
> 1
> <!--#if expr="1=2" -->
> a
> ##<!--#if expr="1=2" -->
> b
> ##<!--#else -->
> c
> ##<!--#endif -->
> d
> <!--#elif expr="2=2" -->
> e
> ##<!--#if expr="2=2" -->
> f
> ####<!--#if expr="1=2" -->
> **11
> ####<!--#elif expr="2=3" -->
> **22
> ####<!--#endif -->
> **33
> ##<!--#else -->
> g
> ##<!--#endif -->
> h
> <!--#else -->
> i
> ##<!--#if expr="1=1" -->
> j
> ##<!--#else -->
> k
> ##<!--#endif -->
> l
> <!--#endif -->
> #
> now we test extra #endif commands
> <!--#endif -->
> n
> <!--#endif -->
> o
>
>
> 1.1 jakarta-tomcat-4.0/tester/web/golden/SSIConditional09.txt
>
> Index: SSIConditional09.txt
> ===================================================================
> 1
>
> e
> ##
> f
> ####
> **33
> ##
> h
>
> #
> now we test extra #endif commands
>
> n
>
> o
>
>
>
> --
> To unsubscribe, e-mail: <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>