/** Expected to be used by the handler once the processor is no longer required. */
 @Override
 public void release(
     SocketWrapper<NioChannel> socket,
     Processor<NioChannel> processor,
     boolean isSocketClosing,
     boolean addToPoller) {
   processor.recycle(isSocketClosing);
   recycledProcessors.offer(processor);
   if (addToPoller) {
     socket.getSocket().getPoller().add(socket.getSocket());
   }
 }
 @Override
 protected void initSsl(SocketWrapper<NioChannel> socket, Processor<NioChannel> processor) {
   if (proto.isSSLEnabled()
       && (proto.sslImplementation != null)
       && (socket.getSocket() instanceof SecureNioChannel)) {
     SecureNioChannel ch = (SecureNioChannel) socket.getSocket();
     processor.setSslSupport(
         proto.sslImplementation.getSSLSupport(ch.getSslEngine().getSession()));
   } else {
     processor.setSslSupport(null);
   }
 }
    @Override
    protected void longPoll(SocketWrapper<NioChannel> socket, Processor<NioChannel> processor) {

      if (processor.isAsync()) {
        socket.setAsync(true);
      } else {
        // Either:
        //  - this is comet request
        //  - this is an upgraded connection
        //  - the request line/headers have not been completely
        //    read
        socket.getSocket().getPoller().add(socket.getSocket());
      }
    }
 /**
  * Expected to be used by the handler once the processor is no longer required.
  *
  * @param socket
  * @param processor
  * @param isSocketClosing Not used in HTTP
  * @param addToPoller
  */
 @Override
 public void release(
     SocketWrapper<NioChannel> socket,
     Processor<NioChannel> processor,
     boolean isSocketClosing,
     boolean addToPoller) {
   processor.recycle(isSocketClosing);
   recycledProcessors.offer(processor);
   if (addToPoller) {
     // The only time this method is called with addToPoller == true
     // is when the socket is in keep-alive so set the appropriate
     // timeout.
     socket.setTimeout(getProtocol().getKeepAliveTimeout());
     socket.getSocket().getPoller().add(socket.getSocket());
   }
 }
  @Override
  public void init(SocketWrapper<NioChannel> socketWrapper, AbstractEndpoint endpoint)
      throws IOException {

    socket = socketWrapper.getSocket();
    pool = ((NioEndpoint) endpoint).getSelectorPool();
  }
 /** Expected to be used by the Poller to release resources on socket close, errors etc. */
 @Override
 public void release(SocketWrapper<NioChannel> socket) {
   Processor<NioChannel> processor = connections.remove(socket.getSocket());
   if (processor != null) {
     processor.recycle(true);
     recycledProcessors.offer(processor);
   }
 }
 /** Expected to be used by the handler once the processor is no longer required. */
 @Override
 public void release(
     SocketWrapper<Long> socket,
     AjpAprProcessor processor,
     boolean isSocketClosing,
     boolean addToPoller) {
   processor.recycle(isSocketClosing);
   recycledProcessors.offer(processor);
   if (addToPoller) {
     ((AprEndpoint) proto.endpoint).getPoller().add(socket.getSocket().longValue(), true);
   }
 }
  @Override
  protected void setRequestLineReadTimeout() throws IOException {

    /*
     * When there is no data in the buffer and this is not the first
     * request on this connection and timeouts are being used the
     * first read for this request may need a different timeout to
     * take account of time spent waiting for a processing thread.
     *
     * This is a little hacky but better than exposing the socket
     * and the timeout info to the InputBuffer
     */
    if (inputBuffer.lastValid == 0 && socket.getLastAccess() > -1) {
      int firstReadTimeout;
      if (keepAliveTimeout == -1) {
        firstReadTimeout = 0;
      } else {
        long queueTime = System.currentTimeMillis() - socket.getLastAccess();

        if (queueTime >= keepAliveTimeout) {
          // Queued for longer than timeout but there might be
          // data so use shortest possible timeout
          firstReadTimeout = 1;
        } else {
          // Cast is safe since queueTime must be less than
          // keepAliveTimeout which is an int
          firstReadTimeout = keepAliveTimeout - (int) queueTime;
        }
      }
      socket.getSocket().setSoTimeout(firstReadTimeout);
      if (!inputBuffer.fill()) {
        throw new EOFException(sm.getString("iib.eof.error"));
      }
      // Once the first byte has been read, the standard timeout should be
      // used so restore it here.
      socket.getSocket().setSoTimeout(endpoint.getSoTimeout());
    }
  }
  /**
   * Process pipelined HTTP requests using the specified input and output streams.
   *
   * @throws IOException error during an I/O operation
   */
  @Override
  public SocketState process(SocketWrapper<Long> socket) throws IOException {
    RequestInfo rp = getRequest().getRequestProcessor();
    rp.setStage(Constants24.getStageParse());

    // Setting up the socket
    this.setSocketWrapper(socket);
    long socketRef = socket.getSocket().longValue();
    Socket.setrbb(socketRef, inputBuffer);
    Socket.setsbb(socketRef, outputBuffer);
    boolean cping = false;

    boolean keptAlive = false;

    while (!getErrorState().isError() && !getEndpoint().isPaused()) {
      // Parsing the request header
      try {
        // Get first message of the request
        if (!readMessage(getRequestHeaderMessage(), true, keptAlive)) {
          // This means that no data is available right now
          // (long keepalive), so that the processor should be recycled
          // and the method should return true
          break;
        }
        // Check message type, process right away and break if
        // not regular request processing
        int type = getRequestHeaderMessage().getByte();
        if (type == Constants25.getJkAjp13CpingRequest()) {
          if (getEndpoint().isPaused()) {
            recycle(true);
            break;
          }
          cping = true;
          if (Socket.send(socketRef, getPongmessagearray(), 0, getPongmessagearray().length) < 0) {
            setErrorState(ErrorState.CLOSE_NOW, null);
          }
          continue;
        } else if (type != Constants25.getJkAjp13ForwardRequest()) {
          // Unexpected packet type. Unread body packets should have
          // been swallowed in finish().
          if (log.isDebugEnabled()) {
            log.debug("Unexpected message: " + type);
          }
          setErrorState(ErrorState.CLOSE_NOW, null);
          break;
        }
        keptAlive = true;
        getRequest().setStartTime(System.currentTimeMillis());
      } catch (IOException e) {
        setErrorState(ErrorState.CLOSE_NOW, e);
        break;
      } catch (Throwable t) {
        ExceptionUtils2.handleThrowable(t);
        log.debug(getSm().getString("ajpprocessor.header.error"), t);
        // 400 - Bad Request
        getResponse().setStatus(400);
        setErrorState(ErrorState.CLOSE_CLEAN, t);
        getAdapter().log(getRequest(), getResponse(), 0);
      }

      if (!getErrorState().isError()) {
        // Setting up filters, and parse some request headers
        rp.setStage(Constants24.getStagePrepare());
        try {
          prepareRequest();
        } catch (Throwable t) {
          ExceptionUtils2.handleThrowable(t);
          log.debug(getSm().getString("ajpprocessor.request.prepare"), t);
          // 500 - Internal Server Error
          getResponse().setStatus(500);
          setErrorState(ErrorState.CLOSE_CLEAN, t);
          getAdapter().log(getRequest(), getResponse(), 0);
        }
      }

      if (!getErrorState().isError() && !cping && getEndpoint().isPaused()) {
        // 503 - Service unavailable
        getResponse().setStatus(503);
        setErrorState(ErrorState.CLOSE_CLEAN, null);
        getAdapter().log(getRequest(), getResponse(), 0);
      }
      cping = false;

      // Process the request in the adapter
      if (!getErrorState().isError()) {
        try {
          rp.setStage(Constants24.getStageService());
          getAdapter().service(getRequest(), getResponse());
        } catch (InterruptedIOException e) {
          setErrorState(ErrorState.CLOSE_NOW, e);
        } catch (Throwable t) {
          ExceptionUtils2.handleThrowable(t);
          log.error(getSm().getString("ajpprocessor.request.process"), t);
          // 500 - Internal Server Error
          getResponse().setStatus(500);
          setErrorState(ErrorState.CLOSE_CLEAN, t);
          getAdapter().log(getRequest(), getResponse(), 0);
        }
      }

      if (isAsync() && !getErrorState().isError()) {
        break;
      }

      // Finish the response if not done yet
      if (!isFinished() && getErrorState().isIoAllowed()) {
        try {
          finish();
        } catch (Throwable t) {
          ExceptionUtils2.handleThrowable(t);
          setErrorState(ErrorState.CLOSE_NOW, t);
        }
      }

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

      rp.setStage(Constants24.getStageKeepalive());
      recycle(false);
    }

    rp.setStage(Constants24.getStageEnded());

    if (!getErrorState().isError() && !getEndpoint().isPaused()) {
      if (isAsync()) {
        return SocketState.LONG;
      } else {
        return SocketState.OPEN;
      }
    } else {
      return SocketState.CLOSED;
    }
  }
