@Override
  public HttpServerExchange sendOutOfBandResponse(HttpServerExchange exchange) {
    if (exchange == null || !HttpContinue.requiresContinueResponse(exchange)) {
      throw UndertowMessages.MESSAGES.outOfBandResponseOnlyAllowedFor100Continue();
    }
    final ConduitState state = resetChannel();
    HttpServerExchange newExchange = new HttpServerExchange(this);
    for (HttpString header : exchange.getRequestHeaders().getHeaderNames()) {
      newExchange.getRequestHeaders().putAll(header, exchange.getRequestHeaders().get(header));
    }
    newExchange.setProtocol(exchange.getProtocol());
    newExchange.setRequestMethod(exchange.getRequestMethod());
    newExchange.setRequestPath(exchange.getRequestPath());
    newExchange.getRequestHeaders().put(Headers.CONNECTION, Headers.KEEP_ALIVE.toString());
    newExchange.getRequestHeaders().put(Headers.CONTENT_LENGTH, 0);

    newExchange.addExchangeCompleteListener(
        new ExchangeCompletionListener() {
          @Override
          public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
            restoreChannel(state);
          }
        });
    return newExchange;
  }
  @Override
  public void handleRequest(final HttpServerExchange exchange) {
    final HeaderMap requestHeaders = exchange.getRequestHeaders();
    boolean persistentConnection;
    final boolean hasConnectionHeader = requestHeaders.contains(Headers.CONNECTION);
    final boolean hasTransferEncoding = requestHeaders.contains(Headers.TRANSFER_ENCODING);
    final boolean hasContentLength = requestHeaders.contains(Headers.CONTENT_LENGTH);
    if (exchange.isHttp11()) {
      persistentConnection =
          !(hasConnectionHeader
              && new HttpString(requestHeaders.getFirst(Headers.CONNECTION)).equals(Headers.CLOSE));
    } else if (exchange.isHttp10()) {
      persistentConnection = false;
      if (hasConnectionHeader) {
        for (String value : requestHeaders.get(Headers.CONNECTION)) {
          if (Headers.KEEP_ALIVE.equals(new HttpString(value))) {
            persistentConnection = true;
            break;
          }
        }
      }
    } else {
      log.trace("Connection not persistent");
      persistentConnection = false;
    }
    HttpString transferEncoding = Headers.IDENTITY;
    if (hasTransferEncoding) {
      transferEncoding = new HttpString(requestHeaders.getLast(Headers.TRANSFER_ENCODING));
    }
    if (hasTransferEncoding && !transferEncoding.equals(Headers.IDENTITY)) {
      exchange.addRequestWrapper(chunkedStreamSourceChannelWrapper());
    } else if (hasContentLength) {
      final long contentLength;
      try {
        contentLength = Long.parseLong(requestHeaders.get(Headers.CONTENT_LENGTH).getFirst());
      } catch (NumberFormatException e) {
        log.trace("Invalid request due to unparsable content length");
        // content length is bad; invalid request
        exchange.setResponseCode(400);
        exchange.endExchange();
        return;
      }
      if (contentLength == 0L) {
        log.trace("No content, starting next request");
        // no content - immediately start the next request, returning an empty stream for this one
        exchange.addRequestWrapper(emptyStreamSourceChannelWrapper());
        exchange.terminateRequest();
      } else {
        // fixed-length content - add a wrapper for a fixed-length stream
        exchange.addRequestWrapper(fixedLengthStreamSourceChannelWrapper(contentLength));
      }
    } else if (hasTransferEncoding) {
      if (transferEncoding.equals(Headers.IDENTITY)) {
        log.trace("Connection not persistent (no content length and identity transfer encoding)");
        // make it not persistent
        persistentConnection = false;
      }
    } else if (persistentConnection) {
      // no content - immediately start the next request, returning an empty stream for this one
      exchange.terminateRequest();
      exchange.addRequestWrapper(emptyStreamSourceChannelWrapper());
    }

    exchange.setPersistent(persistentConnection);

    // now the response wrapper, to add in the appropriate connection control headers
    exchange.addResponseWrapper(responseWrapper(persistentConnection));
    HttpHandlers.executeHandler(next, exchange);
  }