net.lightbody.bmp.proxy.jetty.http.HttpContext Maven / Gradle / Ivy
// ========================================================================
// $Id: HttpContext.java,v 1.136 2006/02/21 09:47:43 gregwilkins Exp $
// Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package net.lightbody.bmp.proxy.jetty.http;
import net.lightbody.bmp.proxy.jetty.http.ResourceCache.ResourceMetaData;
import net.lightbody.bmp.proxy.jetty.http.handler.ErrorPageHandler;
import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import net.lightbody.bmp.proxy.jetty.util.*;
import net.lightbody.bmp.proxy.jetty.util.URI;
import org.apache.commons.logging.Log;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.*;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.*;
/* ------------------------------------------------------------ */
/** Context for a collection of HttpHandlers.
* HTTP Context provides an ordered container for HttpHandlers
* that share the same path prefix, filebase, resourcebase and/or
* classpath.
*
* A HttpContext is analagous to a ServletContext in the
* Servlet API, except that it may contain other types of handler
* other than servlets.
*
* A ClassLoader is created for the context and it uses
* Thread.currentThread().getContextClassLoader(); as it's parent loader.
* The class loader is initialized during start(), when a derived
* context calls initClassLoader() or on the first call to loadClass()
*
*
* Note. that order is important when configuring a HttpContext.
* For example, if resource serving is enabled before servlets, then resources
* take priority.
*
* @see HttpServer
* @see HttpHandler
* @see net.lightbody.bmp.proxy.jetty.jetty.servlet.ServletHttpContext
* @version $Id: HttpContext.java,v 1.136 2006/02/21 09:47:43 gregwilkins Exp $
* @author Greg Wilkins (gregw)
*/
public class HttpContext extends Container
implements LifeCycle,
HttpHandler,
EventProvider,
Serializable
{
private static Log log = LogFactory.getLog(HttpContext.class);
/* ------------------------------------------------------------ */
/** File class path attribute.
* If this name is set as a context init parameter, then the attribute
* name given will be used to set the file classpath for the context as a
* context attribute.
*/
public final static String __fileClassPathAttr=
"HttpContext.FileClassPathAttribute";
public final static String __ErrorHandler=
"net.lightbody.bmp.proxy.jetty.http.ErrorHandler";
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
// These attributes are serialized by WebApplicationContext, which needs
// to be updated if you add to these
private String _contextPath;
private List _vhosts=new ArrayList(2);
private List _hosts=new ArrayList(2);
private List _handlers=new ArrayList(3);
private Map _attributes = new HashMap(3);
private boolean _redirectNullPath=true;
private boolean _statsOn=false;
private PermissionCollection _permissions;
private boolean _classLoaderJava2Compliant=true;
private ResourceCache _resources;
private String[] _systemClasses=new String [] {"java.","javax.servlet.","javax.xml.","net.lightbody.bmp.proxy.jetty.","org.xml.","org.w3c.","org.apache.commons.logging."};
private String[] _serverClasses = new String[] {"-PathMap","-net.lightbody.bmp.proxy.jetty.jetty.servlet.Invoker","-net.lightbody.bmp.proxy.jetty.jetty.servlet.JSR154Filter","-net.lightbody.bmp.proxy.jetty.jetty.servlet.Default","net.lightbody.bmp.proxy.jetty.jetty.Server","net.lightbody.bmp.proxy.jetty.http.","net.lightbody.bmp.proxy.jetty.start.","net.lightbody.bmp.proxy.jetty.stop."};
/* ------------------------------------------------------------ */
private String _contextName;
private String _classPath;
private Map _initParams = new HashMap(11);
private UserRealm _userRealm;
private String _realmName;
private PathMap _constraintMap=new PathMap();
private net.lightbody.bmp.proxy.jetty.http.Authenticator _authenticator;
private RequestLog _requestLog;
private String[] _welcomes=
{
"welcome.html",
"index.html",
"index.htm",
"index.jsp"
};
/* ------------------------------------------------------------ */
private transient boolean _gracefulStop;
private transient ClassLoader _parent;
private transient ClassLoader _loader;
private transient HttpServer _httpServer;
private transient File _tmpDir;
private transient HttpHandler[] _handlersArray;
private transient String[] _vhostsArray;
/* ------------------------------------------------------------ */
transient Object _statsLock=new Object[0];
transient long _statsStartedAt;
transient int _requests;
transient int _requestsActive;
transient int _requestsActiveMax;
transient int _responses1xx; // Informal
transient int _responses2xx; // Success
transient int _responses3xx; // Redirection
transient int _responses4xx; // Client Error
transient int _responses5xx; // Server Error
/* ------------------------------------------------------------ */
/** Constructor.
*/
public HttpContext()
{
setAttribute(__ErrorHandler, new ErrorPageHandler());
_resources=new ResourceCache();
addComponent(_resources);
}
/* ------------------------------------------------------------ */
/** Constructor.
* @param httpServer
* @param contextPathSpec
*/
public HttpContext(HttpServer httpServer,String contextPathSpec)
{
this();
setHttpServer(httpServer);
setContextPath(contextPathSpec);
}
/* ------------------------------------------------------------ */
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
_statsLock=new Object[0];
getHandlers();
for (int i=0;i<_handlersArray.length;i++)
_handlersArray[i].initialize(this);
}
/* ------------------------------------------------------------ */
/** Get the ThreadLocal HttpConnection.
* Get the HttpConnection for current thread, if any. This method is
* not static in order to control access.
* @return HttpConnection for this thread.
*/
public HttpConnection getHttpConnection()
{
return HttpConnection.getHttpConnection();
}
/* ------------------------------------------------------------ */
void setHttpServer(HttpServer httpServer)
{
_httpServer=httpServer;
_contextName=null;
}
/* ------------------------------------------------------------ */
public HttpServer getHttpServer()
{
return _httpServer;
}
/* ------------------------------------------------------------ */
public void setStopGracefully(boolean graceful)
{
_gracefulStop=graceful;
}
/* ------------------------------------------------------------ */
public boolean getStopGracefully()
{
return _gracefulStop;
}
/* ------------------------------------------------------------ */
public static String canonicalContextPathSpec(String contextPathSpec)
{
// check context path
if (contextPathSpec==null ||
contextPathSpec.indexOf(',')>=0 ||
contextPathSpec.startsWith("*"))
throw new IllegalArgumentException ("Illegal context spec:"+contextPathSpec);
if(!contextPathSpec.startsWith("/"))
contextPathSpec='/'+contextPathSpec;
if (contextPathSpec.length()>1)
{
if (contextPathSpec.endsWith("/"))
contextPathSpec+="*";
else if (!contextPathSpec.endsWith("/*"))
contextPathSpec+="/*";
}
return contextPathSpec;
}
/* ------------------------------------------------------------ */
public void setContextPath(String contextPathSpec)
{
if (_httpServer!=null)
_httpServer.removeMappings(this);
contextPathSpec=canonicalContextPathSpec(contextPathSpec);
if (contextPathSpec.length()>1)
_contextPath=contextPathSpec.substring(0,contextPathSpec.length()-2);
else
_contextPath="/";
_contextName=null;
if (_httpServer!=null)
_httpServer.addMappings(this);
}
/* ------------------------------------------------------------ */
/**
* @return The context prefix
*/
public String getContextPath()
{
return _contextPath;
}
/* ------------------------------------------------------------ */
/** Add a virtual host alias to this context.
* @see #setVirtualHosts
* @param hostname A hostname. A null host name means any hostname is
* acceptable. Host names may String representation of IP addresses.
*/
public void addVirtualHost(String hostname)
{
// Note that null hosts are also added.
if (!_vhosts.contains(hostname))
{
_vhosts.add(hostname);
_contextName=null;
if (_httpServer!=null)
{
if (_vhosts.size()==1)
_httpServer.removeMapping(null,this);
_httpServer.addMapping(hostname,this);
}
_vhostsArray=null;
}
}
/* ------------------------------------------------------------ */
/** remove a virtual host alias to this context.
* @see #setVirtualHosts
* @param hostname A hostname. A null host name means any hostname is
* acceptable. Host names may String representation of IP addresses.
*/
public void removeVirtualHost(String hostname)
{
// Note that null hosts are also added.
if (_vhosts.remove(hostname))
{
_contextName=null;
if (_httpServer!=null)
{
_httpServer.removeMapping(hostname,this);
if (_vhosts.size()==0)
_httpServer.addMapping(null,this);
}
_vhostsArray=null;
}
}
/* ------------------------------------------------------------ */
/** Set the virtual hosts for the context.
* Only requests that have a matching host header or fully qualified
* URL will be passed to that context with a virtual host name.
* A context with no virtual host names or a null virtual host name is
* available to all requests that are not served by a context with a
* matching virtual host name.
* @param hosts Array of virtual hosts that this context responds to. A
* null host name or null/empty array means any hostname is acceptable.
* Host names may String representation of IP addresses.
*/
public void setVirtualHosts(String[] hosts)
{
List old = new ArrayList(_vhosts);
if (hosts!=null)
{
for (int i=0;i0)
buf.append(File.pathSeparator);
buf.append(iter.next().toString());
}
if (log.isDebugEnabled()) log.debug("fileClassPath="+buf);
return buf.toString();
}
/* ------------------------------------------------------------ */
/** Sets the class path for the context.
* A class path is only required for a context if it uses classes
* that are not in the system class path.
* @param classPath a comma or ';' separated list of class
* resources. These may be jar files, directories or URLs to jars
* or directories.
*/
public void setClassPath(String classPath)
{
_classPath=classPath;
if (isStarted())
log.warn("classpath set while started");
}
/* ------------------------------------------------------------ */
/** Add the class path element to the context.
* A class path is only required for a context if it uses classes
* that are not in the system class path.
* @param classPath a comma or ';' separated list of class
* resources. These may be jar files, directories or URLs to jars
* or directories.
*/
public void addClassPath(String classPath)
{
if (_classPath==null || _classPath.length()==0)
_classPath=classPath;
else
_classPath+=","+classPath;
if (isStarted())
log.warn("classpath set while started");
}
/* ------------------------------------------------------------ */
/** Add elements to the class path for the context from the jar and zip files found
* in the specified resource.
* @param lib the resource that contains the jar and/or zip files.
* @param append true if the classpath entries are to be appended to any
* existing classpath, or false if they replace the existing classpath.
* @see #setClassPath(String)
*/
public void addClassPaths(Resource lib)
{
if (isStarted())
log.warn("classpaths set while started");
if (lib.exists() && lib.isDirectory())
{
String[] files=lib.list();
for (int f=0;files!=null && f 0)
{
Object constraints= null;
// for each path match
// Add only constraints that have the correct method
// break if the matching pattern changes. This allows only
// constraints with matching pattern and method to be combined.
loop:
for (int m= 0; m < scss.size(); m++)
{
Map.Entry entry= (Map.Entry)scss.get(m);
Object scs= entry.getValue();
String p=(String)entry.getKey();
for (int c=0;c0)
{
Object o = request.getHttpConnection().getConnection();
if (o instanceof Socket)
{
Socket s=(Socket)o;
if (!_hosts.contains(s.getLocalAddress()))
{
if(log.isDebugEnabled())log.debug(s.getLocalAddress()+" not in "+_hosts);
return;
}
}
}
// handle stats
if (_statsOn)
{
synchronized(_statsLock)
{
_requests++;
_requestsActive++;
if (_requestsActive>_requestsActiveMax)
_requestsActiveMax=_requestsActive;
}
}
String pathInContext = URI.canonicalPath(request.getPath());
if (pathInContext==null)
{
// Must be a bad request.
throw new HttpException(HttpResponse.__400_Bad_Request);
}
if (_contextPath.length()>1)
pathInContext=pathInContext.substring(_contextPath.length());
if (_redirectNullPath && (pathInContext==null ||
pathInContext.length()==0))
{
StringBuffer buf=request.getRequestURL();
buf.append("/");
String q=request.getQuery();
if (q!=null&&q.length()!=0)
buf.append("?"+q);
response.sendRedirect(buf.toString());
if (log.isDebugEnabled())
log.debug(this+" consumed all of path "+
request.getPath()+
", redirect to "+buf.toString());
return;
}
String pathParams=null;
int semi = pathInContext.lastIndexOf(';');
if (semi>=0)
{
int pl = pathInContext.length()-semi;
String ep=request.getEncodedPath();
if(';'==ep.charAt(ep.length()-pl))
{
pathParams=pathInContext.substring(semi+1);
pathInContext=pathInContext.substring(0,semi);
}
}
try
{
handle(pathInContext,pathParams,request,response);
}
finally
{
if (_userRealm!=null && request.hasUserPrincipal())
_userRealm.disassociate(request.getUserPrincipal());
}
}
/* ------------------------------------------------------------ */
/** Handler request.
* Call each HttpHandler until request is handled.
* @param pathInContext Path in context
* @param pathParams Path parameters such as encoded Session ID
* @param request
* @param response
* @return True if the request has been handled.
* @exception HttpException
* @exception IOException
*/
public void handle(String pathInContext,
String pathParams,
HttpRequest request,
HttpResponse response)
throws HttpException, IOException
{
Object old_scope= null;
try
{
old_scope= enterContextScope(request,response);
HttpHandler[] handlers= getHandlers();
for (int k= 0; k < handlers.length; k++)
{
HttpHandler handler= handlers[k];
if (handler == null)
{
handlers= getHandlers();
k= -1;
continue;
}
if (!handler.isStarted())
{
if (log.isDebugEnabled())
log.debug(handler + " not started in " + this);
continue;
}
if (log.isDebugEnabled())
log.debug("Handler " + handler);
handler.handle(pathInContext, pathParams, request, response);
if (request.isHandled())
{
if (log.isDebugEnabled())
log.debug("Handled by " + handler);
return;
}
}
return;
}
finally
{
leaveContextScope(request, response, old_scope);
}
}
/* ------------------------------------------------------------ */
/** Enter the context scope.
* This method is called (by handle or servlet dispatchers) to indicate that
* request handling is entering the scope of this context. The opaque scope object
* returned, should be passed to the leaveContextScope method.
*/
public Object enterContextScope(HttpRequest request, HttpResponse response)
{
// Save the thread context loader
Thread thread = Thread.currentThread();
ClassLoader cl=thread.getContextClassLoader();
HttpContext c=response.getHttpContext();
Scope scope=null;
if (cl!=HttpContext.class.getClassLoader() || c!=null)
{
scope=new Scope();
scope._classLoader=cl;
scope._httpContext=c;
}
if (_loader!=null)
thread.setContextClassLoader(_loader);
response.setHttpContext(this);
return scope;
}
/* ------------------------------------------------------------ */
/** Leave the context scope.
* This method is called (by handle or servlet dispatchers) to indicate that
* request handling is leaveing the scope of this context. The opaque scope object
* returned by enterContextScope should be passed in.
*/
public void leaveContextScope(HttpRequest request, HttpResponse response,Object oldScope)
{
if (oldScope==null)
{
Thread.currentThread()
.setContextClassLoader(HttpContext.class.getClassLoader());
response.setHttpContext(null);
}
else
{
Scope old = (Scope)oldScope;
Thread.currentThread().setContextClassLoader(old._classLoader);
response.setHttpContext(old._httpContext);
}
}
/* ------------------------------------------------------------ */
public String getHttpContextName()
{
if (_contextName==null)
_contextName = (_vhosts.size()>1?(_vhosts.toString()+":"):"")+_contextPath;
return _contextName;
}
/* ------------------------------------------------------------ */
public void setHttpContextName(String s)
{
_contextName=s;
}
/* ------------------------------------------------------------ */
public String toString()
{
return "HttpContext["+getContextPath()+","+getHttpContextName()+"]";
}
/* ------------------------------------------------------------ */
public String toString(boolean detail)
{
return "HttpContext["+getContextPath()+","+getHttpContextName()+"]" +
(detail?("="+_handlers):"");
}
/* ------------------------------------------------------------ */
protected synchronized void doStart()
throws Exception
{
if (isStarted())
return;
if (_httpServer.getServerClasses()!=null)
_serverClasses=_httpServer.getServerClasses();
if (_httpServer.getSystemClasses()!=null)
_systemClasses=_httpServer.getSystemClasses();
_resources.start();
statsReset();
if (_httpServer==null)
throw new IllegalStateException("No server for "+this);
// start the context itself
_resources.getMimeMap();
_resources.getEncodingMap();
// Setup realm
if (_userRealm==null && _authenticator!=null)
{
_userRealm=_httpServer.getRealm(_realmName);
if (_userRealm==null)
log.warn("No Realm: "+_realmName);
}
// setup the context loader
initClassLoader(false);
// Set attribute if needed
String attr = getInitParameter(__fileClassPathAttr);
if (attr!=null && attr.length()>0)
setAttribute(attr,getFileClassPath());
// Start the handlers
Thread thread = Thread.currentThread();
ClassLoader lastContextLoader=thread.getContextClassLoader();
try
{
if (_loader!=null)
thread.setContextClassLoader(_loader);
if (_requestLog!=null)
_requestLog.start();
startHandlers();
}
finally
{
thread.setContextClassLoader(lastContextLoader);
getHandlers();
}
}
/* ------------------------------------------------------------ */
/** Start the handlers.
* This is called by start after the classloader has been
* initialized and set as the thread context loader.
* It may be specialized to provide custom handling
* before any handlers are started.
* @exception Exception
*/
protected void startHandlers()
throws Exception
{
// Prepare a multi exception
MultiException mx = new MultiException();
Iterator handlers = _handlers.iterator();
while(handlers.hasNext())
{
HttpHandler handler=(HttpHandler)handlers.next();
if (!handler.isStarted())
try{handler.start();}catch(Exception e){mx.add(e);}
}
mx.ifExceptionThrow();
}
/* ------------------------------------------------------------ */
/** Stop the context.
* @param graceful If true and statistics are on, then this method will wait
* for requestsActive to go to zero before calling stop()
*/
public void stop(boolean graceful)
throws InterruptedException
{
boolean gs=_gracefulStop;
try
{
_gracefulStop=true;
// wait for all requests to complete.
while (graceful && _statsOn && _requestsActive>0 && _httpServer!=null)
try {Thread.sleep(100);}
catch (InterruptedException e){throw e;}
catch (Exception e){LogSupport.ignore(log,e);}
stop();
}
finally
{
_gracefulStop=gs;
}
}
/* ------------------------------------------------------------ */
/** Stop the context.
*/
protected void doStop()
throws Exception
{
if (_httpServer==null)
throw new InterruptedException("Destroy called");
synchronized(this)
{
// Notify the container for the stop
Thread thread = Thread.currentThread();
ClassLoader lastContextLoader=thread.getContextClassLoader();
try
{
if (_loader!=null)
thread.setContextClassLoader(_loader);
Iterator handlers = _handlers.iterator();
while(handlers.hasNext())
{
HttpHandler handler=(HttpHandler)handlers.next();
if (handler.isStarted())
{
try{handler.stop();}
catch(Exception e){log.warn(LogSupport.EXCEPTION,e);}
}
}
if (_requestLog!=null)
_requestLog.stop();
}
finally
{
thread.setContextClassLoader(lastContextLoader);
}
// TODO this is a poor test
if (_loader instanceof ContextLoader)
{
((ContextLoader)_loader).destroy();
LogFactory.release(_loader);
}
_loader=null;
}
_resources.flushCache();
_resources.stop();
}
/* ------------------------------------------------------------ */
/** Destroy a context.
* Destroy a context and remove it from the HttpServer. The
* HttpContext must be stopped before it can be destroyed.
*/
public void destroy()
{
if (isStarted())
throw new IllegalStateException("Started");
if (_httpServer!=null)
_httpServer.removeContext(this);
_httpServer=null;
if (_handlers!=null)
_handlers.clear();
_handlers=null;
_parent=null;
_loader=null;
if (_attributes!=null)
_attributes.clear();
_attributes=null;
if (_initParams!=null)
_initParams.clear();
_initParams=null;
if (_vhosts!=null)
_vhosts.clear();
_vhosts=null;
_hosts=null;
_tmpDir=null;
_permissions=null;
removeComponent(_resources);
if (_resources!=null)
{
_resources.flushCache();
if (_resources.isStarted())
try{_resources.stop();}catch(Exception e){LogSupport.ignore(log,e);}
_resources.destroy();
}
_resources=null;
super.destroy();
}
/* ------------------------------------------------------------ */
/** Set the request log.
* @param log RequestLog to use.
*/
public void setRequestLog(RequestLog log)
{
_requestLog=log;
}
/* ------------------------------------------------------------ */
public RequestLog getRequestLog()
{
return _requestLog;
}
/* ------------------------------------------------------------ */
/** Send an error response.
* This method may be specialized to provide alternative error handling for
* errors generated by the container. The default implemenation calls HttpResponse.sendError
* @param response the response to send
* @param code The error code
* @param msg The message for the error or null for the default
* @throws IOException Problem sending response.
*/
public void sendError(HttpResponse response,int code,String msg)
throws IOException
{
response.sendError(code,msg);
}
/* ------------------------------------------------------------ */
/** Send an error response.
* This method obtains the responses context and call sendError for context specific
* error handling.
* @param response the response to send
* @param code The error code
* @param msg The message for the error or null for the default
* @throws IOException Problem sending response.
*/
public static void sendContextError(HttpResponse response,int code,String msg)
throws IOException
{
HttpContext context = response.getHttpContext();
if (context!=null)
context.sendError(response,code,msg);
else
response.sendError(code,msg);
}
/* ------------------------------------------------------------ */
/** True set statistics recording on for this context.
* @param on If true, statistics will be recorded for this context.
*/
public void setStatsOn(boolean on)
{
log.info("setStatsOn "+on+" for "+this);
_statsOn=on;
statsReset();
}
/* ------------------------------------------------------------ */
public boolean getStatsOn() {return _statsOn;}
/* ------------------------------------------------------------ */
public long getStatsOnMs()
{return _statsOn?(System.currentTimeMillis()-_statsStartedAt):0;}
/* ------------------------------------------------------------ */
public void statsReset()
{
synchronized(_statsLock)
{
if (_statsOn)
_statsStartedAt=System.currentTimeMillis();
_requests=0;
_requestsActiveMax=_requestsActive;
_responses1xx=0;
_responses2xx=0;
_responses3xx=0;
_responses4xx=0;
_responses5xx=0;
}
}
/* ------------------------------------------------------------ */
/**
* @return Get the number of requests handled by this context
* since last call of statsReset(). If setStatsOn(false) then this
* is undefined.
*/
public int getRequests() {return _requests;}
/* ------------------------------------------------------------ */
/**
* @return Number of requests currently active.
* Undefined if setStatsOn(false).
*/
public int getRequestsActive() {return _requestsActive;}
/* ------------------------------------------------------------ */
/**
* @return Maximum number of active requests
* since statsReset() called. Undefined if setStatsOn(false).
*/
public int getRequestsActiveMax() {return _requestsActiveMax;}
/* ------------------------------------------------------------ */
/**
* @return Get the number of responses with a 2xx status returned
* by this context since last call of statsReset(). Undefined if
* if setStatsOn(false).
*/
public int getResponses1xx() {return _responses1xx;}
/* ------------------------------------------------------------ */
/**
* @return Get the number of responses with a 100 status returned
* by this context since last call of statsReset(). Undefined if
* if setStatsOn(false).
*/
public int getResponses2xx() {return _responses2xx;}
/* ------------------------------------------------------------ */
/**
* @return Get the number of responses with a 3xx status returned
* by this context since last call of statsReset(). Undefined if
* if setStatsOn(false).
*/
public int getResponses3xx() {return _responses3xx;}
/* ------------------------------------------------------------ */
/**
* @return Get the number of responses with a 4xx status returned
* by this context since last call of statsReset(). Undefined if
* if setStatsOn(false).
*/
public int getResponses4xx() {return _responses4xx;}
/* ------------------------------------------------------------ */
/**
* @return Get the number of responses with a 5xx status returned
* by this context since last call of statsReset(). Undefined if
* if setStatsOn(false).
*/
public int getResponses5xx() {return _responses5xx;}
/* ------------------------------------------------------------ */
/** Log a request and response.
* Statistics are also collected by this method.
* @param request
* @param response
*/
public void log(HttpRequest request,
HttpResponse response,
int length)
{
if (_statsOn)
{
synchronized(_statsLock)
{
if (--_requestsActive<0)
_requestsActive=0;
if (response!=null)
{
switch(response.getStatus()/100)
{
case 1: _responses1xx++;break;
case 2: _responses2xx++;break;
case 3: _responses3xx++;break;
case 4: _responses4xx++;break;
case 5: _responses5xx++;break;
}
}
}
}
if (_requestLog!=null &&
request!=null &&
response!=null)
_requestLog.log(request,response,length);
else if (_httpServer!=null)
_httpServer.log(request,response,length);
}
/* ------------------------------------------------------------ */
/* Class to save scope of nested context calls
*/
private static class Scope
{
ClassLoader _classLoader;
HttpContext _httpContext;
}
/*
* @see HttpHandler#getName()
*/
public String getName()
{
return this.getContextPath();
}
/*
* @see HttpHandler#getHttpContext()
*/
public HttpContext getHttpContext()
{
return this;
}
/*
* @see HttpHandler#initialize(HttpContext)
*/
public void initialize(HttpContext context)
{
throw new UnsupportedOperationException();
}
/**
* @return
*/
public Resource getBaseResource()
{
return _resources.getBaseResource();
}
/**
* @param type
* @return
*/
public String getEncodingByMimeType(String type)
{
return _resources.getEncodingByMimeType(type);
}
/**
* @return
*/
public Map getEncodingMap()
{
return _resources.getEncodingMap();
}
/**
* @return
*/
public int getMaxCachedFileSize()
{
return _resources.getMaxCachedFileSize();
}
/**
* @return
*/
public int getMaxCacheSize()
{
return _resources.getMaxCacheSize();
}
/**
* @param filename
* @return
*/
public String getMimeByExtension(String filename)
{
return _resources.getMimeByExtension(filename);
}
/**
* @return
*/
public Map getMimeMap()
{
return _resources.getMimeMap();
}
/**
* @param pathInContext
* @return
* @throws IOException
*/
public Resource getResource(String pathInContext) throws IOException
{
return _resources.getResource(pathInContext);
}
/**
* @return
*/
public String getResourceBase()
{
return _resources.getResourceBase();
}
/**
* @param resource
* @return
*/
public ResourceMetaData getResourceMetaData(Resource resource)
{
return _resources.getResourceMetaData(resource);
}
/**
* @param base
*/
public void setBaseResource(Resource base)
{
_resources.setBaseResource(base);
}
/**
* @param encodingMap
*/
public void setEncodingMap(Map encodingMap)
{
_resources.setEncodingMap(encodingMap);
}
/**
* @param maxCachedFileSize
*/
public void setMaxCachedFileSize(int maxCachedFileSize)
{
_resources.setMaxCachedFileSize(maxCachedFileSize);
}
/**
* @param maxCacheSize
*/
public void setMaxCacheSize(int maxCacheSize)
{
_resources.setMaxCacheSize(maxCacheSize);
}
/**
* @param mimeMap
*/
public void setMimeMap(Map mimeMap)
{
_resources.setMimeMap(mimeMap);
}
/**
* @param extension
* @param type
*/
public void setMimeMapping(String extension, String type)
{
_resources.setMimeMapping(extension, type);
}
/**
* @param resourceBase
*/
public void setResourceBase(String resourceBase)
{
_resources.setResourceBase(resourceBase);
}
/**
* @param mimeType
* @param encoding
*/
public void setTypeEncoding(String mimeType, String encoding)
{
_resources.setTypeEncoding(mimeType, encoding);
}
}