@Override public void run() { handle = null; if (expireTime == -1) { return; } long current = System.currentTimeMillis(); if (current < expireTime) { // timeout has been bumped, re-schedule handle = WorkerUtils.executeAfter( connection.getIoThread(), timeoutCommand, (expireTime - current) + FUZZ_FACTOR, TimeUnit.MILLISECONDS); return; } UndertowLogger.REQUEST_LOGGER.tracef( "Timing out channel %s due to inactivity", connection.getSourceChannel()); IoUtils.safeClose(connection); if (connection.getSourceChannel().isReadResumed()) { ChannelListeners.invokeChannelListener( connection.getSourceChannel(), connection.getSourceChannel().getReadListener()); } if (connection.getSinkChannel().isWriteResumed()) { ChannelListeners.invokeChannelListener( connection.getSinkChannel(), connection.getSinkChannel().getWriteListener()); } }
/** Notification that the current request is finished */ public void requestDone() { connection.getSinkChannel().setConduit(originalSinkConduit); connection.getSourceChannel().setConduit(pushBackStreamSourceConduit); connection.getSinkChannel().suspendWrites(); connection.getSinkChannel().setWriteListener(null); if (anyAreSet(state, CLOSE_REQ)) { currentRequest = null; this.state |= CLOSED; IoUtils.safeClose(connection); } else if (anyAreSet(state, UPGRADE_REQUESTED)) { connection.getSourceChannel().suspendReads(); currentRequest = null; return; } currentRequest = null; HttpClientExchange next = pendingQueue.poll(); if (next == null) { // we resume reads, so if the target goes away we get notified connection.getSourceChannel().setReadListener(clientReadListener); connection.getSourceChannel().resumeReads(); } else { initiateRequest(next); } }
/** * Resets the channel to its original state, effectively disabling all current conduit wrappers. * The current state is encapsulated inside a {@link ConduitState} object that can be used the * restore the channel. * * @return An opaque representation of the previous channel state */ public ConduitState resetChannel() { ConduitState ret = new ConduitState( channel.getSinkChannel().getConduit(), channel.getSourceChannel().getConduit()); channel.getSinkChannel().setConduit(originalSinkConduit); channel.getSourceChannel().setConduit(originalSourceConduit); return ret; }
@Override public void handleEvent(StreamConnection channel) { // set read and write timeouts try { Integer readTimeout = channel.getOption(Options.READ_TIMEOUT); Integer idleTimeout = undertowOptions.get(UndertowOptions.IDLE_TIMEOUT); if ((readTimeout == null || readTimeout <= 0) && idleTimeout != null) { readTimeout = idleTimeout; } else if (readTimeout != null && idleTimeout != null && idleTimeout > 0) { readTimeout = Math.min(readTimeout, idleTimeout); } if (readTimeout != null && readTimeout > 0) { channel .getSourceChannel() .setConduit( new ReadTimeoutStreamSourceConduit( channel.getSourceChannel().getConduit(), channel, this)); } Integer writeTimeout = channel.getOption(Options.WRITE_TIMEOUT); if ((writeTimeout == null || writeTimeout <= 0) && idleTimeout != null) { writeTimeout = idleTimeout; } else if (writeTimeout != null && idleTimeout != null && idleTimeout > 0) { writeTimeout = Math.min(writeTimeout, idleTimeout); } if (writeTimeout != null && writeTimeout > 0) { channel .getSinkChannel() .setConduit( new WriteTimeoutStreamSinkConduit( channel.getSinkChannel().getConduit(), channel, this)); } } catch (IOException e) { IoUtils.safeClose(channel); UndertowLogger.REQUEST_IO_LOGGER.ioException(e); } final PortForwardServerConnection connection = new PortForwardServerConnection(channel, bufferPool, undertowOptions, bufferSize); connection .getWorker() .execute( new Runnable() { @Override public void run() { try { connection.startForwarding( masterPortForwardConnection, urlPath, targetPort, requestId.getAndIncrement()); } catch (IOException e) { } finally { IoUtils.safeClose(connection); } } }); }
@Override public void run() { UndertowLogger.REQUEST_LOGGER.tracef("Timing out channel %s due to inactivity"); IoUtils.safeClose(connection); if (connection.getSourceChannel().isReadResumed()) { ChannelListeners.invokeChannelListener( connection.getSourceChannel(), connection.getSourceChannel().getReadListener()); } if (connection.getSinkChannel().isWriteResumed()) { ChannelListeners.invokeChannelListener( connection.getSinkChannel(), connection.getSinkChannel().getWriteListener()); } }
private void sendBadRequestAndClose(final StreamConnection channel, final Exception exception) { UndertowLogger.REQUEST_IO_LOGGER.failedToParseRequest(exception); channel.getSourceChannel().suspendReads(); new StringWriteChannelListener(BAD_REQUEST) { @Override protected void writeDone(final StreamSinkChannel c) { IoUtils.safeClose(channel); } }.setup(channel.getSinkChannel()); }
public AjpServerConnection( StreamConnection channel, Pool<ByteBuffer> bufferPool, HttpHandler rootHandler, OptionMap undertowOptions, int bufferSize) { super(channel, bufferPool, rootHandler, undertowOptions, bufferSize); this.writeReadyHandler = new WriteReadyHandler.ChannelListenerHandler<ConduitStreamSinkChannel>( channel.getSinkChannel()); }
public HttpServerConnection( StreamConnection channel, final Pool<ByteBuffer> bufferPool, final HttpHandler rootHandler, final OptionMap undertowOptions, final int bufferSize) { this.channel = channel; this.bufferPool = bufferPool; this.rootHandler = rootHandler; this.undertowOptions = undertowOptions; this.bufferSize = bufferSize; closeSetter = ChannelListeners.getDelegatingSetter(channel.getCloseSetter(), this); this.originalSinkConduit = channel.getSinkChannel().getConduit(); this.originalSourceConduit = channel.getSourceChannel().getConduit(); }
HttpClientConnection( final StreamConnection connection, final OptionMap options, final Pool<ByteBuffer> bufferPool) { this.options = options; this.connection = connection; this.pushBackStreamSourceConduit = new PushBackStreamSourceConduit(connection.getSourceChannel().getConduit()); this.connection.getSourceChannel().setConduit(pushBackStreamSourceConduit); this.bufferPool = bufferPool; this.originalSinkConduit = connection.getSinkChannel().getConduit(); connection .getCloseSetter() .set( new ChannelListener<StreamConnection>() { public void handleEvent(StreamConnection channel) { HttpClientConnection.this.state |= CLOSED; ChannelListeners.invokeChannelListener( HttpClientConnection.this, closeSetter.get()); } }); }
/** * Resores the channel conduits to a previous state. * * @see #resetChannel() * @param state The original state */ public void restoreChannel(final ConduitState state) { channel.getSinkChannel().setConduit(state.sink); channel.getSourceChannel().setConduit(state.source); }
private void initiateRequest(HttpClientExchange httpClientExchange) { currentRequest = httpClientExchange; pendingResponse = new HttpResponseBuilder(); ClientRequest request = httpClientExchange.getRequest(); String connectionString = request.getRequestHeaders().getFirst(CONNECTION); if (connectionString != null) { HttpString connectionHttpString = new HttpString(connectionString); if (connectionHttpString.equals(CLOSE)) { state |= CLOSE_REQ; } else if (connectionHttpString.equals(UPGRADE)) { state |= UPGRADE_REQUESTED; } } else if (request.getProtocol() != Protocols.HTTP_1_1) { state |= CLOSE_REQ; } if (request.getRequestHeaders().contains(UPGRADE)) { state |= UPGRADE_REQUESTED; } // setup the client request conduits final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(clientReadListener); sourceChannel.resumeReads(); ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); StreamSinkConduit conduit = originalSinkConduit; conduit = new HttpRequestConduit(conduit, bufferPool, request); String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH); String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING); boolean hasContent = true; if (fixedLengthString != null) { try { long length = Long.parseLong(fixedLengthString); conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest); hasContent = length != 0; } catch (NumberFormatException e) { handleError(new IOException(e)); return; } } else if (transferEncodingString != null) { if (!transferEncodingString .toLowerCase(Locale.ENGLISH) .contains(Headers.CHUNKED.toString())) { handleError( UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString)); return; } conduit = new ChunkedStreamSinkConduit( conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange); } else { conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest); hasContent = false; } sinkChannel.setConduit(conduit); httpClientExchange.invokeReadReadyCallback(httpClientExchange); if (!hasContent) { // if there is no content we flush the response channel. // otherwise it is up to the user try { sinkChannel.shutdownWrites(); if (!sinkChannel.flush()) { sinkChannel.setWriteListener( ChannelListeners.flushingChannelListener( null, new ChannelExceptionHandler<ConduitStreamSinkChannel>() { @Override public void handleException( ConduitStreamSinkChannel channel, IOException exception) { handleError(exception); } })); } } catch (IOException e) { handleError(e); } } else if (!sinkChannel.isWriteResumed()) { try { // TODO: this needs some more thought if (!sinkChannel.flush()) { sinkChannel.setWriteListener( new ChannelListener<ConduitStreamSinkChannel>() { @Override public void handleEvent(ConduitStreamSinkChannel channel) { try { if (channel.flush()) { channel.suspendWrites(); } } catch (IOException e) { handleError(e); } } }); sinkChannel.resumeWrites(); } } catch (IOException e) { handleError(e); } } }