HttpReadListener(final HttpServerConnection connection, final HttpRequestParser parser) {
   this.connection = connection;
   this.parser = parser;
   maxRequestSize =
       connection
           .getUndertowOptions()
           .get(UndertowOptions.MAX_HEADER_SIZE, UndertowOptions.DEFAULT_MAX_HEADER_SIZE);
   this.maxEntitySize = connection.getUndertowOptions().get(UndertowOptions.MAX_ENTITY_SIZE, 0);
 }
  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();
    }
  }