markt 2005/04/23 03:22:37
Modified: catalina/src/conf web.xml
catalina/src/share/org/apache/catalina/ssi
ResponseIncludeWrapper.java SSICommand.java
SSIConditional.java SSIConfig.java SSIEcho.java
SSIExec.java SSIFlastmod.java SSIFsize.java
SSIInclude.java SSIMediator.java SSIPrintenv.java
SSIProcessor.java SSIServlet.java
SSIServletExternalResolver.java SSISet.java
webapps/docs changelog.xml ssi-howto.xml
Log:
Provide an ServletFilter implementation of Server Side Includes (SSI). This
was submitted by David Becker under bug
33106.
Revision Changes Path
1.57 +79 -0 jakarta-tomcat-catalina/catalina/src/conf/web.xml
Index: web.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/conf/web.xml,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -r1.56 -r1.57
--- web.xml 4 Apr 2005 20:57:02 -0000 1.56
+++ web.xml 23 Apr 2005 10:22:37 -0000 1.57
@@ -206,6 +206,9 @@
</servlet>
+ <!-- NOTE: An SSI Filter is also available as an alternative SSI
-->
+ <!-- implementation. Use either the Servlet or the Filter but NOT both.
-->
+ <!--
-->
<!-- Server Side Includes processing servlet, which processes SSI
-->
<!-- directives in HTML pages consistent with similar support in web
-->
<!-- servers like Apache. Traditionally, this servlet is mapped to the
-->
@@ -362,6 +365,78 @@
-->
+ <!-- ================== Built In Filter Definitions =====================
-->
+
+ <!-- NOTE: An SSI Servlet is also available as an alternative SSI
-->
+ <!-- implementation. Use either the Servlet or the Filter but NOT both.
-->
+ <!--
-->
+ <!-- Server Side Includes processing filter, which processes SSI
-->
+ <!-- directives in HTML pages consistent with similar support in web
-->
+ <!-- servers like Apache. Traditionally, this filter is mapped to the
-->
+ <!-- URL pattern "*.shtml", though it can be mapped to "*" as it will
-->
+ <!-- selectively enable/disable SSI processing based on mime types. The
-->
+ <!-- contentType init param allows you to apply SSI processing to JSP
-->
+ <!-- pages, javascript, or any other content you wish. This filter
-->
+ <!-- supports the following initialization parameters (default values are
-->
+ <!-- in square brackets):
-->
+ <!--
-->
+ <!-- contentType A regex pattern that must be matched before
-->
+ <!-- SSI processing is applied.
-->
+ <!-- [text/x-server-parsed-html(;.*)?]
-->
+ <!--
-->
+ <!-- debug Debugging detail level for messages logged
-->
+ <!-- by this servlet. [0]
-->
+ <!--
-->
+ <!-- expires The number of seconds before a page with SSI
-->
+ <!-- directives will expire. [No default]
-->
+ <!--
-->
+ <!-- isVirtualWebappRelative
-->
+ <!-- Should "virtual" paths be interpreted as
-->
+ <!-- relative to the context root, instead of
-->
+ <!-- the server root? (0=false, 1=true) [0]
-->
+ <!--
-->
+ <!--
-->
+ <!-- IMPORTANT: To use the SSI filter, you also need to rename the
-->
+ <!-- $CATALINA_HOME/server/lib/servlets-ssi.renametojar file
-->
+ <!-- to $CATALINA_HOME/server/lib/servlets-ssi.jar
-->
+
+<!--
+ <filter>
+ <filter-name>ssi</filter-name>
+ <filter-class>
+ org.apache.catalina.ssi.SSIFilter
+ </filter-class>
+ <init-param>
+ <param-name>contentType</param-name>
+ <param-value>text/x-server-parsed-html(;.*)?</param-value>
+ </init-param>
+ <init-param>
+ <param-name>debug</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ <init-param>
+ <param-name>expires</param-name>
+ <param-value>666</param-value>
+ </init-param>
+ <init-param>
+ <param-name>isVirtualWebappRelative</param-name>
+ <param-value>0</param-value>
+ </init-param>
+ </filter>
+-->
+
+
+ <!-- ==================== Built In Filter Mappings ======================
-->
+
+ <!-- The mapping for the SSI Filter -->
+<!--
+ <filter-mapping>
+ <filter-name>ssi</filter-name>
+ <url-pattern>*.shtml</url-pattern>
+ </filter-mapping>
+-->
+
+
<!-- ==================== Default Session Configuration =================
-->
<!-- You can set the default session timeout (in minutes) for all newly
-->
<!-- created sessions by modifying the value below.
-->
@@ -783,6 +858,10 @@
<mime-type>application/x-shar</mime-type>
</mime-mapping>
<mime-mapping>
+ <extension>shtml</extension>
+ <mime-type>text/x-server-parsed-html</mime-type>
+ </mime-mapping>
+ <mime-mapping>
<extension>smf</extension>
<mime-type>audio/x-midi</mime-type>
</mime-mapping>
1.6 +135 -8
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java
Index: ResponseIncludeWrapper.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ResponseIncludeWrapper.java 1 Sep 2004 18:33:33 -0000 1.5
+++ ResponseIncludeWrapper.java 23 Apr 2005 10:22:37 -0000 1.6
@@ -13,23 +13,40 @@
import java.io.IOException;
import java.io.PrintWriter;
+
+import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.catalina.util.DateTool;
/**
* A HttpServletResponseWrapper, used from
* <code>SSIServletExternalResolver</code>
*
* @author Bip Thelin
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class ResponseIncludeWrapper extends HttpServletResponseWrapper {
/**
+ * The names of some headers we want to capture.
+ */
+ private static final String CONTENT_TYPE = "content-type";
+ private static final String LAST_MODIFIED = "last-modified";
+ protected long lastModified = -1;
+ private String contentType = null;
+
+ /**
* Our ServletOutputStream
*/
- protected ServletOutputStream originalServletOutputStream;
+ protected ServletOutputStream captureServletOutputStream;
protected ServletOutputStream servletOutputStream;
protected PrintWriter printWriter;
+
+ private ServletContext context;
+ private HttpServletRequest request;
/**
@@ -41,10 +58,13 @@
* @param out
* The ServletOutputStream' to use
*/
- public ResponseIncludeWrapper(HttpServletResponse res,
- ServletOutputStream originalServletOutputStream) {
- super(res);
- this.originalServletOutputStream = originalServletOutputStream;
+ public ResponseIncludeWrapper(ServletContext context,
+ HttpServletRequest request, HttpServletResponse response,
+ ServletOutputStream captureServletOutputStream) {
+ super(response);
+ this.context = context;
+ this.request = request;
+ this.captureServletOutputStream = captureServletOutputStream;
}
@@ -74,7 +94,7 @@
public PrintWriter getWriter() throws java.io.IOException {
if (servletOutputStream == null) {
if (printWriter == null) {
- printWriter = new PrintWriter(originalServletOutputStream);
+ printWriter = new PrintWriter(captureServletOutputStream);
}
return printWriter;
}
@@ -93,10 +113,117 @@
public ServletOutputStream getOutputStream() throws java.io.IOException {
if (printWriter == null) {
if (servletOutputStream == null) {
- servletOutputStream = originalServletOutputStream;
+ servletOutputStream = captureServletOutputStream;
}
return servletOutputStream;
}
throw new IllegalStateException();
}
+
+
+ /**
+ * Returns the value of the <code>last-modified</code> header field. The
+ * result is the number of milliseconds since January 1, 1970 GMT.
+ *
+ * @return the date the resource referenced by this
+ * <code>ResponseIncludeWrapper</code> was last modified, or -1 if not
+ * known.
+ */
+ public long getLastModified() {
+ if (lastModified == -1) {
+ // javadocs say to return -1 if date not known, if you want
another
+ // default, put it here
+ return -1;
+ }
+ return lastModified;
+ }
+
+ /**
+ * Sets the value of the <code>last-modified</code> header field.
+ *
+ * @param value The number of milliseconds since January 1, 1970 GMT.
+ */
+ public void setLastModified(long lastModified) {
+ this.lastModified = lastModified;
+ ((HttpServletResponse) getResponse()).setDateHeader(LAST_MODIFIED,
+ lastModified);
+ }
+
+ /**
+ * Returns the value of the <code>content-type</code> header field.
+ *
+ * @return the content type of the resource referenced by this
+ * <code>ResponseIncludeWrapper</code>, or <code>null</code> if not
known.
+ */
+ public String getContentType() {
+ if (contentType == null) {
+ String url = request.getRequestURI();
+ String mime = context.getMimeType(url);
+ if (mime != null)
+ {
+ setContentType(mime);
+ }
+ else
+ {
+ // return a safe value
+ setContentType("application/x-octet-stream");
+ }
+ }
+ return contentType;
+ }
+
+ /**
+ * Sets the value of the <code>content-type</code> header field.
+ *
+ * @param mime a mime type
+ */
+ public void setContentType(String mime) {
+ contentType = mime;
+ if (contentType != null) {
+ getResponse().setContentType(contentType);
+ }
+ }
+
+
+ public void addDateHeader(String name, long value) {
+ super.addDateHeader(name, value);
+ String lname = name.toLowerCase();
+ if (lname.equals(LAST_MODIFIED)) {
+ lastModified = value;
+ }
+ }
+
+ public void addHeader(String name, String value) {
+ super.addHeader(name, value);
+ String lname = name.toLowerCase();
+ if (lname.equals(LAST_MODIFIED)) {
+ try {
+ lastModified = DateTool.rfc1123Format.parse(value).getTime();
+ } catch (Throwable ignore) { }
+ } else if (lname.equals(CONTENT_TYPE)) {
+ contentType = value;
+ }
+ }
+
+ public void setDateHeader(String name, long value) {
+ super.setDateHeader(name, value);
+ String lname = name.toLowerCase();
+ if (lname.equals(LAST_MODIFIED)) {
+ lastModified = value;
+ }
+ }
+
+ public void setHeader(String name, String value) {
+ super.setHeader(name, value);
+ String lname = name.toLowerCase();
+ if (lname.equals(LAST_MODIFIED)) {
+ try {
+ lastModified = DateTool.rfc1123Format.parse(value).getTime();
+ } catch (Throwable ignore) { }
+ }
+ else if (lname.equals(CONTENT_TYPE))
+ {
+ contentType = value;
+ }
+ }
}
\ No newline at end of file
1.5 +4 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
Index: SSICommand.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSICommand.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSICommand.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSICommand.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -18,6 +18,7 @@
*
* @author Bip Thelin
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public interface SSICommand {
@@ -34,10 +35,11 @@
* The parameter values
* @param writer
* the writer to output to
+ * @return the most current modified date resulting from any SSI commands
* @throws SSIStopProcessingException
* if SSI processing should be aborted
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer)
throws SSIStopProcessingException;
}
\ No newline at end of file
1.3 +11 -7
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
Index: SSIConditional.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SSIConditional.java 1 Sep 2004 18:33:33 -0000 1.2
+++ SSIConditional.java 23 Apr 2005 10:22:37 -0000 1.3
@@ -18,14 +18,17 @@
*
* @version $Revision$
* @author Paul Speed
+ * @author David Becker
*/
public class SSIConditional implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer)
throws SSIStopProcessingException {
+ // Assume anything using conditionals was modified by it
+ long lastModified = System.currentTimeMillis();
// Retrieve the current state information
SSIConditionalState state = ssiMediator.getConditionalState();
if ("if".equalsIgnoreCase(commandName)) {
@@ -33,7 +36,7 @@
// except count it
if (state.processConditionalCommandsOnly) {
state.nestingCount++;
- return;
+ return lastModified;
}
state.nestingCount = 0;
// Evaluate the expression
@@ -48,12 +51,12 @@
} else if ("elif".equalsIgnoreCase(commandName)) {
// No need to even execute if we are nested in
// a false branch
- if (state.nestingCount > 0) return;
+ if (state.nestingCount > 0) return lastModified;
// If a branch was already taken in this if block
// then disable output and return
if (state.branchTaken) {
state.processConditionalCommandsOnly = true;
- return;
+ return lastModified;
}
// Evaluate the expression
if (evaluateArguments(paramNames, paramValues, ssiMediator)) {
@@ -68,7 +71,7 @@
} else if ("else".equalsIgnoreCase(commandName)) {
// No need to even execute if we are nested in
// a false branch
- if (state.nestingCount > 0) return;
+ if (state.nestingCount > 0) return lastModified;
// If we've already taken another branch then
// disable output otherwise enable it.
state.processConditionalCommandsOnly = state.branchTaken;
@@ -80,7 +83,7 @@
// one level on the nesting count
if (state.nestingCount > 0) {
state.nestingCount--;
- return;
+ return lastModified;
}
// Turn output back on
state.processConditionalCommandsOnly = false;
@@ -93,6 +96,7 @@
//throw new SsiCommandException( "Not a conditional command:" +
// cmdName );
}
+ return lastModified;
}
1.5 +5 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
Index: SSIConfig.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIConfig.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIConfig.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -18,13 +18,14 @@
* @author Bip Thelin
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public final class SSIConfig implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
for (int i = 0; i < paramNames.length; i++) {
String paramName = paramNames[i];
@@ -46,5 +47,7 @@
writer.write(configErrMsg);
}
}
+ // Setting config options doesn't really change the page
+ return 0;
}
}
\ No newline at end of file
1.4 +6 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
Index: SSIEcho.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SSIEcho.java 1 Sep 2004 18:33:33 -0000 1.3
+++ SSIEcho.java 23 Apr 2005 10:22:37 -0000 1.4
@@ -18,6 +18,7 @@
* @author Bip Thelin
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIEcho implements SSICommand {
@@ -28,8 +29,9 @@
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
String encoding = DEFAULT_ENCODING;
String errorMessage = ssiMediator.getConfigErrMsg();
for (int i = 0; i < paramNames.length; i++) {
@@ -42,6 +44,7 @@
variableValue = MISSING_VARIABLE_VALUE;
}
writer.write(variableValue);
+ lastModified = System.currentTimeMillis();
} else if (paramName.equalsIgnoreCase("encoding")) {
if (isValidEncoding(paramValue)) {
encoding = paramValue;
@@ -54,6 +57,7 @@
writer.write(errorMessage);
}
}
+ return lastModified;
}
1.5 +9 -5
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
Index: SSIExec.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIExec.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIExec.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIExec.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -23,6 +23,7 @@
* @author Amy Roh
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIExec implements SSICommand {
@@ -33,16 +34,17 @@
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
String configErrMsg = ssiMediator.getConfigErrMsg();
String paramName = paramNames[0];
String paramValue = paramValues[0];
String substitutedValue =
ssiMediator.substituteVariables(paramValue);
if (paramName.equalsIgnoreCase("cgi")) {
- ssiInclude.process(ssiMediator, "include",
- new String[]{"virtual"}, new String[]{substitutedValue},
- writer);
+ lastModified = ssiInclude.process(ssiMediator, "include",
+ new String[]{"virtual"}, new
String[]{substitutedValue},
+ writer);
} else if (paramName.equalsIgnoreCase("cmd")) {
boolean foundProgram = false;
try {
@@ -57,6 +59,7 @@
IOTools.flow(stdErrReader, writer, buf);
IOTools.flow(stdOutReader, writer, buf);
proc.waitFor();
+ lastModified = System.currentTimeMillis();
} catch (InterruptedException e) {
ssiMediator.log("Couldn't exec file: " + substitutedValue,
e);
writer.write(configErrMsg);
@@ -68,5 +71,6 @@
ssiMediator.log("Couldn't exec file: " + substitutedValue,
e);
}
}
+ return lastModified;
}
}
\ No newline at end of file
1.5 +6 -3
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
Index: SSIFlastmod.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIFlastmod.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIFlastmod.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -22,14 +22,16 @@
* @author Bip Thelin
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public final class SSIFlastmod implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
String configErrMsg = ssiMediator.getConfigErrMsg();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < paramNames.length; i++) {
@@ -41,7 +43,7 @@
if (paramName.equalsIgnoreCase("file")
|| paramName.equalsIgnoreCase("virtual")) {
boolean virtual = paramName.equalsIgnoreCase("virtual");
- long lastModified = ssiMediator.getFileLastModified(
+ lastModified = ssiMediator.getFileLastModified(
substitutedValue, virtual);
Date date = new Date(lastModified);
String configTimeFmt = ssiMediator.getConfigTimeFmt();
@@ -58,6 +60,7 @@
writer.write(configErrMsg);
}
}
+ return lastModified;
}
1.4 +7 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
Index: SSIFsize.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/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 1 Sep 2004 18:33:33 -0000 1.3
+++ SSIFsize.java 23 Apr 2005 10:22:37 -0000 1.4
@@ -20,6 +20,7 @@
* @author Bip Thelin
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public final class SSIFsize implements SSICommand {
@@ -30,8 +31,9 @@
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
String configErrMsg = ssiMediator.getConfigErrMsg();
for (int i = 0; i < paramNames.length; i++) {
String paramName = paramNames[i];
@@ -42,6 +44,8 @@
if (paramName.equalsIgnoreCase("file")
|| paramName.equalsIgnoreCase("virtual")) {
boolean virtual = paramName.equalsIgnoreCase("virtual");
+ lastModified = ssiMediator.getFileLastModified(
+ substitutedValue, virtual);
long size = ssiMediator.getFileSize(substitutedValue,
virtual);
String configSizeFmt = ssiMediator.getConfigSizeFmt();
@@ -56,6 +60,7 @@
writer.write(configErrMsg);
}
}
+ return lastModified;
}
1.5 +7 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
Index: SSIInclude.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIInclude.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIInclude.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -19,14 +19,16 @@
* @author Bip Thelin
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public final class SSIInclude implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
String configErrMsg = ssiMediator.getConfigErrMsg();
for (int i = 0; i < paramNames.length; i++) {
String paramName = paramNames[i];
@@ -37,6 +39,8 @@
if (paramName.equalsIgnoreCase("file")
|| paramName.equalsIgnoreCase("virtual")) {
boolean virtual = paramName.equalsIgnoreCase("virtual");
+ lastModified = ssiMediator.getFileLastModified(
+ substitutedValue, virtual);
String text = ssiMediator.getFileText(substitutedValue,
virtual);
writer.write(text);
@@ -51,5 +55,6 @@
writer.write(configErrMsg);
}
}
+ return lastModified;
}
}
\ No newline at end of file
1.5 +5 -4
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
Index: SSIMediator.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIMediator.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIMediator.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -29,6 +29,7 @@
* @author Amy Roh
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIMediator {
@@ -41,7 +42,7 @@
protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT;
protected String className = getClass().getName();
protected SSIExternalResolver ssiExternalResolver;
- protected Date lastModifiedDate;
+ protected long lastModifiedDate;
protected int debug;
protected Strftime strftime;
protected SSIConditionalState conditionalState = new
SSIConditionalState();
@@ -64,7 +65,7 @@
public SSIMediator(SSIExternalResolver ssiExternalResolver,
- Date lastModifiedDate, int debug) {
+ long lastModifiedDate, int debug) {
this.ssiExternalResolver = ssiExternalResolver;
this.lastModifiedDate = lastModifiedDate;
this.debug = debug;
@@ -315,7 +316,7 @@
setVariableValue("DATE_LOCAL", null);
ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL",
retVal);
- retVal = formatDate(lastModifiedDate, null);
+ retVal = formatDate(new Date(lastModifiedDate), null);
setVariableValue("LAST_MODIFIED", null);
ssiExternalResolver.setVariableValue(className +
".LAST_MODIFIED",
retVal);
1.4 +7 -3
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
Index: SSIPrintenv.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SSIPrintenv.java 1 Sep 2004 18:33:33 -0000 1.3
+++ SSIPrintenv.java 23 Apr 2005 10:22:37 -0000 1.4
@@ -18,14 +18,16 @@
* Implements the Server-side #printenv command
*
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIPrintenv implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer) {
+ long lastModified = 0;
//any arguments should produce an error
if (paramNames.length > 0) {
String errorMessage = ssiMediator.getConfigErrMsg();
@@ -46,7 +48,9 @@
writer.write('=');
writer.write(variableValue);
writer.write('\n');
+ lastModified = System.currentTimeMillis();
}
}
+ return lastModified;
}
-}
\ No newline at end of file
+}
1.5 +10 -5
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
Index: SSIProcessor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SSIProcessor.java 1 Sep 2004 18:33:33 -0000 1.4
+++ SSIProcessor.java 23 Apr 2005 10:22:37 -0000 1.5
@@ -15,7 +15,6 @@
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
-import java.util.Date;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.apache.catalina.util.IOTools;
@@ -25,6 +24,7 @@
* necessary[
*
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIProcessor {
@@ -76,11 +76,12 @@
* the reader to read the file containing SSIs from
* @param writer
* the writer to write the file with the SSIs processed.
+ * @return the most current modified date resulting from any SSI commands
* @throws IOException
* when things go horribly awry. Should be unlikely since the
* SSICommand usually catches 'normal' IOExceptions.
*/
- public void process(Reader reader, Date lastModifiedDate,
+ public long process(Reader reader, long lastModifiedDate,
PrintWriter writer) throws IOException {
SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver,
lastModifiedDate, debug);
@@ -142,8 +143,11 @@
// command is not conditional
if
(!ssiMediator.getConditionalState().processConditionalCommandsOnly
|| ssiCommand instanceof SSIConditional)
{
- ssiCommand.process(ssiMediator, strCmd,
- paramNames, paramValues, writer);
+ long lmd = ssiCommand.process(ssiMediator,
strCmd,
+ paramNames, paramValues,
writer);
+ if (lmd > lastModifiedDate) {
+ lastModifiedDate = lmd;
+ }
}
}
if (errorMessage != null) {
@@ -160,6 +164,7 @@
//If we are here, then we have already stopped processing, so all
// is good
}
+ return lastModifiedDate;
}
1.10 +10 -6
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java
Index: SSIServlet.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- SSIServlet.java 4 Apr 2005 20:57:02 -0000 1.9
+++ SSIServlet.java 23 Apr 2005 10:22:37 -0000 1.10
@@ -19,7 +19,6 @@
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
-import java.util.Date;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -33,6 +32,7 @@
* @author Bip Thelin
* @author Amy Roh
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIServlet extends HttpServlet {
@@ -190,8 +190,9 @@
protected void processSSI(HttpServletRequest req, HttpServletResponse
res,
URL resource) throws IOException {
- SSIExternalResolver ssiExternalResolver = new
SSIServletExternalResolver(
- this, req, res, isVirtualWebappRelative, debug,
inputEncoding);
+ SSIExternalResolver ssiExternalResolver =
+ new SSIServletExternalResolver(getServletContext(), req, res,
+ isVirtualWebappRelative, debug, inputEncoding);
SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver,
debug);
PrintWriter printWriter = null;
@@ -217,8 +218,11 @@
}
BufferedReader bufferedReader = new BufferedReader(isr);
- Date lastModifiedDate = new Date(resourceInfo.getLastModified());
- ssiProcessor.process(bufferedReader, lastModifiedDate, printWriter);
+ long lastModified = ssiProcessor.process(bufferedReader,
+ resourceInfo.getLastModified(), printWriter);
+ if (lastModified > 0) {
+ res.setDateHeader("last-modified", lastModified);
+ }
if (buffered) {
printWriter.flush();
String text = stringWriter.toString();
1.6 +54 -25
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java
Index: SSIServletExternalResolver.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- SSIServletExternalResolver.java 4 Apr 2005 20:57:02 -0000 1.5
+++ SSIServletExternalResolver.java 23 Apr 2005 10:22:37 -0000 1.6
@@ -12,6 +12,7 @@
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
@@ -21,13 +22,15 @@
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.connector.Request;
+
/**
* An implementation of SSIExternalResolver that is used with servlets.
*
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSIServletExternalResolver implements SSIExternalResolver {
@@ -37,17 +40,17 @@
"QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR",
"REMOTE_HOST", "REMOTE_USER", "REQUEST_METHOD", "SCRIPT_NAME",
"SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL",
"SERVER_SOFTWARE"};
- protected HttpServlet servlet;
+ protected ServletContext context;
protected HttpServletRequest req;
protected HttpServletResponse res;
protected boolean isVirtualWebappRelative;
protected int debug;
protected String inputEncoding;
- public SSIServletExternalResolver(HttpServlet servlet,
+ public SSIServletExternalResolver(ServletContext context,
HttpServletRequest req, HttpServletResponse res,
boolean isVirtualWebappRelative, int debug, String
inputEncoding) {
- this.servlet = servlet;
+ this.context = context;
this.req = req;
this.res = res;
this.isVirtualWebappRelative = isVirtualWebappRelative;
@@ -61,9 +64,9 @@
//is the same as Servlet.log( message ), since API
//doesn't seem to say so.
if (throwable != null) {
- servlet.log(message, throwable);
+ context.log(message, throwable);
} else {
- servlet.log(message);
+ context.log(message);
}
}
@@ -161,7 +164,35 @@
} else if (name.equalsIgnoreCase("QUERY_STRING_UNESCAPED")) {
String queryString = req.getQueryString();
if (queryString != null) {
- retVal = URLDecoder.decode(queryString);
+ // Use default as a last resort
+ String queryStringEncoding =
+ org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+
+ String uriEncoding = null;
+ boolean useBodyEncodingForURI = false;
+
+ // Get encoding settings from request / connector if possible
+ String requestEncoding = req.getCharacterEncoding();
+ if (req instanceof Request) {
+ uriEncoding =
((Request)req).getConnector().getURIEncoding();
+ useBodyEncodingForURI =
+
((Request)req).getConnector().getUseBodyEncodingForURI();
+ }
+
+ // If valid, apply settings from request / connector
+ if (uriEncoding != null) {
+ queryStringEncoding = uriEncoding;
+ } else if(useBodyEncodingForURI) {
+ if (requestEncoding != null) {
+ queryStringEncoding = requestEncoding;
+ }
+ }
+
+ try {
+ retVal = URLDecoder.decode(queryString,
queryStringEncoding);
+ } catch (UnsupportedEncodingException e) {
+ retVal = queryString;
+ }
}
} else if (name.equalsIgnoreCase("REMOTE_ADDR")) {
retVal = req.getRemoteAddr();
@@ -180,8 +211,7 @@
} else if (name.equalsIgnoreCase("SERVER_PROTOCOL")) {
retVal = req.getProtocol();
} else if (name.equalsIgnoreCase("SERVER_SOFTWARE")) {
- ServletContext servletContext = servlet.getServletContext();
- retVal = servletContext.getServerInfo();
+ retVal = context.getServerInfo();
}
return retVal;
}
@@ -251,26 +281,24 @@
+ nonVirtualPath);
}
String path = getAbsolutePath(nonVirtualPath);
- ServletContext servletContext = servlet.getServletContext();
ServletContextAndPath csAndP = new ServletContextAndPath(
- servletContext, path);
+ context, path);
return csAndP;
}
protected ServletContextAndPath getServletContextAndPathFromVirtualPath(
String virtualPath) throws IOException {
- ServletContext servletContext = servlet.getServletContext();
String path = null;
if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) {
- path = getAbsolutePath(virtualPath);
+ return new ServletContextAndPath(context,
getAbsolutePath(virtualPath));
} else {
String normalized = SSIServletRequestUtil.normalize(virtualPath);
if (isVirtualWebappRelative) {
- path = normalized;
+ return new ServletContextAndPath(context, normalized);
} else {
- servletContext = servletContext.getContext(normalized);
- if (servletContext == null) {
+ ServletContext normContext = context.getContext(normalized);
+ if (normContext == null) {
throw new IOException("Couldn't get context for path: "
+ normalized);
}
@@ -278,19 +306,19 @@
// to remove,
// ie:
// '/file1.shtml' vs '/appName1/file1.shtml'
- if (!isRootContext(servletContext)) {
- path = getPathWithoutContext(normalized);
- if (path == null) {
+ if (!isRootContext(normContext)) {
+ String noContext = getPathWithoutContext(normalized);
+ if (noContext == null) {
throw new IOException(
"Couldn't remove context from path: "
+ normalized);
}
+ return new ServletContextAndPath(normContext, noContext);
} else {
- path = normalized;
+ return new ServletContextAndPath(normContext,
normalized);
}
}
}
- return new ServletContextAndPath(servletContext, path);
}
@@ -370,9 +398,10 @@
throw new IOException(
"Couldn't get request dispatcher for path: " + path);
}
- ByteArrayServletOutputStream basos = new
ByteArrayServletOutputStream();
- ResponseIncludeWrapper responseIncludeWrapper = new
ResponseIncludeWrapper(
- res, basos);
+ ByteArrayServletOutputStream basos =
+ new ByteArrayServletOutputStream();
+ ResponseIncludeWrapper responseIncludeWrapper =
+ new ResponseIncludeWrapper(context, req, res, basos);
rd.include(req, responseIncludeWrapper);
//We can't assume the included servlet flushed its output
responseIncludeWrapper.flushOutputStreamOrWriter();
1.4 +6 -2
jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSISet.java
Index: SSISet.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/ssi/SSISet.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- SSISet.java 1 Sep 2004 18:33:33 -0000 1.3
+++ SSISet.java 23 Apr 2005 10:22:37 -0000 1.4
@@ -17,15 +17,17 @@
*
* @author Paul Speed
* @author Dan Sandberg
+ * @author David Becker
* @version $Revision$, $Date$
*/
public class SSISet implements SSICommand {
/**
* @see SSICommand
*/
- public void process(SSIMediator ssiMediator, String commandName,
+ public long process(SSIMediator ssiMediator, String commandName,
String[] paramNames, String[] paramValues, PrintWriter writer)
throws SSIStopProcessingException {
+ long lastModified = 0;
String errorMessage = ssiMediator.getConfigErrMsg();
String variableName = null;
for (int i = 0; i < paramNames.length; i++) {
@@ -39,6 +41,7 @@
.substituteVariables(paramValue);
ssiMediator.setVariableValue(variableName,
substitutedValue);
+ lastModified = System.currentTimeMillis();
} else {
ssiMediator.log("#set--no variable specified");
writer.write(errorMessage);
@@ -50,5 +53,6 @@
throw new SSIStopProcessingException();
}
}
+ return lastModified;
}
}
\ No newline at end of file
1.292 +4 -0 jakarta-tomcat-catalina/webapps/docs/changelog.xml
Index: changelog.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/webapps/docs/changelog.xml,v
retrieving revision 1.291
retrieving revision 1.292
diff -u -r1.291 -r1.292
--- changelog.xml 22 Apr 2005 20:38:38 -0000 1.291
+++ changelog.xml 23 Apr 2005 10:22:37 -0000 1.292
@@ -99,6 +99,10 @@
Remove CopyParentClassLoader rule, which doesn't seem to be doing
anything useful
anymore. (remm)
</fix>
+ <add>
+ Provide an ServletFilter implementation of Server Side Includes
(SSI). This was
+ submitted by David Becker under <bug>33106</bug>. (markt)
+ </add>
</changelog>
</subsection>
1.4 +41 -4 jakarta-tomcat-catalina/webapps/docs/ssi-howto.xml
Index: ssi-howto.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat-catalina/webapps/docs/ssi-howto.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ssi-howto.xml 4 Apr 2005 20:57:02 -0000 1.3
+++ ssi-howto.xml 23 Apr 2005 10:22:37 -0000 1.4
@@ -29,10 +29,19 @@
<a href="http://httpd.apache.org/docs/howto/ssi.html#basicssidirectives">
Apache Introduction to SSI</a> for information on using SSI directives.</p>
-<p>SSI support is implemented using the servlet class
+<p>SSI support is available as a servlet and as a filter. You should use one
+or the other to provide SSI support but not both.</p>
+
+<p>Servlet based SSI support is implemented using the class
<code>org.apache.catalina.ssi.SSIServlet</code>. Traditionally, this servlet
is mapped to the URL pattern "*.shtml".</p>
+<p>Filter based SSI support is implemented using the class
+<code>org.apache.catalina.ssi.SSIFilter</code>. Traditionally, this filter
+is mapped to the URL pattern "*.shtml", though it can be mapped to "*" as
+it will selectively enable/disable SSI processing based on mime types. The
+contentType init param allows you to apply SSI processing to JSP pages,
+javascript, or any other content you wish.</p>
<p>By default SSI support is disabled in Tomcat.</p>
</section>
@@ -46,11 +55,17 @@
<p>Rename <code>$CATALINA_BASE/server/lib/servlets-ssi.renametojar</code>
to <code>$CATALINA_BASE/server/lib/servlets-ssi.jar</code>.</p>
-<p>Remove the XML comments from around the SSI servlet and servlet-mapping
-configuration in <code>$CATALINA_BASE/conf/web.xml</code>.</p>
+<p>To use the SSI servlet, remove the XML comments from around the SSI
servlet
+and servlet-mapping configuration in
+<code>$CATALINA_BASE/conf/web.xml</code>.</p>
+
+<p>To use the SSI filter, remove the XML comments from around the SSI filter
+and filter-mapping configuration in
+<code>$CATALINA_BASE/conf/web.xml</code>.</p>
+
</section>
-<section name="Configuration">
+<section name="Servlet Configuration">
<p>There are several servlet init parameters which can be used to
configure the behaviour of the SSI servlet.
@@ -75,6 +90,28 @@
</section>
+<section name="Filter Configuration">
+
+<p>There are several filter init parameters which can be used to
+configure the behaviour of the SSI filter.
+<ul>
+<li><strong>contentType</strong> - A regex pattern that must be matched
before
+SSI processing is applied. When crafting your own pattern, don't forget that
a
+mime content type may be followed by an optional character set in the form
+"mime/type; charset=set" that you must take into account. Default is
+"text/x-server-parsed-html(;.*)?".</li>
+<li><strong>debug</strong> - Debugging detail level for messages logged
+by this servlet. Default 0.</li>
+<li><strong>expires</strong> - The number of seconds before a page with SSI
+directives will expire. Default behaviour is for all SSI directives to be
+evaluated for every request.</li>
+<li><strong>isVirtualWebappRelative</strong> - Should "virtual" SSI directive
+paths be interpreted as relative to the context root, instead of the server
+root? (0=false, 1=true) Default 0 (false).</li>
+</ul>
+</p>
+
+</section>
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]