/** Release the Filter instance associated with this FilterConfig, if there is one. */
  void release() {

    unregisterJMX();

    if (this.filter != null) {
      if (Globals.IS_SECURITY_ENABLED) {
        try {
          SecurityUtil.doAsPrivilege("destroy", filter);
        } catch (java.lang.Exception ex) {
          context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
        }
        SecurityUtil.remove(filter);
      } else {
        filter.destroy();
      }
      if (!context.getIgnoreAnnotations()) {
        try {
          ((StandardContext) context).getInstanceManager().destroyInstance(this.filter);
        } catch (Exception e) {
          Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
          ExceptionUtils.handleThrowable(t);
          context.getLogger().error("ApplicationFilterConfig.preDestroy", t);
        }
      }
    }
    this.filter = null;
  }
예제 #2
0
 protected final void handlePojoMethodException(Throwable t) {
   t = ExceptionUtils.unwrapInvocationTargetException(t);
   ExceptionUtils.handleThrowable(t);
   if (t instanceof RuntimeException) {
     throw (RuntimeException) t;
   } else {
     throw new RuntimeException(t);
   }
 }
  /**
   * Wrap the incoming value into quotes and escape any inner quotes with double quotes.
   *
   * @param value - The value to wrap quotes around
   * @return '-' if empty of null. Otherwise, toString() will be called on the object and the value
   *     will be wrapped in quotes and any quotes will be escaped with 2 sets of quotes.
   */
  private String wrap(Object value) {
    String svalue;
    // Does the value contain a " ? If so must encode it
    if (value == null || "-".equals(value)) return "-";

    try {
      svalue = value.toString();
      if ("".equals(svalue)) return "-";
    } catch (Throwable e) {
      ExceptionUtils.handleThrowable(e);
      /* Log error */
      return "-";
    }

    /* Wrap all quotes in double quotes. */
    StringBuilder buffer = new StringBuilder(svalue.length() + 2);
    buffer.append('\'');
    int i = 0;
    while (i < svalue.length()) {
      int j = svalue.indexOf('\'', i);
      if (j == -1) {
        buffer.append(svalue.substring(i));
        i = svalue.length();
      } else {
        buffer.append(svalue.substring(i, j + 1));
        buffer.append('"');
        i = j + 2;
      }
    }

    buffer.append('\'');
    return buffer.toString();
  }
  /**
   * Handle an HTTP status code or Java exception by forwarding control to the location included in
   * the specified errorPage object. It is assumed that the caller has already recorded any request
   * attributes that are to be forwarded to this page. Return <code>true</code> if we successfully
   * utilized the specified error page location, or <code>false</code> if the default error report
   * should be rendered.
   *
   * @param request The request being processed
   * @param response The response being generated
   * @param errorPage The errorPage directive we are obeying
   */
  private boolean custom(Request request, Response response, ErrorPage errorPage) {

    if (container.getLogger().isDebugEnabled())
      container.getLogger().debug("Processing " + errorPage);

    try {
      // Forward control to the specified location
      ServletContext servletContext = request.getContext().getServletContext();
      RequestDispatcher rd = servletContext.getRequestDispatcher(errorPage.getLocation());

      if (response.isCommitted()) {
        // Response is committed - including the error page is the
        // best we can do
        rd.include(request.getRequest(), response.getResponse());
      } else {
        // Reset the response (keeping the real error code and message)
        response.resetBuffer(true);
        response.setContentLength(-1);

        rd.forward(request.getRequest(), response.getResponse());

        // If we forward, the response is suspended again
        response.setSuspended(false);
      }

      // Indicate that we have successfully processed this custom page
      return (true);

    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      // Report our failure to process this custom page
      container.getLogger().error("Exception Processing " + errorPage, t);
      return (false);
    }
  }
예제 #5
0
 private void handleThrowableOnSend(Throwable t) throws WsIOException {
   ExceptionUtils.handleThrowable(t);
   wsSession.getLocal().onError(wsSession, t);
   CloseReason cr =
       new CloseReason(CloseCodes.CLOSED_ABNORMALLY, sm.getString("wsFrame.ioeTriggeredClose"));
   throw new WsIOException(cr);
 }
예제 #6
0
    /**
     * The background thread that adds sockets to the Poller, checks the poller for triggered events
     * and hands the associated socket off to an appropriate processor as events occur.
     */
    @Override
    public void run() {
      // Loop until destroy() is called
      while (true) {

        boolean hasEvents = false;

        try {
          if (!close) {
            hasEvents = events();
            if (wakeupCounter.getAndSet(-1) > 0) {
              // if we are here, means we have other stuff to do
              // do a non blocking select
              keyCount = selector.selectNow();
            } else {
              keyCount = selector.select(selectorTimeout);
            }
            wakeupCounter.set(0);
          }
          if (close) {
            events();
            timeout(0, false);
            try {
              selector.close();
            } catch (IOException ioe) {
              log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
            }
            break;
          }
        } catch (Throwable x) {
          ExceptionUtils.handleThrowable(x);
          log.error("", x);
          continue;
        }
        // either we timed out or we woke up, process events first
        if (keyCount == 0) hasEvents = (hasEvents | events());

        Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
        // Walk through the collection of ready keys and dispatch
        // any active event.
        while (iterator != null && iterator.hasNext()) {
          SelectionKey sk = iterator.next();
          NioSocketWrapper attachment = (NioSocketWrapper) sk.attachment();
          // Attachment may be null if another thread has called
          // cancelledKey()
          if (attachment == null) {
            iterator.remove();
          } else {
            iterator.remove();
            processKey(sk, attachment);
          }
        } // while

        // process timeouts
        timeout(keyCount, hasEvents);
      } // while

      stopLatch.countDown();
    }
