/**
  * Adds a {@link ChannelWrapper} to the request wrapper chain.
  *
  * @param wrapper the wrapper
  */
 public void addRequestWrapper(final ChannelWrapper<StreamSourceChannel> wrapper) {
   ChannelWrapper[] oldVal;
   ChannelWrapper[] newVal;
   int oldLen;
   do {
     oldVal = requestWrappers;
     if (oldVal == null) {
       throw UndertowMessages.MESSAGES.requestChannelAlreadyProvided();
     }
     oldLen = oldVal.length;
     newVal = Arrays.copyOf(oldVal, oldLen + 1);
     newVal[oldLen] = wrapper;
   } while (!requestWrappersUpdater.compareAndSet(this, oldVal, newVal));
 }
    @Override
    public FormData parseBlocking() throws IOException {
      final FormData existing = exchange.getAttachment(FORM_DATA);
      if (existing != null) {
        return existing;
      }

      StreamSourceChannel channel = exchange.getRequestChannel();
      if (channel == null) {
        throw new IOException(UndertowMessages.MESSAGES.requestChannelAlreadyProvided());
      } else {
        while (state != 4) {
          doParse(channel);
          if (state != 4) {
            channel.awaitReadable();
          }
        }
      }
      return data;
    }
 @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);
     }
   }
 }