/**
   * Handle the HTTP status code (and corresponding message) generated while processing the
   * specified Request to produce the specified Response. Any exceptions that occur during
   * generation of the error report are logged and swallowed.
   *
   * @param request The request being processed
   * @param response The response being generated
   */
  private void status(Request request, Response response) {

    int statusCode = response.getStatus();

    // Handle a custom error page for this status code
    Context context = request.getContext();
    if (context == null) return;

    /* Only look for error pages when isError() is set.
     * isError() is set when response.sendError() is invoked. This
     * allows custom error pages without relying on default from
     * web.xml.
     */
    if (!response.isError()) return;

    ErrorPage errorPage = context.findErrorPage(statusCode);
    if (errorPage == null) {
      // Look for a default error page
      errorPage = context.findErrorPage(0);
    }
    if (errorPage != null && response.setErrorReported()) {
      response.setAppCommitted(false);
      request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode));

      String message = response.getMessage();
      if (message == null) message = "";
      request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
      request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation());
      request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR);

      Wrapper wrapper = request.getWrapper();
      if (wrapper != null)
        request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName());
      request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
      if (custom(request, response, errorPage)) {
        try {
          response.finishResponse();
        } catch (ClientAbortException e) {
          // Ignore
        } catch (IOException e) {
          container.getLogger().warn("Exception Processing " + errorPage, e);
        }
      }
    }
  }
 private static ServletInfo getServletInfo(Wrapper wrapper, String contextName) {
   ServletInfo si = new ServletInfo();
   si.setApplicationName(contextName.length() > 0 ? contextName : "/");
   si.setServletName(wrapper.getName());
   si.setServletClass(wrapper.getServletClass());
   si.setAvailable(!wrapper.isUnavailable());
   si.setLoadOnStartup(wrapper.getLoadOnStartup());
   si.setRunAs(wrapper.getRunAs());
   si.getMappings().addAll(Arrays.asList(wrapper.findMappings()));
   if (wrapper instanceof StandardWrapper) {
     StandardWrapper sw = (StandardWrapper) wrapper;
     si.setAllocationCount(sw.getCountAllocated());
     si.setErrorCount(sw.getErrorCount());
     si.setLoadTime(sw.getLoadTime());
     si.setMaxInstances(sw.getMaxInstances());
     si.setMaxTime(sw.getMaxTime());
     si.setMinTime(sw.getMinTime() == Long.MAX_VALUE ? 0 : sw.getMinTime());
     si.setProcessingTime(sw.getProcessingTime());
     si.setRequestCount(sw.getRequestCount());
     si.setSingleThreaded(sw.isSingleThreadModel());
   }
   return si;
 }
  /**
   * Handle the specified Throwable encountered while processing the specified Request to produce
   * the specified Response. Any exceptions that occur during generation of the exception report are
   * logged and swallowed.
   *
   * @param request The request being processed
   * @param response The response being generated
   * @param throwable The exception that occurred (which possibly wraps a root cause exception
   */
  protected void throwable(Request request, Response response, Throwable throwable) {
    Context context = request.getContext();
    if (context == null) return;

    Throwable realError = throwable;

    if (realError instanceof ServletException) {
      realError = ((ServletException) realError).getRootCause();
      if (realError == null) {
        realError = throwable;
      }
    }

    // If this is an aborted request from a client just log it and return
    if (realError instanceof ClientAbortException) {
      if (log.isDebugEnabled()) {
        log.debug(sm.getString("standardHost.clientAbort", realError.getCause().getMessage()));
      }
      return;
    }

    ErrorPage errorPage = findErrorPage(context, throwable);
    if ((errorPage == null) && (realError != throwable)) {
      errorPage = findErrorPage(context, realError);
    }

    if (errorPage != null) {
      if (response.setErrorReported()) {
        response.setAppCommitted(false);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation());
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR);
        request.setAttribute(
            RequestDispatcher.ERROR_STATUS_CODE,
            new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
        request.setAttribute(RequestDispatcher.ERROR_MESSAGE, throwable.getMessage());
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, realError);
        Wrapper wrapper = request.getWrapper();
        if (wrapper != null)
          request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName());
        request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, realError.getClass());
        if (custom(request, response, errorPage)) {
          try {
            response.finishResponse();
          } catch (IOException e) {
            container.getLogger().warn("Exception Processing " + errorPage, e);
          }
        }
      }
    } else {
      // A custom error-page has not been defined for the exception
      // that was thrown during request processing. Check if an
      // error-page for error code 500 was specified and if so,
      // send that page back as the response.
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      // The response is an error
      response.setError();

      status(request, response);
    }
  }
