From 833ebd0714d59355d62e0f5e1558ba2a23ebd014 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 23 Apr 2009 18:29:46 +0000 Subject: [PATCH] Jetty: Fix temp dir handling, which was causing susidns not to start on windows. Jetty forms the temp directory name from, among other things, the bound address. The patch in 0.7.2 to bind to IPV6 addresses led to ':' in the directory name, which is not allowed on windows. Change these to '_'. --- .../src/org/mortbay/http/HttpContext.java | 2198 +++++++++++++++++ 1 file changed, 2198 insertions(+) create mode 100644 apps/jetty/java/src/org/mortbay/http/HttpContext.java 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); + } +}