@Override public int read(final byte[] b, final int off, final int len) throws IOException { if (anyAreSet(state, FLAG_CLOSED)) { throw UndertowServletMessages.MESSAGES.streamIsClosed(); } if (anyAreSet(state, FLAG_FINISHED)) { return -1; } ByteBuffer buffer = ByteBuffer.wrap(b, off, len); if (listener == null) { int res = Channels.readBlocking(channel, buffer); if (res == -1) { state |= FLAG_FINISHED; } return res; } else { if (anyAreClear(state, FLAG_READY)) { throw UndertowServletMessages.MESSAGES.streamNotReady(); } int res = channel.read(buffer); if (res == -1) { state |= FLAG_FINISHED; } else if (res == 0) { state &= ~FLAG_READY; channel.resumeReads(); } return res; } }
@Override public void setReadListener(final ReadListener readListener) { if (readListener == null) { throw UndertowServletMessages.MESSAGES.paramCannotBeNull("readListener"); } if (listener != null) { throw UndertowServletMessages.MESSAGES.listenerAlreadySet(); } listener = readListener; channel.getReadSetter().set(new UpgradeServletChannelListener()); channel.resumeReads(); }
@Override public void parse(HttpHandler handler) throws Exception { if (exchange.getAttachment(FORM_DATA) != null) { handler.handleRequest(exchange); return; } this.handler = handler; StreamSourceChannel channel = exchange.getRequestChannel(); if (channel == null) { throw new IOException(UndertowMessages.MESSAGES.requestChannelAlreadyProvided()); } else { doParse(channel); if (state != 4) { channel.getReadSetter().set(this); channel.resumeReads(); } else { exchange.dispatch(SameThreadExecutor.INSTANCE, handler); } } }
@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 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(); }