예제 #7
0
  /**
   * Set the Valve instance that has been distinguished as the basic Valve for this Pipeline (if
   * any). Prior to setting the basic Valve, the Valve's <code>setContainer()</code> will be called,
   * if it implements <code>Contained</code>, with the owning Container as an argument. The method
   * may throw an <code>IllegalArgumentException</code> if this Valve chooses not to be associated
   * with this Container, or <code>IllegalStateException</code> if it is already associated with a
   * different Container.
   *
   * @param valve Valve to be distinguished as the basic Valve
   */
  @Override
  public void setBasic(Valve valve) {

    // Change components if necessary
    Valve oldBasic = this.basic;
    if (oldBasic == valve) return;

    // Stop the old component if necessary
    if (oldBasic != null) {
      if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) {
        try {
          ((Lifecycle) oldBasic).stop();
        } catch (LifecycleException e) {
          log.error("StandardPipeline.setBasic: stop", e);
        }
      }
      if (oldBasic instanceof Contained) {
        try {
          ((Contained) oldBasic).setContainer(null);
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
        }
      }
    }

    // Start the new component if necessary
    if (valve == null) return;
    if (valve instanceof Contained) {
      ((Contained) valve).setContainer(this.container);
    }
    if (getState().isAvailable() && valve instanceof Lifecycle) {
      try {
        ((Lifecycle) valve).start();
      } catch (LifecycleException e) {
        log.error("StandardPipeline.setBasic: start", e);
        return;
      }
    }

    // Update the pipeline
    Valve current = first;
    while (current != null) {
      if (current.getNext() == oldBasic) {
        current.setNext(valve);
        break;
      }
      current = current.getNext();
    }

    this.basic = valve;
  }
  /**
   * Set the filter definition we are configured for. This has the side effect of instantiating an
   * instance of the corresponding filter class.
   *
   * @param filterDef The new filter definition
   * @exception ClassCastException if the specified class does not implement the <code>
   *     javax.servlet.Filter</code> interface
   * @exception ClassNotFoundException if the filter class cannot be found
   * @exception IllegalAccessException if the filter class cannot be publicly instantiated
   * @exception InstantiationException if an exception occurs while instantiating the filter object
   * @exception ServletException if thrown by the filter's init() method
   * @throws NamingException
   * @throws InvocationTargetException
   */
  void setFilterDef(FilterDef filterDef)
      throws ClassCastException, ClassNotFoundException, IllegalAccessException,
          InstantiationException, ServletException, InvocationTargetException, NamingException {

    this.filterDef = filterDef;
    if (filterDef == null) {

      // Release any previously allocated filter instance
      if (this.filter != null) {
        if (Globals.IS_SECURITY_ENABLED) {
          try {
            SecurityUtil.doAsPrivilege("destroy", filter);
          } catch (java.lang.Exception ex) {
            context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
          }
          SecurityUtil.remove(filter);
        } else {
          filter.destroy();
        }
        if (!context.getIgnoreAnnotations()) {
          try {
            ((StandardContext) context).getInstanceManager().destroyInstance(this.filter);
          } catch (Exception e) {
            Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(t);
            context.getLogger().error("ApplicationFilterConfig.preDestroy", t);
          }
        }
      }
      this.filter = null;

    } else {
      // Allocate a new filter instance if necessary
      if (filterDef.getFilter() == null) {
        getFilter();
      }
    }
  }
예제 #9
0
  /**
   * Process the specified connection.
   *
   * @param socket The socket channel
   * @return <code>true</code> if the socket was correctly configured and processing may continue,
   *     <code>false</code> if the socket needs to be close immediately
   */
  protected boolean setSocketOptions(SocketChannel socket) {
    // Process the connection
    try {
      // disable blocking, APR style, we are gonna be polling it
      socket.configureBlocking(false);
      Socket sock = socket.socket();
      socketProperties.setProperties(sock);

      NioChannel channel = nioChannels.pop();
      if (channel == null) {
        SocketBufferHandler bufhandler =
            new SocketBufferHandler(
                socketProperties.getAppReadBufSize(),
                socketProperties.getAppWriteBufSize(),
                socketProperties.getDirectBuffer());
        if (isSSLEnabled()) {
          channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
        } else {
          channel = new NioChannel(socket, bufhandler);
        }
      } else {
        channel.setIOChannel(socket);
        channel.reset();
      }
      getPoller0().register(channel);
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      try {
        log.error("", t);
      } catch (Throwable tt) {
        ExceptionUtils.handleThrowable(tt);
      }
      // Tell to close the socket
      return false;
    }
    return true;
  }
예제 #10
0
  @Override
  public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request == null) {
      // Create objects
      request = connector.createRequest();
      request.setCoyoteRequest(req);
      response = connector.createResponse();
      response.setCoyoteResponse(res);

      // Link objects
      request.setResponse(response);
      response.setRequest(request);

      // Set as notes
      req.setNote(ADAPTER_NOTES, request);
      res.setNote(ADAPTER_NOTES, response);

      // Set query string encoding
      req.getParameters().setQueryStringEncoding(connector.getURIEncoding());
    }

    try {
      // Log at the lowest level available. logAccess() will be
      // automatically called on parent containers.
      boolean logged = false;
      if (request.mappingData != null) {
        if (request.mappingData.context != null) {
          logged = true;
          ((Context) request.mappingData.context).logAccess(request, response, time, true);
        } else if (request.mappingData.host != null) {
          logged = true;
          ((Host) request.mappingData.host).logAccess(request, response, time, true);
        }
      }
      if (!logged) {
        connector.getService().getContainer().logAccess(request, response, time, true);
      }
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      log.warn(sm.getString("coyoteAdapter.accesslogFail"), t);
    } finally {
      request.recycle();
      response.recycle();
    }
  }
