/**
   * Register requests for tracking, whenever needed.
   *
   * @param request The servlet request to be processed
   * @param response The servlet response to be created
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet error occurs
   */
  @Override
  public void invoke(Request request, Response response) throws IOException, ServletException {
    // Perform the request
    getNext().invoke(request, response);

    if (request.isComet() && !response.isClosed()) {
      // Start tracking this connection, since this is a
      // begin event, and Comet mode is on
      HttpSession session = request.getSession(true);

      // Track the connection for webapp reload
      cometRequests.add(request);

      // Track the connection for session expiration
      synchronized (session) {
        Request[] requests = (Request[]) session.getAttribute(cometRequestsAttribute);
        if (requests == null) {
          requests = new Request[1];
          requests[0] = request;
          session.setAttribute(cometRequestsAttribute, requests);
        } else {
          Request[] newRequests = new Request[requests.length + 1];
          for (int i = 0; i < requests.length; i++) {
            newRequests[i] = requests[i];
          }
          newRequests[requests.length] = request;
          session.setAttribute(cometRequestsAttribute, newRequests);
        }
      }
    }
  }
Beispiel #2
0
  /** Service method. */
  @Override
  public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
      throws Exception {

    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());
    }

    if (connector.getXpoweredBy()) {
      response.addHeader("X-Powered-By", POWERED_BY);
    }

    boolean comet = false;
    boolean async = false;

    try {

      // Parse and set Catalina and configuration specific
      // request parameters
      req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
      boolean postParseSuccess = postParseRequest(req, request, res, response);
      if (postParseSuccess) {
        // check valves if we support async
        request.setAsyncSupported(
            connector.getService().getContainer().getPipeline().isAsyncSupported());
        // Calling the container
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

        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);
          }
        }
      }
      AsyncContextImpl asyncConImpl = (AsyncContextImpl) request.getAsyncContext();
      if (asyncConImpl != null) {
        async = true;
      } else if (!comet) {
        request.finishRequest();
        response.finishResponse();
        if (postParseSuccess && request.getMappingData().context != null) {
          // Log only if processing was invoked.
          // If postParseRequest() failed, it has already logged it.
          // If context is null this was the start of a comet request
          // that failed and has already been logged.
          ((Context) request.getMappingData().context)
              .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false);
        }
        req.action(ActionCode.POST_REQUEST, null);
      }

    } catch (IOException e) {
      // Ignore
    } finally {
      req.getRequestProcessor().setWorkerThreadName(null);
      AtomicBoolean error = new AtomicBoolean(false);
      res.action(ActionCode.IS_ERROR, error);
      // Recycle the wrapper request and response
      if (!comet && !async || error.get()) {
        request.recycle();
        response.recycle();
      } else {
        // Clear converters so that the minimum amount of memory
        // is used by this processor
        request.clearEncoders();
        response.clearEncoders();
      }
    }
  }
Beispiel #3
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;
  }
Beispiel #4
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();
      }
    }
  }
  /**
   * Use events to update the connection state.
   *
   * @param request The servlet request to be processed
   * @param response The servlet response to be created
   * @exception IOException if an input/output error occurs
   * @exception ServletException if a servlet error occurs
   */
  @Override
  public void event(Request request, Response response, CometEvent event)
      throws IOException, ServletException {

    // Perform the request
    boolean ok = false;
    try {
      getNext().event(request, response, event);
      ok = true;
    } finally {
      if (!ok
          || response.isClosed()
          || (event.getEventType() == CometEvent.EventType.END)
          || (event.getEventType() == CometEvent.EventType.ERROR
              && !(event.getEventSubType() == CometEvent.EventSubType.TIMEOUT))) {

        // Remove the connection from webapp reload tracking
        cometRequests.remove(request);

        // Remove connection from session expiration tracking
        // Note: can't get the session if it has been invalidated but
        // OK since session listener will have done clean-up
        HttpSession session = request.getSession(false);
        if (session != null) {
          synchronized (session) {
            Request[] reqs = null;
            try {
              reqs = (Request[]) session.getAttribute(cometRequestsAttribute);
            } catch (IllegalStateException ise) {
              // Ignore - session has been invalidated
              // Listener will have cleaned up
            }
            if (reqs != null) {
              boolean found = false;
              for (int i = 0; !found && (i < reqs.length); i++) {
                found = (reqs[i] == request);
              }
              if (found) {
                if (reqs.length > 1) {
                  Request[] newConnectionInfos = new Request[reqs.length - 1];
                  int pos = 0;
                  for (int i = 0; i < reqs.length; i++) {
                    if (reqs[i] != request) {
                      newConnectionInfos[pos++] = reqs[i];
                    }
                  }
                  try {
                    session.setAttribute(cometRequestsAttribute, newConnectionInfos);
                  } catch (IllegalStateException ise) {
                    // Ignore - session has been invalidated
                    // Listener will have cleaned up
                  }
                } else {
                  try {
                    session.removeAttribute(cometRequestsAttribute);
                  } catch (IllegalStateException ise) {
                    // Ignore - session has been invalidated
                    // Listener will have cleaned up
                  }
                }
              }
            }
          }
        }
      }
    }
  }