Beispiel #10
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;
    }
  }
    @Override
    public SocketState process(SocketWrapper<Socket> socket, SocketStatus status) {

      spdyContext.getNetSupport().onAccept(socket.getSocket());
      return SocketState.CLOSED;
    }
  /**
   * Send an action to the connector.
   *
   * @param actionCode Type of the action
   * @param param Action parameter
   */
  @Override
  public void actionInternal(ActionCode actionCode, Object param) {

    if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE) {

      try {
        if (sslSupport != null) {
          Object sslO = sslSupport.getCipherSuite();
          if (sslO != null) request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, sslO);
          sslO = sslSupport.getPeerCertificateChain(false);
          if (sslO != null) request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO);
          sslO = sslSupport.getKeySize();
          if (sslO != null) request.setAttribute(SSLSupport.KEY_SIZE_KEY, sslO);
          sslO = sslSupport.getSessionId();
          if (sslO != null) request.setAttribute(SSLSupport.SESSION_ID_KEY, sslO);
          request.setAttribute(SSLSupport.SESSION_MGR, sslSupport);
        }
      } catch (Exception e) {
        log.warn(sm.getString("http11processor.socket.ssl"), e);
      }

    } else if (actionCode == ActionCode.REQ_HOST_ADDR_ATTRIBUTE) {

      if ((remoteAddr == null) && (socket != null)) {
        InetAddress inetAddr = socket.getSocket().getInetAddress();
        if (inetAddr != null) {
          remoteAddr = inetAddr.getHostAddress();
        }
      }
      request.remoteAddr().setString(remoteAddr);

    } else if (actionCode == ActionCode.REQ_LOCAL_NAME_ATTRIBUTE) {

      if ((localName == null) && (socket != null)) {
        InetAddress inetAddr = socket.getSocket().getLocalAddress();
        if (inetAddr != null) {
          localName = inetAddr.getHostName();
        }
      }
      request.localName().setString(localName);

    } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) {

      if ((remoteHost == null) && (socket != null)) {
        InetAddress inetAddr = socket.getSocket().getInetAddress();
        if (inetAddr != null) {
          remoteHost = inetAddr.getHostName();
        }
        if (remoteHost == null) {
          if (remoteAddr != null) {
            remoteHost = remoteAddr;
          } else { // all we can do is punt
            request.remoteHost().recycle();
          }
        }
      }
      request.remoteHost().setString(remoteHost);

    } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) {

      if (localAddr == null) localAddr = socket.getSocket().getLocalAddress().getHostAddress();

      request.localAddr().setString(localAddr);

    } else if (actionCode == ActionCode.REQ_REMOTEPORT_ATTRIBUTE) {

      if ((remotePort == -1) && (socket != null)) {
        remotePort = socket.getSocket().getPort();
      }
      request.setRemotePort(remotePort);

    } else if (actionCode == ActionCode.REQ_LOCALPORT_ATTRIBUTE) {

      if ((localPort == -1) && (socket != null)) {
        localPort = socket.getSocket().getLocalPort();
      }
      request.setLocalPort(localPort);

    } else if (actionCode == ActionCode.REQ_SSL_CERTIFICATE) {
      if (sslSupport != null) {
        /*
         * Consume and buffer the request body, so that it does not
         * interfere with the client's handshake messages
         */
        InputFilter[] inputFilters = inputBuffer.getFilters();
        ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]).setLimit(maxSavePostSize);
        inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
        try {
          Object sslO = sslSupport.getPeerCertificateChain(true);
          if (sslO != null) {
            request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO);
          }
        } catch (Exception e) {
          log.warn(sm.getString("http11processor.socket.ssl"), e);
        }
      }
    } else if (actionCode == ActionCode.ASYNC_COMPLETE) {
      if (asyncStateMachine.asyncComplete()) {
        ((JIoEndpoint) endpoint).processSocketAsync(this.socket, SocketStatus.OPEN);
      }
    } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) {
      if (param == null) return;
      long timeout = ((Long) param).longValue();
      // if we are not piggy backing on a worker thread, set the timeout
      socket.setTimeout(timeout);
    } else if (actionCode == ActionCode.ASYNC_DISPATCH) {
      if (asyncStateMachine.asyncDispatch()) {
        ((JIoEndpoint) endpoint).processSocketAsync(this.socket, SocketStatus.OPEN);
      }
    }
  }
 @Override
 protected void setSocketTimeout(int timeout) throws IOException {
   socket.getSocket().setSoTimeout(timeout);
 }
    @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;
    }