예제 #11
0
  private void fireEndpointOnClose(CloseReason closeReason) {

    // Fire the onClose event
    Thread t = Thread.currentThread();
    ClassLoader cl = t.getContextClassLoader();
    t.setContextClassLoader(applicationClassLoader);
    try {
      localEndpoint.onClose(this, closeReason);
    } catch (Throwable throwable) {
      ExceptionUtils.handleThrowable(throwable);
      localEndpoint.onError(this, throwable);
    } finally {
      t.setContextClassLoader(cl);
    }
  }
예제 #12
0
 public NioSocketWrapper cancelledKey(SelectionKey key) {
   NioSocketWrapper ka = null;
   try {
     if (key == null) return null; // nothing to do
     ka = (NioSocketWrapper) key.attach(null);
     if (ka != null) {
       // If attachment is non-null then there may be a current
       // connection with an associated processor.
       getHandler().release(ka);
     }
     if (key.isValid()) key.cancel();
     if (key.channel().isOpen()) {
       try {
         key.channel().close();
       } catch (Exception e) {
         if (log.isDebugEnabled()) {
           log.debug(sm.getString("endpoint.debug.channelCloseFail"), e);
         }
       }
     }
     try {
       if (ka != null) {
         ka.getSocket().close(true);
       }
     } catch (Exception e) {
       if (log.isDebugEnabled()) {
         log.debug(sm.getString("endpoint.debug.socketCloseFail"), e);
       }
     }
     try {
       if (ka != null
           && ka.getSendfileData() != null
           && ka.getSendfileData().fchannel != null
           && ka.getSendfileData().fchannel.isOpen()) {
         ka.getSendfileData().fchannel.close();
       }
     } catch (Exception ignore) {
     }
     if (ka != null) {
       countDownConnection();
     }
   } catch (Throwable e) {
     ExceptionUtils.handleThrowable(e);
     if (log.isDebugEnabled()) log.error("", e);
   }
   return ka;
 }
 @Override
 @SuppressWarnings("unchecked") // doPrivileged() returns the correct type
 public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
   if (SecurityUtil.isPackageProtectionEnabled()) {
     try {
       return (T) invokeMethod(context, "createListener", new Object[] {c});
     } catch (Throwable t) {
       ExceptionUtils.handleThrowable(t);
       if (t instanceof ServletException) {
         throw (ServletException) t;
       }
       return null;
     }
   } else {
     return context.createListener(c);
   }
 }
 /** @deprecated */
 @Override
 @Deprecated
 public Servlet getServlet(String name) throws ServletException {
   if (SecurityUtil.isPackageProtectionEnabled()) {
     try {
       return (Servlet) invokeMethod(context, "getServlet", new Object[] {name});
     } catch (Throwable t) {
       ExceptionUtils.handleThrowable(t);
       if (t instanceof ServletException) {
         throw (ServletException) t;
       }
       return null;
     }
   } else {
     return context.getServlet(name);
   }
 }
  /**
   * Use reflection to invoke the requested method. Cache the method object to speed up the process
   *
   * @param methodName The method to invoke.
   * @param clazz The class where the method is.
   * @param params The arguments passed to the called method.
   */
  private Object doPrivileged(final String methodName, final Class<?>[] clazz, Object[] params) {

    try {
      Method method = context.getClass().getMethod(methodName, clazz);
      return executeMethod(method, context, params);
    } catch (Exception ex) {
      try {
        handleException(ex);
      } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        throw new RuntimeException(t.getMessage());
      }
      return null;
    } finally {
      params = null;
    }
  }
예제 #16
0
 @Override
 public void run() {
   try {
     if (getServer() != null) {
       Catalina.this.stop();
     }
   } catch (Throwable ex) {
     ExceptionUtils.handleThrowable(ex);
     log.error(sm.getString("catalina.shutdownHookFail"), ex);
   } finally {
     // If JULI is used, shut JULI down *after* the server shuts down
     // so log messages aren't lost
     LogManager logManager = LogManager.getLogManager();
     if (logManager instanceof ClassLoaderLogManager) {
       ((ClassLoaderLogManager) logManager).shutdown();
     }
   }
 }
예제 #17
0
 /**
  * Attempt to load a class using the given Container's class loader. If the class cannot be
  * loaded, a debug level log message will be written to the Container's log and null will be
  * returned.
  */
 public static Class<?> loadClass(Context context, String className) {
   ClassLoader cl = context.getLoader().getClassLoader();
   Log log = context.getLogger();
   Class<?> clazz = null;
   try {
     clazz = cl.loadClass(className);
   } catch (ClassNotFoundException e) {
     log.debug(sm.getString("introspection.classLoadFailed", className), e);
   } catch (NoClassDefFoundError e) {
     log.debug(sm.getString("introspection.classLoadFailed", className), e);
   } catch (ClassFormatError e) {
     log.debug(sm.getString("introspection.classLoadFailed", className), e);
   } catch (Throwable t) {
     ExceptionUtils.handleThrowable(t);
     log.debug(sm.getString("introspection.classLoadFailed", className), t);
   }
   return clazz;
 }
