/** 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; } }
/** * 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; }