@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);
      }
    }
  }