예제 #18
0
 protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
   try {
     if (close) {
       cancelledKey(sk);
     } else if (sk.isValid() && attachment != null) {
       if (sk.isReadable() || sk.isWritable()) {
         if (attachment.getSendfileData() != null) {
           processSendfile(sk, attachment, false);
         } else {
           unreg(sk, attachment, sk.readyOps());
           boolean closeSocket = false;
           // Read goes before write
           if (sk.isReadable()) {
             if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
               closeSocket = true;
             }
           }
           if (!closeSocket && sk.isWritable()) {
             if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
               closeSocket = true;
             }
           }
           if (closeSocket) {
             cancelledKey(sk);
           }
         }
       }
     } else {
       // invalid key
       cancelledKey(sk);
     }
   } catch (CancelledKeyException ckx) {
     cancelledKey(sk);
   } catch (Throwable t) {
     ExceptionUtils.handleThrowable(t);
     log.error("", t);
   }
 }
예제 #19
0
  /** Stop an existing server instance. */
  public void stop() {

    try {
      // Remove the ShutdownHook first so that server.stop()
      // doesn't get invoked twice
      if (useShutdownHook) {
        Runtime.getRuntime().removeShutdownHook(shutdownHook);

        // If JULI is being used, re-enable JULI's shutdown to ensure
        // log messages are not lost
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
          ((ClassLoaderLogManager) logManager).setUseShutdownHook(true);
        }
      }
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      // This will fail on JDK 1.2. Ignoring, as Tomcat can run
      // fine without the shutdown hook.
    }

    // Shut down the server
    try {
      Server s = getServer();
      LifecycleState state = s.getState();
      if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
          && LifecycleState.DESTROYED.compareTo(state) >= 0) {
        // Nothing to do. stop() was already called
      } else {
        s.stop();
        s.destroy();
      }
    } catch (LifecycleException e) {
      log.error("Catalina.stop", e);
    }
  }
예제 #20
0
  @Override
  public boolean asyncDispatch(
      org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status)
      throws Exception {
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request == null) {
      throw new IllegalStateException("Dispatch may only happen on an existing request.");
    }
    boolean comet = false;
    boolean success = true;
    AsyncContextImpl asyncConImpl = (AsyncContextImpl) request.getAsyncContext();
    req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
    try {
      if (!request.isAsync() && !comet) {
        // Error or timeout - need to tell listeners the request is over
        // Have to test this first since state may change while in this
        // method and this is only required if entering this method in
        // this state
        Context ctxt = (Context) request.getMappingData().context;
        if (ctxt != null) {
          ctxt.fireRequestDestroyEvent(request);
        }
        // Lift any suspension (e.g. if sendError() was used by an async
        // request) to allow the response to be written to the client
        response.setSuspended(false);
      }

      if (status == SocketStatus.TIMEOUT) {
        if (!asyncConImpl.timeout()) {
          asyncConImpl.setErrorState(null, false);
        }
      }
      // Has an error occurred during async processing that needs to be
      // processed by the application's error page mechanism (or Tomcat's
      // if the application doesn't define one)?
      if (!request.isAsyncDispatching() && request.isAsync() && response.isErrorReportRequired()) {
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
      }

      if (request.isAsyncDispatching()) {
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
        Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
        if (t != null) {
          asyncConImpl.setErrorState(t, true);
        }
      }

      if (request.isComet()) {
        if (!response.isClosed() && !response.isError()) {
          if (request.getAvailable()
              || (request.getContentLength() > 0 && (!request.isParametersParsed()))) {
            // Invoke a read event right away if there are available bytes
            if (event(req, res, SocketStatus.OPEN_READ)) {
              comet = true;
              res.action(ActionCode.COMET_BEGIN, null);
            }
          } else {
            comet = true;
            res.action(ActionCode.COMET_BEGIN, null);
          }
        } else {
          // Clear the filter chain, as otherwise it will not be reset elsewhere
          // since this is a Comet request
          request.setFilterChain(null);
        }
      }
      if (!request.isAsync() && !comet) {
        request.finishRequest();
        response.finishResponse();
        req.action(ActionCode.POST_REQUEST, null);
        ((Context) request.getMappingData().context)
            .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false);
      }

      // Check to see if the processor is in an error state. If it is,
      // bail out now.
      AtomicBoolean error = new AtomicBoolean(false);
      res.action(ActionCode.IS_ERROR, error);
      if (error.get()) {
        success = false;
      }
    } catch (IOException e) {
      success = false;
      // Ignore
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      success = false;
      log.error(sm.getString("coyoteAdapter.service"), t);
    } finally {
      req.getRequestProcessor().setWorkerThreadName(null);
      // Recycle the wrapper request and response
      if (!success || (!comet && !request.isAsync())) {
        request.recycle();
        response.recycle();
      } else {
        // Clear converters so that the minimum amount of memory
        // is used by this processor
        request.clearEncoders();
        response.clearEncoders();
      }
    }
    return success;
  }
