All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.browsermob.proxy.jetty.http.HttpServer Maven / Gradle / Ivy

There is a newer version: 2.0-beta-7
Show newest version
// ========================================================================
// $Id: HttpServer.java,v 1.70 2005/12/04 11:43:21 gregwilkins Exp $
// Copyright 1999-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.browsermob.proxy.jetty.http;

import org.apache.commons.logging.Log;
import org.browsermob.proxy.jetty.http.handler.DumpHandler;
import org.browsermob.proxy.jetty.http.handler.NotFoundHandler;
import org.browsermob.proxy.jetty.http.handler.ResourceHandler;
import org.browsermob.proxy.jetty.log.LogFactory;
import org.browsermob.proxy.jetty.util.*;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.*;



/* ------------------------------------------------------------ */
/** HTTP Server.
 * Services HTTP requests by maintaining a mapping between
 * a collection of HttpListeners which generate requests and
 * HttpContexts which contain collections of HttpHandlers.
 *
 * This class is configured by API calls.  The
 * org.mortbay.jetty.Server class uses XML configuration files to
 * configure instances of this class.
 *
 * The HttpServer implements the BeanContext API so that membership
 * events may be generated for HttpListeners, HttpContexts and WebApplications.
 *
 * @see HttpContext
 * @see HttpHandler
 * @see HttpConnection
 * @see HttpListener
 * @see org.browsermob.proxy.jetty.jetty.Server
 * @version $Id: HttpServer.java,v 1.70 2005/12/04 11:43:21 gregwilkins Exp $
 * @author Greg Wilkins (gregw)
 */
