]> WPIA git - gigi.git/blobdiff - lib/jetty/org/eclipse/jetty/servlet/Invoker.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / servlet / Invoker.java
diff --git a/lib/jetty/org/eclipse/jetty/servlet/Invoker.java b/lib/jetty/org/eclipse/jetty/servlet/Invoker.java
new file mode 100644 (file)
index 0000000..4613144
--- /dev/null
@@ -0,0 +1,314 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.ArrayUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/* ------------------------------------------------------------ */
+/**  Dynamic Servlet Invoker.
+ * This servlet invokes anonymous servlets that have not been defined
+ * in the web.xml or by other means. The first element of the pathInfo
+ * of a request passed to the envoker is treated as a servlet name for
+ * an existing servlet, or as a class name of a new servlet.
+ * This servlet is normally mapped to /servlet/*
+ * This servlet support the following initParams:
+ * <PRE>
+ *  nonContextServlets       If false, the invoker can only load
+ *                           servlets from the contexts classloader.
+ *                           This is false by default and setting this
+ *                           to true may have security implications.
+ *
+ *  verbose                  If true, log dynamic loads
+ *
+ *  *                        All other parameters are copied to the
+ *                           each dynamic servlet as init parameters
+ * </PRE>
+ * @version $Id: Invoker.java 4780 2009-03-17 15:36:08Z jesse $
+ *
+ */
+public class Invoker extends HttpServlet
+{
+    private static final Logger LOG = Log.getLogger(Invoker.class);
+
+
+    private ContextHandler _contextHandler;
+    private ServletHandler _servletHandler;
+    private Map.Entry _invokerEntry;
+    private Map _parameters;
+    private boolean _nonContextServlets;
+    private boolean _verbose;
+
+    /* ------------------------------------------------------------ */
+    public void init()
+    {
+        ServletContext config=getServletContext();
+        _contextHandler=((ContextHandler.Context)config).getContextHandler();
+
+        Handler handler=_contextHandler.getHandler();
+        while (handler!=null && !(handler instanceof ServletHandler) && (handler instanceof HandlerWrapper))
+            handler=((HandlerWrapper)handler).getHandler();
+        _servletHandler = (ServletHandler)handler;
+        Enumeration e = getInitParameterNames();
+        while(e.hasMoreElements())
+        {
+            String param=(String)e.nextElement();
+            String value=getInitParameter(param);
+            String lvalue=value.toLowerCase(Locale.ENGLISH);
+            if ("nonContextServlets".equals(param))
+            {
+                _nonContextServlets=value.length()>0 && lvalue.startsWith("t");
+            }
+            if ("verbose".equals(param))
+            {
+                _verbose=value.length()>0 && lvalue.startsWith("t");
+            }
+            else
+            {
+                if (_parameters==null)
+                    _parameters=new HashMap();
+                _parameters.put(param,value);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    protected void service(HttpServletRequest request, HttpServletResponse response)
+       throws ServletException, IOException
+    {
+        // Get the requested path and info
+        boolean included=false;
+        String servlet_path=(String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
+        if (servlet_path==null)
+            servlet_path=request.getServletPath();
+        else
+            included=true;
+        String path_info = (String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
+        if (path_info==null)
+            path_info=request.getPathInfo();
+
+        // Get the servlet class
+        String servlet = path_info;
+        if (servlet==null || servlet.length()<=1 )
+        {
+            response.sendError(404);
+            return;
+        }
+
+
+        int i0=servlet.charAt(0)=='/'?1:0;
+        int i1=servlet.indexOf('/',i0);
+        servlet=i1<0?servlet.substring(i0):servlet.substring(i0,i1);
+
+        // look for a named holder
+        ServletHolder[] holders = _servletHandler.getServlets();
+        ServletHolder holder = getHolder (holders, servlet);
+
+        if (holder!=null)
+        {
+            // Found a named servlet (from a user's web.xml file) so
+            // now we add a mapping for it
+            if (LOG.isDebugEnabled())
+                LOG.debug("Adding servlet mapping for named servlet:"+servlet+":"+URIUtil.addPaths(servlet_path,servlet)+"/*");
+            ServletMapping mapping = new ServletMapping();
+            mapping.setServletName(servlet);
+            mapping.setPathSpec(URIUtil.addPaths(servlet_path,servlet)+"/*");
+            _servletHandler.setServletMappings((ServletMapping[])ArrayUtil.addToArray(_servletHandler.getServletMappings(), mapping, ServletMapping.class));
+        }
+        else
+        {
+            // look for a class mapping
+            if (servlet.endsWith(".class"))
+                servlet=servlet.substring(0,servlet.length()-6);
+            if (servlet==null || servlet.length()==0)
+            {
+                response.sendError(404);
+                return;
+            }
+
+            synchronized(_servletHandler)
+            {
+                // find the entry for the invoker (me)
+                 _invokerEntry=_servletHandler.getHolderEntry(servlet_path);
+
+                // Check for existing mapping (avoid threaded race).
+                String path=URIUtil.addPaths(servlet_path,servlet);
+                Map.Entry entry = _servletHandler.getHolderEntry(path);
+
+                if (entry!=null && !entry.equals(_invokerEntry))
+                {
+                    // Use the holder
+                    holder=(ServletHolder)entry.getValue();
+                }
+                else
+                {
+                    // Make a holder
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Making new servlet="+servlet+" with path="+path+"/*");
+                    holder=_servletHandler.addServletWithMapping(servlet, path+"/*");
+
+                    if (_parameters!=null)
+                        holder.setInitParameters(_parameters);
+
+                    try {holder.start();}
+                    catch (Exception e)
+                    {
+                        LOG.debug(e);
+                        throw new UnavailableException(e.toString());
+                    }
+
+                    // Check it is from an allowable classloader
+                    if (!_nonContextServlets)
+                    {
+                        Object s=holder.getServlet();
+
+                        if (_contextHandler.getClassLoader()!=
+                            s.getClass().getClassLoader())
+                        {
+                            try
+                            {
+                                holder.stop();
+                            }
+                            catch (Exception e)
+                            {
+                                LOG.ignore(e);
+                            }
+
+                            LOG.warn("Dynamic servlet "+s+
+                                         " not loaded from context "+
+                                         request.getContextPath());
+                            throw new UnavailableException("Not in context");
+                        }
+                    }
+
+                    if (_verbose && LOG.isDebugEnabled())
+                        LOG.debug("Dynamic load '"+servlet+"' at "+path);
+                }
+            }
+        }
+
+        if (holder!=null)
+        {
+            final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
+            holder.handle(baseRequest,
+                    new InvokedRequest(request,included,servlet,servlet_path,path_info),
+                          response);
+        }
+        else
+        {
+            LOG.info("Can't find holder for servlet: "+servlet);
+            response.sendError(404);
+        }
+
+
+    }
+
+    /* ------------------------------------------------------------ */
+    class InvokedRequest extends HttpServletRequestWrapper
+    {
+        String _servletPath;
+        String _pathInfo;
+        boolean _included;
+
+        /* ------------------------------------------------------------ */
+        InvokedRequest(HttpServletRequest request,
+                boolean included,
+                String name,
+                String servletPath,
+                String pathInfo)
+        {
+            super(request);
+            _included=included;
+            _servletPath=URIUtil.addPaths(servletPath,name);
+            _pathInfo=pathInfo.substring(name.length()+1);
+            if (_pathInfo.length()==0)
+                _pathInfo=null;
+        }
+
+        /* ------------------------------------------------------------ */
+        public String getServletPath()
+        {
+            if (_included)
+                return super.getServletPath();
+            return _servletPath;
+        }
+
+        /* ------------------------------------------------------------ */
+        public String getPathInfo()
+        {
+            if (_included)
+                return super.getPathInfo();
+            return _pathInfo;
+        }
+
+        /* ------------------------------------------------------------ */
+        public Object getAttribute(String name)
+        {
+            if (_included)
+            {
+                if (name.equals(Dispatcher.INCLUDE_REQUEST_URI))
+                    return URIUtil.addPaths(URIUtil.addPaths(getContextPath(),_servletPath),_pathInfo);
+                if (name.equals(Dispatcher.INCLUDE_PATH_INFO))
+                    return _pathInfo;
+                if (name.equals(Dispatcher.INCLUDE_SERVLET_PATH))
+                    return _servletPath;
+            }
+            return super.getAttribute(name);
+        }
+    }
+
+
+    private ServletHolder getHolder(ServletHolder[] holders, String servlet)
+    {
+        if (holders == null)
+            return null;
+
+        ServletHolder holder = null;
+        for (int i=0; holder==null && i<holders.length; i++)
+        {
+            if (holders[i].getName().equals(servlet))
+            {
+                holder = holders[i];
+            }
+        }
+        return holder;
+    }
+}