예제 #21
0
  /**
   * Event method.
   *
   * @return false to indicate an error, expected or not
   */
  @Override
  public boolean event(
      org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request.getWrapper() == null) {
      return false;
    }

    boolean error = false;
    boolean read = false;
    try {
      if (status == SocketStatus.OPEN_READ) {
        if (response.isClosed()) {
          // The event has been closed asynchronously, so call end instead of
          // read to cleanup the pipeline
          request.getEvent().setEventType(CometEvent.EventType.END);
          request.getEvent().setEventSubType(null);
        } else {
          try {
            // Fill the read buffer of the servlet layer
            if (request.read()) {
              read = true;
            }
          } catch (IOException e) {
            error = true;
          }
          if (read) {
            request.getEvent().setEventType(CometEvent.EventType.READ);
            request.getEvent().setEventSubType(null);
          } else if (error) {
            request.getEvent().setEventType(CometEvent.EventType.ERROR);
            request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT);
          } else {
            request.getEvent().setEventType(CometEvent.EventType.END);
            request.getEvent().setEventSubType(null);
          }
        }
      } else if (status == SocketStatus.DISCONNECT) {
        request.getEvent().setEventType(CometEvent.EventType.ERROR);
        request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT);
        error = true;
      } else if (status == SocketStatus.ERROR) {
        request.getEvent().setEventType(CometEvent.EventType.ERROR);
        request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION);
        error = true;
      } else if (status == SocketStatus.STOP) {
        request.getEvent().setEventType(CometEvent.EventType.END);
        request.getEvent().setEventSubType(CometEvent.EventSubType.SERVER_SHUTDOWN);
      } else if (status == SocketStatus.TIMEOUT) {
        if (response.isClosed()) {
          // The event has been closed asynchronously, so call end instead of
          // read to cleanup the pipeline
          request.getEvent().setEventType(CometEvent.EventType.END);
          request.getEvent().setEventSubType(null);
        } else {
          request.getEvent().setEventType(CometEvent.EventType.ERROR);
          request.getEvent().setEventSubType(CometEvent.EventSubType.TIMEOUT);
        }
      }

      req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());

      // Calling the container
      connector
          .getService()
          .getContainer()
          .getPipeline()
          .getFirst()
          .event(request, response, request.getEvent());

      if (!error
          && !response.isClosed()
          && (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) != null)) {
        // An unexpected exception occurred while processing the event, so
        // error should be called
        request.getEvent().setEventType(CometEvent.EventType.ERROR);
        request.getEvent().setEventSubType(null);
        error = true;
        connector
            .getService()
            .getContainer()
            .getPipeline()
            .getFirst()
            .event(request, response, request.getEvent());
      }
      if (response.isClosed() || !request.isComet()) {
        if (status == SocketStatus.OPEN_READ
            && request.getEvent().getEventType() != EventType.END) {
          // CometEvent.close was called during an event other than END
          request.getEvent().setEventType(CometEvent.EventType.END);
          request.getEvent().setEventSubType(null);
          error = true;
          connector
              .getService()
              .getContainer()
              .getPipeline()
              .getFirst()
              .event(request, response, request.getEvent());
        }
        res.action(ActionCode.COMET_END, null);
      } else if (!error && read && request.getAvailable()) {
        // If this was a read and not all bytes have been read, or if no data
        // was read from the connector, then it is an error
        request.getEvent().setEventType(CometEvent.EventType.ERROR);
        request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION);
        error = true;
        connector
            .getService()
            .getContainer()
            .getPipeline()
            .getFirst()
            .event(request, response, request.getEvent());
      }
      return (!error);
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      if (!(t instanceof IOException)) {
        log.error(sm.getString("coyoteAdapter.service"), t);
      }
      error = true;
      return false;
    } finally {
      req.getRequestProcessor().setWorkerThreadName(null);
      // Recycle the wrapper request and response
      if (error || response.isClosed() || !request.isComet()) {
        ((Context) request.getMappingData().context)
            .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false);
        request.recycle();
        request.setFilterChain(null);
        response.recycle();
      }
    }
  }
예제 #22
0
  /**
   * Perform work as a particular </code>Subject</code>. Here the work will be granted to a <code>
   * null</code> subject.
   *
   * @param methodName the method to apply the security restriction
   * @param targetObject the <code>Servlet</code> on which the method will be called.
   * @param targetArguments <code>Object</code> array contains the runtime parameters instance.
   * @param principal the <code>Principal</code> to which the security privilege applies
   */
  private static void execute(
      final Method method,
      final Object targetObject,
      final Object[] targetArguments,
      Principal principal)
      throws java.lang.Exception {

    try {
      Subject subject = null;
      PrivilegedExceptionAction<Void> pea =
          new PrivilegedExceptionAction<Void>() {
            @Override
            public Void run() throws Exception {
              method.invoke(targetObject, targetArguments);
              return null;
            }
          };

      // The first argument is always the request object
      if (targetArguments != null && targetArguments[0] instanceof HttpServletRequest) {
        HttpServletRequest request = (HttpServletRequest) targetArguments[0];

        boolean hasSubject = false;
        HttpSession session = request.getSession(false);
        if (session != null) {
          subject = (Subject) session.getAttribute(Globals.SUBJECT_ATTR);
          hasSubject = (subject != null);
        }

        if (subject == null) {
          subject = new Subject();

          if (principal != null) {
            subject.getPrincipals().add(principal);
          }
        }

        if (session != null && !hasSubject) {
          session.setAttribute(Globals.SUBJECT_ATTR, subject);
        }
      }

      Subject.doAsPrivileged(subject, pea, null);
    } catch (PrivilegedActionException pe) {
      Throwable e;
      if (pe.getException() instanceof InvocationTargetException) {
        e = pe.getException().getCause();
        ExceptionUtils.handleThrowable(e);
      } else {
        e = pe;
      }

      if (log.isDebugEnabled()) {
        log.debug(sm.getString("SecurityUtil.doAsPrivilege"), e);
      }

      if (e instanceof UnavailableException) throw (UnavailableException) e;
      else if (e instanceof ServletException) throw (ServletException) e;
      else if (e instanceof IOException) throw (IOException) e;
      else if (e instanceof RuntimeException) throw (RuntimeException) e;
      else throw new ServletException(e.getMessage(), e);
    }
  }
예제 #23
0
  /**
   * Process pipelined HTTP requests using the specified input and output streams.
   *
   * @throws IOException error during an I/O operation
   */
  @Override
  public SocketState process(SocketWrapper<NioChannel> socket) throws IOException {
    RequestInfo rp = request.getRequestProcessor();
    rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

    // Setting up the socket
    this.socketWrapper = socket;

    long soTimeout = endpoint.getSoTimeout();
    boolean cping = false;

    // Error flag
    error = false;

    while (!error && !endpoint.isPaused()) {
      // Parsing the request header
      try {
        // Get first message of the request
        int bytesRead = readMessage(requestHeaderMessage, false);
        if (bytesRead == 0) {
          break;
        }
        // Set back timeout if keep alive timeout is enabled
        if (keepAliveTimeout > 0) {
          socket.setTimeout(soTimeout);
        }
        // Check message type, process right away and break if
        // not regular request processing
        int type = requestHeaderMessage.getByte();
        if (type == Constants.JK_AJP13_CPING_REQUEST) {
          if (endpoint.isPaused()) {
            recycle(true);
            break;
          }
          cping = true;
          try {
            output(pongMessageArray, 0, pongMessageArray.length);
          } catch (IOException e) {
            error = true;
          }
          recycle(false);
          continue;
        } else if (type != Constants.JK_AJP13_FORWARD_REQUEST) {
          // Unexpected packet type. Unread body packets should have
          // been swallowed in finish().
          if (log.isDebugEnabled()) {
            log.debug("Unexpected message: " + type);
          }
          error = true;
          recycle(true);
          break;
        }
        request.setStartTime(System.currentTimeMillis());
      } catch (IOException e) {
        error = true;
        break;
      } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        log.debug(sm.getString("ajpprocessor.header.error"), t);
        // 400 - Bad Request
        response.setStatus(400);
        adapter.log(request, response, 0);
        error = true;
      }

      if (!error) {
        // Setting up filters, and parse some request headers
        rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
        try {
          prepareRequest();
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          log.debug(sm.getString("ajpprocessor.request.prepare"), t);
          // 400 - Internal Server Error
          response.setStatus(400);
          adapter.log(request, response, 0);
          error = true;
        }
      }

      if (!error && !cping && endpoint.isPaused()) {
        // 503 - Service unavailable
        response.setStatus(503);
        adapter.log(request, response, 0);
        error = true;
      }
      cping = false;

      // Process the request in the adapter
      if (!error) {
        try {
          rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
          adapter.service(request, response);
        } catch (InterruptedIOException e) {
          error = true;
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          log.error(sm.getString("ajpprocessor.request.process"), t);
          // 500 - Internal Server Error
          response.setStatus(500);
          adapter.log(request, response, 0);
          error = true;
        }
      }

      if (isAsync() && !error) {
        break;
      }

      // Finish the response if not done yet
      if (!finished) {
        try {
          finish();
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          error = true;
        }
      }

      // If there was an error, make sure the request is counted as
      // and error, and update the statistics counter
      if (error) {
        response.setStatus(500);
      }
      request.updateCounters();

      rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
      // Set keep alive timeout if enabled
      if (keepAliveTimeout > 0) {
        socket.setTimeout(keepAliveTimeout);
      }

      recycle(false);
    }

    rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);

    if (!error && !endpoint.isPaused()) {
      if (isAsync()) {
        return SocketState.LONG;
      } else {
        return SocketState.OPEN;
      }
    } else {
      return SocketState.CLOSED;
    }
  }
  /**
   * Select the appropriate child Context to process this request, based on the specified request
   * URI. If no matching Context can be found, return an appropriate HTTP error.
   *
   * @param request Request to be processed
   * @param response Response to be produced
   * @exception IOException if an input/output error occurred
   * @exception ServletException if a servlet error occurred
   */
  @Override
  public final void invoke(Request request, Response response)
      throws IOException, ServletException {

    /*
     * xujb:
     * 和Engine一样,调用下层的context,让它来做一些处理
     * 自身也处理了一些的逻辑
     *
     * */

    // Select the Context to be used for this Request
    Context context = request.getContext();
    if (context == null) {
      response.sendError(
          HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext"));
      return;
    }

    // Bind the context CL to the current thread
    if (context.getLoader() != null) {
      // Not started - it should check for availability first
      // This should eventually move to Engine, it's generic.
      if (Globals.IS_SECURITY_ENABLED) {
        PrivilegedAction<Void> pa = new PrivilegedSetTccl(context.getLoader().getClassLoader());
        AccessController.doPrivileged(pa);
      } else {
        Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
      }
    }
    if (request.isAsyncSupported()) {
      request.setAsyncSupported(context.getPipeline().isAsyncSupported());
    }

    boolean asyncAtStart = request.isAsync();
    boolean asyncDispatching = request.isAsyncDispatching();
    if (asyncAtStart || context.fireRequestInitEvent(request)) {

      // Ask this Context to process this request. Requests that are in
      // async mode and are not being dispatched to this resource must be
      // in error and have been routed here to check for application
      // defined error pages.
      try {
        if (!asyncAtStart || asyncDispatching) {
          context.getPipeline().getFirst().invoke(request, response);
        } else {
          // Make sure this request/response is here because an error
          // report is required.
          if (!response.isErrorReportRequired()) {
            throw new IllegalStateException(sm.getString("standardHost.asyncStateError"));
          }
        }
      } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        // If a new error occurred while trying to report a previous
        // error simply log the new error and allow the original error
        // to be reported.
        if (response.isErrorReportRequired()) {
          container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
        } else {
          request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
          throwable(request, response, t);
        }
      }

      // Now that the request/response pair is back under container
      // control lift the suspension so that the error handling can
      // complete and/or the container can flush any remaining data
      response.setSuspended(false);

      Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

      // Protect against NPEs if the context was destroyed during a
      // long running request.
      if (!context.getState().isAvailable()) {
        return;
      }

      // Look for (and render if found) an application level error page
      if (response.isErrorReportRequired()) {
        if (t != null) {
          throwable(request, response, t);
        } else {
          status(request, response);
        }
      }

      if (!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) {
        context.fireRequestDestroyEvent(request);
      }
    }

    // Access a session (if present) to update last accessed time, based on a
    // strict interpretation of the specification
    if (ACCESS_SESSION) {
      request.getSession(false);
    }

    // Restore the context classloader
    if (Globals.IS_SECURITY_ENABLED) {
      PrivilegedAction<Void> pa = new PrivilegedSetTccl(StandardHostValve.class.getClassLoader());
      AccessController.doPrivileged(pa);
    } else {
      Thread.currentThread().setContextClassLoader(StandardHostValve.class.getClassLoader());
    }
  }
