// ErrorFilter.java
// $Id: ErrorFilter.java,v 1.19 2002/10/29 14:42:57 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.jigsaw.filters;
import org.w3c.tools.resources.Attribute;
import org.w3c.tools.resources.AttributeRegistry;
import org.w3c.tools.resources.FilterInterface;
import org.w3c.tools.resources.FramedResource;
import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.ReplyInterface;
import org.w3c.tools.resources.RequestInterface;
import org.w3c.tools.resources.Resource;
import org.w3c.tools.resources.ResourceFilter;
import org.w3c.tools.resources.ServerInterface;
import org.w3c.tools.resources.StringAttribute;
import org.w3c.jigsaw.http.Reply;
import org.w3c.jigsaw.http.Request;
import org.w3c.www.http.HTTP;
import org.w3c.www.http.HeaderValue;
import org.w3c.www.http.HttpMessage;
import org.w3c.www.http.HttpReplyMessage;
import org.w3c.www.http.HttpRequestMessage;
/**
* The ErroFilter class allows you to customize and enhance error messages.
* This filter will catch all errors on their way back to the client, and
* use internal requests to provide a nice customizable error message.
* <p>You can use any resources (including server side includes, content
* negotiated resources, etc) to deliver error messages.
*/
public class ErrorFilter extends ResourceFilter {
/**
* A request state, to avoid looping on errors about errors.
*/
protected static final String ERRED = "org.w3c.jigsaw.filters.ErrorFilter";
/**
* Attribute index - The base URL for error messages.
*/
protected static int ATTR_BASEURL = -1;
/**
* Attribute index - The common extension for error messages (can be null).
*/
protected static int ATTR_EXTENSION = -1;
static {
Attribute a = null;
Class cls = null;
try {
cls = Class.forName("org.w3c.jigsaw.filters.ErrorFilter");
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
// Declare the error base URL attribute:
a = new StringAttribute("base-url"
, "/errors"
, Attribute.EDITABLE);
ATTR_BASEURL = AttributeRegistry.registerAttribute(cls, a);
// Declare the extension attribute:
a = new StringAttribute("extension"
, "html"
, Attribute.EDITABLE);
ATTR_EXTENSION = AttributeRegistry.registerAttribute(cls, a);
}
/**
* Get the base URL describing the error directory.
* @return The base URL.
*/
public String getBaseURL() {
return (String) getValue(ATTR_BASEURL, null);
}
/**
* Get the value of the extension attribute.
* @return A String, for the common extension to error messages, or
* <strong>null</strong> if undefined.
*/
public String getExtension() {
return (String) getValue(ATTR_EXTENSION, null);
}
/**
* Compute the path for the given status code.
* @return A path leading to the customizable error message for the
* given status code.
*/
public String getErrorResource(int status) {
String ext = getExtension() ;
if ( ext != null ) {
return getBaseURL()+"/"+Integer.toString(status)+"."+ext;
} else {
return getBaseURL()+"/"+Integer.toString(status);
}
}
/**
* This one just makes sure the outgoing filter gets called.
* @param request The original request to be handled.
* @exception ProtocolException If processing should be interrupted,
* because an abnormal situation occured.
*/
public ReplyInterface ingoingFilter(RequestInterface request)
throws ProtocolException
{
return null;
}
/**
* Re-compute error message.
* This filter uses internal redirection to get the error message body.
* In case of failure, the original reply is returned, otherwise, a new
* reply is gotten from the appropriate error resource, and is returned.
* @param request The request that has been handled.
* @param reply The reply, as emited by the original resource.
* @return A new error reply, having the same status code, and
* authentication information then the given reply, but enhanced
* with the error resource body.
* @exception ProtocolException If processing should be interrupted,
* because an abnormal situation occured.
*/
public ReplyInterface outgoingFilter(RequestInterface req,
ReplyInterface rep)
throws ProtocolException
{
Request request = (Request) req;
Reply reply = (Reply) rep;
// Filter valid replies:
int status = reply.getStatus();
switch (status/100) {
case 1:
case 2:
case 3:
case 10:
return null;
}
// Filter replies that are already taken care of:
if ( request.hasState(ERRED) )
return null;
// Hack error replies:
Request ereq = (Request) request.getClone();
Reply erep = null;
try {
ereq.setState(ERRED, Boolean.TRUE);
ereq.setURLPath(getErrorResource(status));
if (request.getMethod().equals(HTTP.HEAD)) {
ereq.setMethod(HTTP.HEAD);
} else {
ereq.setMethod(HTTP.GET);
}
// remove conditional statements
ereq.setIfModifiedSince(-1);
ereq.setIfUnmodifiedSince(-1);
ereq.setIfMatch(null);
ereq.setIfNoneMatch(null);
if (ereq.getIfRange() != null) {
ereq.setIfRange(null);
}
ereq.setCacheControl(null);
erep = (Reply) getServer().perform(ereq);
// Hack back the original reply into the new reply:
// - Put back the status
HeaderValue v = null;
erep.setStatus(reply.getStatus());
// - Put back the authenticate informations
v = reply.getHeaderValue(reply.H_WWW_AUTHENTICATE);
erep.setHeaderValue(reply.H_WWW_AUTHENTICATE, v);
// - Put back the proxy authenticate informations
v = reply.getHeaderValue(reply.H_PROXY_AUTHENTICATE);
erep.setHeaderValue(reply.H_PROXY_AUTHENTICATE, v);
} catch (Exception ex) {
return reply;
}
return erep;
}
/**
* We do catch exceptions, just in case we can customize the error.
* @param request The request tha triggered the exception.
* @param ex The exception.
* @param filters Remaining filters to be called.
* @param idx Current filter index within above array.
*/
public ReplyInterface exceptionFilter(RequestInterface request,
ProtocolException ex,
FilterInterface filters[],
int idx)
{
Reply reply = (Reply) ex.getReply();
if ( reply != null ) {
try {
return outgoingFilter(request, reply, filters, idx);
} catch (ProtocolException exx) {
}
}
return null;
}
public void initialize(Object values[]) {
super.initialize(values);
}
}