diff --git a/apps/jetty/java/src/org/mortbay/http/HttpContext.java b/apps/jetty/java/src/org/mortbay/http/HttpContext.java new file mode 100644 index 000000000..061d3ad17 --- /dev/null +++ b/apps/jetty/java/src/org/mortbay/http/HttpContext.java @@ -0,0 +1,2198 @@ +// ======================================================================== +// $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 org.mortbay.http; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.UnknownHostException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.apache.commons.logging.Log; +import org.mortbay.log.LogFactory; +import org.mortbay.http.ResourceCache.ResourceMetaData; +import org.mortbay.http.handler.ErrorPageHandler; +import org.mortbay.util.Container; +import org.mortbay.util.EventProvider; +import org.mortbay.util.IO; +import org.mortbay.util.LazyList; +import org.mortbay.util.LifeCycle; +import org.mortbay.util.LogSupport; +import org.mortbay.util.MultiException; +import org.mortbay.util.Resource; +import org.mortbay.util.URI; + + +/* ------------------------------------------------------------ */ +/** 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 org.mortbay.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= + "org.mortbay.http.HttpContext.FileClassPathAttribute"; + + public final static String __ErrorHandler= + "org.mortbay.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.","org.mortbay.","org.xml.","org.w3c.","org.apache.commons.logging."}; + private String[] _serverClasses = new String[] {"-org.mortbay.http.PathMap","-org.mortbay.jetty.servlet.Invoker","-org.mortbay.jetty.servlet.JSR154Filter","-org.mortbay.jetty.servlet.Default","org.mortbay.jetty.Server","org.mortbay.http.","org.mortbay.start.","org.mortbay.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 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;i 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 org.mortbay.http.HttpHandler#getName() + */ + public String getName() + { + return this.getContextPath(); + } + + /* + * @see org.mortbay.http.HttpHandler#getHttpContext() + */ + public HttpContext getHttpContext() + { + return this; + } + + /* + * @see org.mortbay.http.HttpHandler#initialize(org.mortbay.http.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); + } +}