예제 #25
0
    @Override
    public void run() {

      int errorDelay = 0;

      // Loop until we receive a shutdown command
      while (running) {

        // Loop if endpoint is paused
        while (paused && running) {
          state = AcceptorState.PAUSED;
          try {
            Thread.sleep(50);
          } catch (InterruptedException e) {
            // Ignore
          }
        }

        if (!running) {
          break;
        }
        state = AcceptorState.RUNNING;

        try {
          // if we have reached max connections, wait
          countUpOrAwaitConnection();

          SocketChannel socket = null;
          try {
            // Accept the next incoming connection from the server
            // socket
            socket = serverSock.accept();
          } catch (IOException ioe) {
            // we didn't get a socket
            countDownConnection();
            // Introduce delay if necessary
            errorDelay = handleExceptionWithDelay(errorDelay);
            // re-throw
            throw ioe;
          }
          // Successful accept, reset the error delay
          errorDelay = 0;

          // setSocketOptions() will add channel to the poller
          // if successful
          if (running && !paused) {
            if (!setSocketOptions(socket)) {
              countDownConnection();
              closeSocket(socket);
            }
          } else {
            countDownConnection();
            closeSocket(socket);
          }
        } catch (SocketTimeoutException sx) {
          // Ignore: Normal condition
        } catch (IOException x) {
          if (running) {
            log.error(sm.getString("endpoint.accept.fail"), x);
          }
        } catch (Throwable t) {
          ExceptionUtils.handleThrowable(t);
          log.error(sm.getString("endpoint.accept.fail"), t);
        }
      }
      state = AcceptorState.ENDED;
    }