public class HttpServer extends Container
                        implements LifeCycle,
                                   EventProvider,
                                   Serializable
{
    private static Log log = LogFactory.getLog(HttpServer.class);
    
    /* ------------------------------------------------------------ */
    private static WeakHashMap __servers = new WeakHashMap();
    private static Collection __roServers =
        Collections.unmodifiableCollection(__servers.keySet());
    private static String[] __noVirtualHost=new String[1];
    
    
    /* ------------------------------------------------------------ */
    /** Get HttpServer Collection.
     * Get a collection of all known HttpServers.  Servers can be
     * removed from this list with the setAnonymous call.
     * @return  Collection of all servers.
     */
    public static Collection getHttpServers()
    {
        return __roServers;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @deprecated User getHttpServers()
     */
    public static List getHttpServerList()
    {
        return new ArrayList(__roServers);
    }
    
    /* ------------------------------------------------------------ */
    private List _listeners = new ArrayList(3);
    private HashMap _realmMap = new HashMap(3);    
    private StringMap _virtualHostMap = new StringMap();
    private boolean _trace=false;
    private RequestLog _requestLog;
    private int _requestsPerGC ;
    private boolean _resolveRemoteHost =false;
    
    private String[] _serverClasses;
    private String[] _systemClasses;
    
    private transient int _gcRequests;
    private transient HttpContext _notFoundContext=null;
    private transient boolean _gracefulStop;
    
    
    
    /* ------------------------------------------------------------ */
    /** Constructor. 
     */
    public HttpServer()
    {
        this(false);
    }
    
    /* ------------------------------------------------------------ */
    /** Constructor. 
     * @param anonymous If true, the server is not included in the
     * static server lists and stopAll methods.
     */
    public HttpServer(boolean anonymous)
    {
        setAnonymous(anonymous);
        _virtualHostMap.setIgnoreCase(true);
    }
    
    /* ------------------------------------------------------------ */
    private void readObject(java.io.ObjectInputStream in)
        throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        HttpListener[] listeners=getListeners();
        HttpContext[] contexts=getContexts();
        _listeners.clear();
        _virtualHostMap.clear();
        setContexts(contexts);
        setListeners(listeners);
        _statsLock=new Object[0];
    }
 
    
    /* ------------------------------------------------------------ */
    /** 
     * @param anonymous If true, the server is not included in the
     * static server lists and stopAll methods.
     */
    public void setAnonymous(boolean anonymous)
    {
        if (anonymous)
            __servers.remove(this);
        else
            __servers.put(this,__servers);
    }

    /* ------------------------------------------------------------ */
    public void setStopGracefully(boolean graceful)
    {
	_gracefulStop=graceful;
    }

    /* ------------------------------------------------------------ */
    public boolean getStopGracefully()
    {
	return _gracefulStop;
    }


    /* ------------------------------------------------------------ */
    /** 
     * @param listeners Array of HttpListeners.
     */
    public void setListeners(HttpListener[] listeners)
    {
        List old = new ArrayList(_listeners);
        
        for (int i=0;i=contextList.size())
                    return null;
                hc=(HttpContext)contextList.get(i);
            }
        }

        return hc;
    }

    
    /* ------------------------------------------------------------ */
    /** Get or create context. 
     * @param virtualHost The virtual host or null for all hosts.
     * @param contextPathSpec
     * @return HttpContext. If multiple contexts exist for the same
     * virtualHost and pathSpec, the most recently added context is returned.
     * If no context exists, a new context is created by a call to newHttpContext.
     */
    public HttpContext getContext(String virtualHost, String contextPathSpec)
    { 
        HttpContext hc=null;
        contextPathSpec=HttpContext.canonicalContextPathSpec(contextPathSpec);
        PathMap contextMap=(PathMap)_virtualHostMap.get(virtualHost);
        
        if (contextMap!=null)
        {
            List contextList = (List)contextMap.get(contextPathSpec);
            if (contextList!=null && contextList.size()>0)
                hc=(HttpContext)contextList.get(contextList.size()-1);
        }
        if (hc==null)
            hc=addContext(virtualHost,contextPathSpec);

        return hc;
    }
    
    /* ------------------------------------------------------------ */
    /** Get or create context. 
     * @param contextPathSpec Path specification relative to the context path.
     * @return The HttpContext  If multiple contexts exist for the same
     * pathSpec, the most recently added context is returned.
     * If no context exists, a new context is created by a call to newHttpContext.
     */
    public HttpContext getContext(String contextPathSpec)
    {
        return getContext(null,contextPathSpec);
    }    
 
    /* ------------------------------------------------------------ */
    /** Create a new HttpContext.
     * Specialized HttpServer classes may override this method to
     * return subclasses of HttpContext.
     * @return A new instance of HttpContext or a subclass of HttpContext
     */
    protected HttpContext newHttpContext()
    {
        return new HttpContext();
    }

    /* ------------------------------------------------------------ */    
    synchronized void addMapping(String virtualHost, HttpContext context)
    {
        // Get the map of contexts
        PathMap contextMap=(PathMap)_virtualHostMap.get(virtualHost);
        if (contextMap==null)
        {
            contextMap=new PathMap(7);
            _virtualHostMap.put(virtualHost,contextMap);
        }
        
        // Generalize contextPath
        String contextPathSpec=
            HttpContext.canonicalContextPathSpec(context.getContextPath());
        
        // Get the list of contexts at this path
        List contextList = (List)contextMap.get(contextPathSpec);
        if (contextList==null)
        {
            contextList=new ArrayList(1);
            contextMap.put(contextPathSpec,contextList);
        }
        
        // Add the context to the list
        contextList.add(context);
            
        if(log.isDebugEnabled())log.debug("Added "+context+" for host "+(virtualHost==null?"*":virtualHost));
    }
    

    /* ------------------------------------------------------------ */
    synchronized void addMappings(HttpContext context)
    {
        if (context==_notFoundContext)
            return;
        
        String[] hosts=context.getVirtualHosts();
        if (hosts==null || hosts.length==0)
            hosts = __noVirtualHost;

        // For each host name
        for (int h=0;h0 && _gcRequests++>_requestsPerGC)
        {
            _gcRequests=0;
            System.gc();
        }
        
        while (true)
        {
            PathMap contextMap=(PathMap)_virtualHostMap.get(host);
            if (contextMap!=null)
            {
                List contextLists =contextMap.getMatches(request.getPath());
                if(contextLists!=null)
                {
                    if(log.isTraceEnabled())log.trace("Contexts at "+request.getPath()+": "+contextLists);
                    
                    for (int i=0;i _connectionsOpenMax)
                _connectionsOpenMax=_connectionsOpen;
        }
    }
    
    /* ------------------------------------------------------------ */
    void statsGotRequest()
    {
        synchronized(_statsLock)
        {
            _requestsActive++;
            if (_requestsActive > _requestsActiveMax)
                _requestsActiveMax=_requestsActive;
        }
    }
    
    /* ------------------------------------------------------------ */
    void statsEndRequest(long duration,boolean ok)
    {
        synchronized(_statsLock)
        {
            _requests++;
            _requestsActive--;
            if (_requestsActive<0)
                _requestsActive=0;
            if (_requestsActive < _requestsActiveMin)
                _requestsActiveMin=_requestsActive;
            
            if (ok)
            {
                _requestsDurationTotal+=duration;
                if (_requestsDurationMin==0 || duration<_requestsDurationMin)
                    _requestsDurationMin=duration;
                if (duration>_requestsDurationMax)
                    _requestsDurationMax=duration;
            }
            else
                _errors++;
        }
    }
    
    /* ------------------------------------------------------------ */
    void statsCloseConnection(long duration,int requests)
    {
        synchronized(_statsLock)
        {
            _connections++;
            _connectionsOpen--;
            _connectionsDurationTotal+=duration;
            if (_connectionsOpen<0)
                _connectionsOpen=0;
            if (_connectionsOpen<_connectionsOpenMin)
                _connectionsOpenMin=_connectionsOpen;
            if (_connectionsDurationMin==0 || duration<_connectionsDurationMin)
                _connectionsDurationMin=duration;
            if (duration>_connectionsDurationMax)
                _connectionsDurationMax=duration;
            if (_connectionsRequestsMin==0 || requests<_connectionsRequestsMin)
                _connectionsRequestsMin=requests;
            if (requests>_connectionsRequestsMax)
                _connectionsRequestsMax=requests;
        }
    }


    /* ------------------------------------------------------------ */
    /** Save the HttpServer
     * The server is saved by serialization to the given filename or URL.
     *
     * @param saveat A file or URL to save the configuration at. 
     * @exception MalformedURLException 
     * @exception IOException 
     */
    public void save(String saveat)
        throws MalformedURLException,
               IOException
    {
        Resource resource = Resource.newResource(saveat);
        ObjectOutputStream out = new ObjectOutputStream(resource.getOutputStream());
        out.writeObject(this);
        out.flush();
        out.close();
        log.info("Saved "+this+" to "+resource);
    }
    
    /* ------------------------------------------------------------ */
    /** Destroy a stopped server.
     * Remove all components and send notifications to all event
     * listeners. The HttpServer must be stopped before it can be destroyed.
     */
    public void destroy()
    {
        __servers.remove(this);
        if (isStarted())
            throw new IllegalStateException("Started");
        if (_listeners!=null)
            _listeners.clear();
        _listeners=null;
        if (_virtualHostMap!=null)
            _virtualHostMap.clear();
        _virtualHostMap=null;
        _notFoundContext=null;

        super.destroy();
    }
    
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    /** Construct server from command line arguments.
     * @param args 
     */
    public static void main(String[] args)
    {
        if (args.length==0 || args.length>2)
        {
            System.err.println
                ("\nUsage - java org.browsermob.proxy.jetty.http.HttpServer [:]");
            System.err.println
                ("\nUsage - java org.browsermob.proxy.jetty.http.HttpServer -r [savefile]");
            System.err.println
                ("  Serves files from '.' directory");
            System.err.println
                ("  Dump handler for not found requests");
            System.err.println
                ("  Default port is 8080");
            System.exit(1);
        }
        
        try{
            
            if (args.length==1)
            {
                // Create the server
                HttpServer server = new HttpServer();
                
                // Default is no virtual host
                String host=null;
                HttpContext context = server.getContext(host,"/");
                context.setResourceBase(".");
                context.addHandler(new ResourceHandler());
                context.addHandler(new DumpHandler());
                context.addHandler(new NotFoundHandler());

                InetAddrPort address = new InetAddrPort(args[0]);
                server.addListener(address);

                server.start();
            }
            else
            {
                Resource resource = Resource.newResource(args[1]);
                ObjectInputStream in = new ObjectInputStream(resource.getInputStream());
                HttpServer server = (HttpServer)in.readObject();
                in.close();
                server.start();
            }
            
        }
        catch (Exception e)
        {
            log.warn(LogSupport.EXCEPTION,e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy