@Override public void handleEvent(StreamSourceChannel channel) { if (this.subscriptionClosed) { return; } try { ByteBuffer buffer = this.pooledBuffer.getBuffer(); int count; do { count = channel.read(buffer); if (count == 0) { return; } else if (count == -1) { if (buffer.position() > 0) { doOnNext(buffer); } doOnComplete(); } else { if (buffer.remaining() == 0) { if (this.demand == 0) { channel.suspendReads(); } doOnNext(buffer); if (this.demand > 0) { scheduleNextMessage(); } break; } } } while (count > 0); } catch (IOException e) { doOnError(e); } }
@Override public void handleEvent(final StreamSourceChannel channel) { if (anyAreClear(state, FLAG_FINISHED)) { try { state |= FLAG_READY; channel.suspendReads(); listener.onDataAvailable(); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); IoUtils.safeClose(channel); } } if (anyAreSet(state, FLAG_FINISHED) && anyAreClear(state, FLAG_ON_DATA_READ_CALLED)) { state |= FLAG_ON_DATA_READ_CALLED; try { channel.shutdownReads(); listener.onAllDataRead(); } catch (IOException e) { IoUtils.safeClose(channel); } } else if (allAreClear(state, FLAG_FINISHED)) { channel.resumeReads(); } }
public void handleEvent(final Channel channel) { if (done) { if (channel instanceof StreamSinkChannel) { ((StreamSinkChannel) channel).suspendWrites(); } else if (channel instanceof StreamSourceChannel) { ((StreamSourceChannel) channel).suspendReads(); } return; } boolean noWrite = false; if (pooledBuffer == null) { pooledBuffer = pool.allocate(); noWrite = true; } else if (channel instanceof StreamSourceChannel) { noWrite = true; // attempt a read first, as this is a read notification pooledBuffer.getResource().compact(); } final ByteBuffer buffer = pooledBuffer.getResource(); try { long read; for (; ; ) { boolean writeFailed = false; // always attempt to write first if we have the buffer if (!noWrite) { while (buffer.hasRemaining()) { final int res; try { res = sink.write(buffer); } catch (IOException e) { pooledBuffer.free(); pooledBuffer = null; done = true; ChannelListeners.invokeChannelExceptionHandler(sink, writeExceptionHandler, e); return; } if (res == 0) { writeFailed = true; break; } } if (sourceDone && !buffer.hasRemaining()) { done = true; done(source, sink, sourceListener, sinkListener); return; } buffer.compact(); } noWrite = false; if (buffer.hasRemaining() && !sourceDone) { try { read = source.read(buffer); buffer.flip(); } catch (IOException e) { pooledBuffer.free(); pooledBuffer = null; done = true; ChannelListeners.invokeChannelExceptionHandler(source, readExceptionHandler, e); return; } if (read == 0) { break; } else if (read == -1) { sourceDone = true; if (!buffer.hasRemaining()) { done = true; done(source, sink, sourceListener, sinkListener); return; } } } else { buffer.flip(); if (writeFailed) { break; } } } // suspend writes if there is nothing to write if (!buffer.hasRemaining()) { sink.suspendWrites(); } else if (!sink.isWriteResumed()) { sink.resumeWrites(); } // suspend reads if there is nothing to read if (buffer.remaining() == buffer.capacity()) { source.suspendReads(); } else if (!source.isReadResumed()) { source.resumeReads(); } } finally { if (pooledBuffer != null && !buffer.hasRemaining()) { pooledBuffer.free(); pooledBuffer = null; } } }
public void handleEvent(final StreamSourceChannel channel) { Pooled<ByteBuffer> existing = connection.getExtraBytes(); final Pooled<ByteBuffer> pooled = existing == null ? connection.getBufferPool().allocate() : existing; final ByteBuffer buffer = pooled.getResource(); boolean free = true; try { int res; do { if (existing == null) { buffer.clear(); try { res = channel.read(buffer); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.debug("Error reading request", e); IoUtils.safeClose(connection); return; } } else { res = buffer.remaining(); } if (res == 0) { if (!channel.isReadResumed()) { channel.getReadSetter().set(this); channel.resumeReads(); } return; } else if (res == -1) { try { channel.suspendReads(); channel.shutdownReads(); final StreamSinkChannel responseChannel = this.connection.getChannel().getSinkChannel(); responseChannel.shutdownWrites(); // will return false if there's a response queued ahead of this one, so we'll set up a // listener then if (!responseChannel.flush()) { responseChannel .getWriteSetter() .set(ChannelListeners.flushingChannelListener(null, null)); responseChannel.resumeWrites(); } } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.debug("Error reading request", e); // f**k it, it's all ruined IoUtils.safeClose(channel); return; } return; } if (existing != null) { existing = null; connection.setExtraBytes(null); } else { buffer.flip(); } parser.handle(buffer, state, httpServerExchange); if (buffer.hasRemaining()) { free = false; connection.setExtraBytes(pooled); } int total = read + res; read = total; if (read > maxRequestSize) { UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge( connection.getPeerAddress(), maxRequestSize); IoUtils.safeClose(connection); return; } } while (!state.isComplete()); // we remove ourselves as the read listener from the channel; // if the http handler doesn't set any then reads will suspend, which is the right thing to do channel.getReadSetter().set(null); channel.suspendReads(); final HttpServerExchange httpServerExchange = this.httpServerExchange; httpServerExchange.putAttachment( UndertowOptions.ATTACHMENT_KEY, connection.getUndertowOptions()); httpServerExchange.setRequestScheme(connection.getSslSession() != null ? "https" : "http"); this.httpServerExchange = null; HttpTransferEncoding.setupRequest(httpServerExchange); HttpHandlers.executeRootHandler( connection.getRootHandler(), httpServerExchange, Thread.currentThread() instanceof XnioExecutor); } catch (Exception e) { sendBadRequestAndClose(connection.getChannel(), e); return; } finally { if (free) pooled.free(); } }
public void handleEvent(StreamSourceChannel channel) { HttpResponseBuilder builder = pendingResponse; final Pooled<ByteBuffer> pooled = bufferPool.allocate(); final ByteBuffer buffer = pooled.getResource(); boolean free = true; try { if (builder == null) { // read ready when no request pending buffer.clear(); try { int res = channel.read(buffer); if (res == -1) { UndertowLogger.CLIENT_LOGGER.debugf( "Connection to %s was closed by the target server", connection.getPeerAddress()); IoUtils.safeClose(HttpClientConnection.this); } else if (res != 0) { UndertowLogger.CLIENT_LOGGER.debugf( "Target server %s sent unexpected data when no request pending, closing connection", connection.getPeerAddress()); IoUtils.safeClose(HttpClientConnection.this); } // otherwise it is a spurious notification } catch (IOException e) { if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) { UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException"); } safeClose(connection); } return; } final ResponseParseState state = builder.getParseState(); int res; do { buffer.clear(); try { res = channel.read(buffer); } catch (IOException e) { if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) { UndertowLogger.CLIENT_LOGGER.debugf(e, "Connection closed with IOException"); } safeClose(channel); return; } if (res == 0) { if (!channel.isReadResumed()) { channel.getReadSetter().set(this); channel.resumeReads(); } return; } else if (res == -1) { channel.suspendReads(); IoUtils.safeClose(HttpClientConnection.this); try { final StreamSinkChannel requestChannel = connection.getSinkChannel(); requestChannel.shutdownWrites(); // will return false if there's a response queued ahead of this one, so we'll set up a // listener then if (!requestChannel.flush()) { requestChannel .getWriteSetter() .set(ChannelListeners.flushingChannelListener(null, null)); requestChannel.resumeWrites(); } // Cancel the current active request currentRequest.setFailed(new IOException(MESSAGES.connectionClosed())); } catch (IOException e) { if (UndertowLogger.CLIENT_LOGGER.isDebugEnabled()) { UndertowLogger.CLIENT_LOGGER.debugf( e, "Connection closed with IOException when attempting to shut down reads"); } IoUtils.safeClose(channel); // Cancel the current active request currentRequest.setFailed(e); return; } return; } buffer.flip(); HttpResponseParser.INSTANCE.handle(buffer, state, builder); if (buffer.hasRemaining()) { free = false; pushBackStreamSourceConduit.pushBack(pooled); } } while (!state.isComplete()); final ClientResponse response = builder.build(); String connectionString = response.getResponseHeaders().getFirst(CONNECTION); // check if an upgrade worked if (anyAreSet(HttpClientConnection.this.state, UPGRADE_REQUESTED)) { if ((connectionString == null || !UPGRADE.equalToString(connectionString)) && !response.getResponseHeaders().contains(UPGRADE)) { // just unset the upgrade requested flag HttpClientConnection.this.state &= ~UPGRADE_REQUESTED; } } if (connectionString != null) { if (HttpString.tryFromString(connectionString).equals(Headers.CLOSE)) { HttpClientConnection.this.state |= CLOSE_REQ; } } if (builder.getStatusCode() == 100) { pendingResponse = new HttpResponseBuilder(); currentRequest.setContinueResponse(response); } else { prepareResponseChannel(response, currentRequest); channel.getReadSetter().set(null); channel.suspendReads(); pendingResponse = null; currentRequest.setResponse(response); } } catch (Exception e) { UndertowLogger.CLIENT_LOGGER.exceptionProcessingRequest(e); IoUtils.safeClose(connection); currentRequest.setFailed(new IOException(e)); } finally { if (free) pooled.free(); } }
public void setup(StreamSourceChannel channel) { channel.suspendReads(); channel.getReadSetter().set(this); channel.resumeReads(); }