예제 #26
0
    @SuppressWarnings("deprecation") // Old HTTP upgrade method has been deprecated
    public SocketState process(SocketWrapper<S> wrapper, SocketStatus status) {
      if (wrapper == null) {
        // Nothing to do. Socket has been closed.
        return SocketState.CLOSED;
      }

      S socket = wrapper.getSocket();
      if (socket == null) {
        // Nothing to do. Socket has been closed.
        return SocketState.CLOSED;
      }

      Processor<S> processor = connections.get(socket);
      if (status == SocketStatus.DISCONNECT && processor == null) {
        // Nothing to do. Endpoint requested a close and there is no
        // longer a processor associated with this socket.
        return SocketState.CLOSED;
      }

      wrapper.setAsync(false);
      ContainerThreadMarker.markAsContainerThread();

      try {
        if (processor == null) {
          processor = recycledProcessors.poll();
        }
        if (processor == null) {
          processor = createProcessor();
        }

        initSsl(wrapper, processor);

        SocketState state = SocketState.CLOSED;
        do {
          if (status == SocketStatus.CLOSE_NOW) {
            processor.errorDispatch();
            state = SocketState.CLOSED;
          } else if (status == SocketStatus.DISCONNECT && !processor.isComet()) {
            // Do nothing here, just wait for it to get recycled
            // Don't do this for Comet we need to generate an end
            // event (see BZ 54022)
          } else if (processor.isAsync()) {
            state = processor.asyncDispatch(status);
          } else if (state == SocketState.ASYNC_END) {
            state = processor.asyncDispatch(status);
            // release() won't get called so in case this request
            // takes a long time to process remove the socket from
            // the waiting requests now else the async timeout will
            // fire
            getProtocol().endpoint.removeWaitingRequest(wrapper);
            if (state == SocketState.OPEN) {
              // There may be pipe-lined data to read. If the data
              // isn't processed now, execution will exit this
              // loop and call release() which will recycle the
              // processor (and input buffer) deleting any
              // pipe-lined data. To avoid this, process it now.
              state = processor.process(wrapper);
            }
          } else if (processor.isComet()) {
            state = processor.event(status);
          } else if (processor.getUpgradeInbound() != null) {
            state = processor.upgradeDispatch();
          } else if (processor.isUpgrade()) {
            state = processor.upgradeDispatch(status);
          } else {
            state = processor.process(wrapper);
          }

          if (state != SocketState.CLOSED && processor.isAsync()) {
            state = processor.asyncPostProcess();
          }

          if (state == SocketState.UPGRADING) {
            // Get the HTTP upgrade handler
            HttpUpgradeHandler httpUpgradeHandler = processor.getHttpUpgradeHandler();
            // Release the Http11 processor to be re-used
            release(wrapper, processor, false, false);
            // Create the upgrade processor
            processor = createUpgradeProcessor(wrapper, httpUpgradeHandler);
            // Mark the connection as upgraded
            wrapper.setUpgraded(true);
            // Associate with the processor with the connection
            connections.put(socket, processor);
            // Initialise the upgrade handler (which may trigger
            // some IO using the new protocol which is why the lines
            // above are necessary)
            // This cast should be safe. If it fails the error
            // handling for the surrounding try/catch will deal with
            // it.
            httpUpgradeHandler.init((WebConnection) processor);
          } else if (state == SocketState.UPGRADING_TOMCAT) {
            // Get the UpgradeInbound handler
            org.apache.coyote.http11.upgrade.UpgradeInbound inbound = processor.getUpgradeInbound();
            // Release the Http11 processor to be re-used
            release(wrapper, processor, false, false);
            // Create the light-weight upgrade processor
            processor = createUpgradeProcessor(wrapper, inbound);
            inbound.onUpgradeComplete();
          }
          if (getLog().isDebugEnabled()) {
            getLog()
                .debug(
                    "Socket: ["
                        + wrapper
                        + "], Status in: ["
                        + status
                        + "], State out: ["
                        + state
                        + "]");
          }
        } while (state == SocketState.ASYNC_END
            || state == SocketState.UPGRADING
            || state == SocketState.UPGRADING_TOMCAT);

        if (state == SocketState.LONG) {
          // In the middle of processing a request/response. Keep the
          // socket associated with the processor. Exact requirements
          // depend on type of long poll
          connections.put(socket, processor);
          longPoll(wrapper, processor);
        } else if (state == SocketState.OPEN) {
          // In keep-alive but between requests. OK to recycle
          // processor. Continue to poll for the next request.
          connections.remove(socket);
          release(wrapper, processor, false, true);
        } else if (state == SocketState.SENDFILE) {
          // Sendfile in progress. If it fails, the socket will be
          // closed. If it works, the socket will be re-added to the
          // poller
          connections.remove(socket);
          release(wrapper, processor, false, false);
        } else if (state == SocketState.UPGRADED) {
          // Need to keep the connection associated with the processor
          connections.put(socket, processor);
          // Don't add sockets back to the poller if this was a
          // non-blocking write otherwise the poller may trigger
          // multiple read events which may lead to thread starvation
          // in the connector. The write() method will add this socket
          // to the poller if necessary.
          if (status != SocketStatus.OPEN_WRITE) {
            longPoll(wrapper, processor);
          }
        } else {
          // Connection closed. OK to recycle the processor. Upgrade
          // processors are not recycled.
          connections.remove(socket);
          if (processor.isUpgrade()) {
            processor.getHttpUpgradeHandler().destroy();
          } else if (processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) {
            // NO-OP
          } else {
            release(wrapper, processor, true, false);
          }
        }
        return state;
      } catch (java.net.SocketException e) {
        // SocketExceptions are normal
        getLog().debug(sm.getString("abstractConnectionHandler.socketexception.debug"), e);
      } catch (java.io.IOException e) {
        // IOExceptions are normal
        getLog().debug(sm.getString("abstractConnectionHandler.ioexception.debug"), e);
      }
      // Future developers: if you discover any other
      // rare-but-nonfatal exceptions, catch them here, and log as
      // above.
      catch (Throwable e) {
        ExceptionUtils.handleThrowable(e);
        // any other exception or error is odd. Here we log it
        // with "ERROR" level, so it will show up even on
        // less-than-verbose logs.
        getLog().error(sm.getString("abstractConnectionHandler.error"), e);
      }
      // Make sure socket/processor is removed from the list of current
      // connections
      connections.remove(socket);
      // Don't try to add upgrade processors back into the pool
      if (!(processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor)
          && !processor.isUpgrade()) {
        release(wrapper, processor, true, false);
      }
      return SocketState.CLOSED;
    }
예제 #27
0
    @Override
    protected void doRun() {
      NioChannel socket = socketWrapper.getSocket();
      SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());

      try {
        int handshake = -1;

        try {
          if (key != null) {
            // For STOP there is no point trying to handshake as the
            // Poller has been stopped.
            if (socket.isHandshakeComplete() || event == SocketEvent.STOP) {
              handshake = 0;
            } else {
              handshake = socket.handshake(key.isReadable(), key.isWritable());
              // The handshake process reads/writes from/to the
              // socket. status may therefore be OPEN_WRITE once
              // the handshake completes. However, the handshake
              // happens when the socket is opened so the status
              // must always be OPEN_READ after it completes. It
              // is OK to always set this as it is only used if
              // the handshake completes.
              event = SocketEvent.OPEN_READ;
            }
          }
        } catch (IOException x) {
          handshake = -1;
          if (log.isDebugEnabled()) log.debug("Error during SSL handshake", x);
        } catch (CancelledKeyException ckx) {
          handshake = -1;
        }
        if (handshake == 0) {
          SocketState state = SocketState.OPEN;
          // Process the request from this socket
          if (event == null) {
            state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
          } else {
            state = getHandler().process(socketWrapper, event);
          }
          if (state == SocketState.CLOSED) {
            close(socket, key);
          }
        } else if (handshake == -1) {
          close(socket, key);
        } else if (handshake == SelectionKey.OP_READ) {
          socketWrapper.registerReadInterest();
        } else if (handshake == SelectionKey.OP_WRITE) {
          socketWrapper.registerWriteInterest();
        }
      } catch (CancelledKeyException cx) {
        socket.getPoller().cancelledKey(key);
      } catch (VirtualMachineError vme) {
        ExceptionUtils.handleThrowable(vme);
      } catch (Throwable t) {
        log.error("", t);
        socket.getPoller().cancelledKey(key);
      } finally {
        socketWrapper = null;
        event = null;
        // return to cache
        if (running && !paused) {
          processorCache.push(this);
        }
      }
    }