Example #4
0
  /**
   * Serve the specified request, creating the corresponding response. After the first time a
   * particular servlet class is requested, it will be served directly (like any registered servlet)
   * because it will have been registered and mapped in our associated Context.
   *
   * @param request The servlet request we are processing
   * @param response The servlet response we are creating
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet-specified error occurs
   */
  public void serveRequest(HttpServletRequest request, HttpServletResponse response)
      throws IOException, ServletException {

    // Disallow calling this servlet via a named dispatcher
    if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null)
      throw new ServletException(sm.getString("invokerServlet.notNamed"));

    // Identify the input parameters and our "included" state
    String inRequestURI = null;
    String inServletPath = null;
    String inPathInfo = null;
    boolean included = (request.getAttribute(Globals.REQUEST_URI_ATTR) != null);

    if (included) {
      inRequestURI = (String) request.getAttribute(Globals.REQUEST_URI_ATTR);
      inServletPath = (String) request.getAttribute(Globals.SERVLET_PATH_ATTR);
      inPathInfo = (String) request.getAttribute(Globals.PATH_INFO_ATTR);
    } else {
      inRequestURI = request.getRequestURI();
      inServletPath = request.getServletPath();
      inPathInfo = request.getPathInfo();
    }
    if (debug >= 1) {
      log("included='" + included + "', requestURI='" + inRequestURI + "'");
      log("  servletPath='" + inServletPath + "', pathInfo='" + inPathInfo + "'");
    }

    // Make sure a servlet name or class name was specified
    if (inPathInfo == null) {
      if (debug >= 1) log("Invalid pathInfo '" + inPathInfo + "'");
      if (included)
        throw new ServletException(sm.getString("invokerServlet.invalidPath", inRequestURI));
      else {
        response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI);
        return;
      }
    }

    // Identify the outgoing servlet name or class, and outgoing path info
    String pathInfo = inPathInfo;
    String servletClass = pathInfo.substring(1);
    int slash = servletClass.indexOf('/');
    //        if (debug >= 2)
    //            log("  Calculating with servletClass='" + servletClass +
    //                "', pathInfo='" + pathInfo + "', slash=" + slash);
    if (slash >= 0) {
      pathInfo = servletClass.substring(slash);
      servletClass = servletClass.substring(0, slash);
    } else {
      pathInfo = "";
    }

    if (servletClass.startsWith("org.apache.catalina")) {
      response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI);
      return;
    }

    if (debug >= 1)
      log("Processing servlet '" + servletClass + "' with path info '" + pathInfo + "'");
    String name = "org.apache.catalina.INVOKER." + servletClass;
    String pattern = inServletPath + "/" + servletClass + "/*";
    Wrapper wrapper = null;

    // Synchronize to avoid race conditions when multiple requests
    // try to initialize the same servlet at the same time
    synchronized (this) {

      // Are we referencing an existing servlet class or name?
      wrapper = (Wrapper) context.findChild(servletClass);
      if (wrapper == null) wrapper = (Wrapper) context.findChild(name);
      if (wrapper != null) {
        if (debug >= 1)
          log(
              "Using wrapper for servlet '"
                  + wrapper.getName()
                  + "' with mapping '"
                  + pattern
                  + "'");
        context.addServletMapping(pattern, wrapper.getName());
      }

      // No, create a new wrapper for the specified servlet class
      else {

        if (debug >= 1)
          log("Creating wrapper for '" + servletClass + "' with mapping '" + pattern + "'");

        try {
          wrapper = context.createWrapper();
          wrapper.setName(name);
          wrapper.setLoadOnStartup(1);
          wrapper.setServletClass(servletClass);
          context.addChild(wrapper);
          context.addServletMapping(pattern, name);
        } catch (Throwable t) {
          log(sm.getString("invokerServlet.cannotCreate", inRequestURI), t);
          context.removeServletMapping(pattern);
          context.removeChild(wrapper);
          if (included)
            throw new ServletException(
                sm.getString("invokerServlet.cannotCreate", inRequestURI), t);
          else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI);
            return;
          }
        }
      }
    }

    // Create a request wrapper to pass on to the invoked servlet
    InvokerHttpRequest wrequest = new InvokerHttpRequest(request);
    wrequest.setRequestURI(inRequestURI);
    StringBuffer sb = new StringBuffer(inServletPath);
    sb.append("/");
    sb.append(servletClass);
    wrequest.setServletPath(sb.toString());
    if ((pathInfo == null) || (pathInfo.length() < 1)) {
      wrequest.setPathInfo(null);
      wrequest.setPathTranslated(null);
    } else {
      wrequest.setPathInfo(pathInfo);
      wrequest.setPathTranslated(getServletContext().getRealPath(pathInfo));
    }

    // Allocate a servlet instance to perform this request
    Servlet instance = null;
    try {
      //            if (debug >= 2)
      //                log("  Allocating servlet instance");
      instance = wrapper.allocate();
    } catch (ServletException e) {
      log(sm.getString("invokerServlet.allocate", inRequestURI), e);
      context.removeServletMapping(pattern);
      context.removeChild(wrapper);
      Throwable rootCause = e.getRootCause();
      if (rootCause == null) rootCause = e;
      if (rootCause instanceof ClassNotFoundException) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND, inRequestURI);
        return;
      } else if (rootCause instanceof IOException) {
        throw (IOException) rootCause;
      } else if (rootCause instanceof RuntimeException) {
        throw (RuntimeException) rootCause;
      } else if (rootCause instanceof ServletException) {
        throw (ServletException) rootCause;
      } else {
        throw new ServletException(
            sm.getString("invokerServlet.allocate", inRequestURI), rootCause);
      }
    } catch (Throwable e) {
      log(sm.getString("invokerServlet.allocate", inRequestURI), e);
      context.removeServletMapping(pattern);
      context.removeChild(wrapper);
      throw new ServletException(sm.getString("invokerServlet.allocate", inRequestURI), e);
    }

    // After loading the wrapper, restore some of the fields when including
    if (included) {
      wrequest.setRequestURI(request.getRequestURI());
      wrequest.setPathInfo(request.getPathInfo());
      wrequest.setServletPath(request.getServletPath());
    }

    // Invoke the service() method of the allocated servlet
    try {
      String jspFile = wrapper.getJspFile();
      if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
      else request.removeAttribute(Globals.JSP_FILE_ATTR);
      request.setAttribute(Globals.INVOKED_ATTR, request.getServletPath());
      //            if (debug >= 2)
      //                log("  Calling service() method, jspFile=" +
      //                    jspFile);
      instance.service(wrequest, response);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
    } catch (IOException e) {
      //            if (debug >= 2)
      //                log("  service() method IOException", e);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
      try {
        wrapper.deallocate(instance);
      } catch (Throwable f) {;
      }
      throw e;
    } catch (UnavailableException e) {
      //            if (debug >= 2)
      //                log("  service() method UnavailableException", e);
      context.removeServletMapping(pattern);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
      try {
        wrapper.deallocate(instance);
      } catch (Throwable f) {;
      }
      throw e;
    } catch (ServletException e) {
      //            if (debug >= 2)
      //                log("  service() method ServletException", e);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
      try {
        wrapper.deallocate(instance);
      } catch (Throwable f) {;
      }
      throw e;
    } catch (RuntimeException e) {
      //            if (debug >= 2)
      //                log("  service() method RuntimeException", e);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
      try {
        wrapper.deallocate(instance);
      } catch (Throwable f) {;
      }
      throw e;
    } catch (Throwable e) {
      //            if (debug >= 2)
      //                log("  service() method Throwable", e);
      request.removeAttribute(Globals.INVOKED_ATTR);
      request.removeAttribute(Globals.JSP_FILE_ATTR);
      try {
        wrapper.deallocate(instance);
      } catch (Throwable f) {;
      }
      throw new ServletException("Invoker service() exception", e);
    }

    // Deallocate the allocated servlet instance
    try {
      //            if (debug >= 2)
      //                log("  deallocate servlet instance");
      wrapper.deallocate(instance);
    } catch (ServletException e) {
      log(sm.getString("invokerServlet.deallocate", inRequestURI), e);
      throw e;
    } catch (Throwable e) {
      log(sm.getString("invokerServlet.deallocate", inRequestURI), e);
      throw new ServletException(sm.getString("invokerServlet.deallocate", inRequestURI), e);
    }
  }