@Override
      public void handleEvent(StreamSourceChannel channel) {
        if (this.subscriptionClosed) {
          return;
        }

        try {
          ByteBuffer buffer = this.pooledBuffer.getBuffer();
          int count;
          do {
            count = channel.read(buffer);
            if (count == 0) {
              return;
            } else if (count == -1) {
              if (buffer.position() > 0) {
                doOnNext(buffer);
              }
              doOnComplete();
            } else {
              if (buffer.remaining() == 0) {
                if (this.demand == 0) {
                  channel.suspendReads();
                }
                doOnNext(buffer);
                if (this.demand > 0) {
                  scheduleNextMessage();
                }
                break;
              }
            }
          } while (count > 0);
        } catch (IOException e) {
          doOnError(e);
        }
      }
 @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;
   }
 }
 void cleanup() {
   // All other cleanup handlers have been called.  We will inspect the state of the exchange
   // and attempt to fix any leftover or broken crap as best as we can.
   //
   // At this point if any channels were not acquired, we know that not even default handlers have
   // handled the request, meaning we basically have no idea what their state is; the response
   // headers
   // may not even be valid.
   //
   // The only thing we can do is to determine if the request and reply were both terminated; if
   // not,
   // consume the request body nicely, send whatever HTTP response we have, and close down the
   // connection.
   complete = true;
   int oldVal, newVal;
   do {
     oldVal = state;
     if (allAreSet(oldVal, FLAG_CLEANUP)) {
       return;
     }
     newVal = oldVal | FLAG_CLEANUP | FLAG_REQUEST_TERMINATED | FLAG_RESPONSE_TERMINATED;
   } while (!stateUpdater.compareAndSet(this, oldVal, newVal));
   final StreamSourceChannel requestChannel = underlyingRequestChannel;
   final StreamSinkChannel responseChannel = underlyingResponseChannel;
   if (allAreSet(oldVal, FLAG_REQUEST_TERMINATED | FLAG_RESPONSE_TERMINATED)) {
     // we're good; a transfer coding handler took care of things.
     return;
   } else {
     try {
       // we do not attempt to drain the read side, as one of the reasons this could
       // be happening is because the request was too large
       requestChannel.shutdownReads();
       responseChannel.shutdownWrites();
       if (!responseChannel.flush()) {
         responseChannel
             .getWriteSetter()
             .set(
                 ChannelListeners.<StreamSinkChannel>flushingChannelListener(
                     new ChannelListener<StreamSinkChannel>() {
                       public void handleEvent(final StreamSinkChannel channel) {
                         // this shouldn't be necessary...
                         channel.suspendWrites();
                         channel.getWriteSetter().set(null);
                       }
                     },
                     ChannelListeners.closingChannelExceptionHandler()));
         responseChannel.resumeWrites();
       }
     } catch (Throwable t) {
       // All sorts of things could go wrong, from runtime exceptions to java.io.IOException to
       // errors.
       // Just kill off the connection, it's f****d beyond repair.
       safeClose(requestChannel);
       safeClose(responseChannel);
       safeClose(connection);
     }
   }
 }
 @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 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);
     }
   }
 }
 @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();
   }
 }
    @Override
    public void handleEvent(StreamSourceChannel channel) {
      if (this.session.isDisconnected()) {
        if (logger.isDebugEnabled()) {
          logger.debug("SockJS sockJsSession closed, closing response.");
        }
        IoUtils.safeClose(this.connection);
        throw new SockJsException("Session closed.", this.session.getId(), null);
      }

      Object pooled = undertowBufferSupport.allocatePooledResource();
      try {
        int r;
        do {
          ByteBuffer buffer = undertowBufferSupport.getByteBuffer(pooled);
          buffer.clear();
          r = channel.read(buffer);
          buffer.flip();
          if (r == 0) {
            return;
          } else if (r == -1) {
            onSuccess();
          } else {
            while (buffer.hasRemaining()) {
              int b = buffer.get();
              if (b == '\n') {
                handleFrame();
              } else {
                this.outputStream.write(b);
              }
            }
          }
        } while (r > 0);
      } catch (IOException exc) {
        onFailure(exc);
      } finally {
        undertowBufferSupport.closePooledResource(pooled);
      }
    }
Beispiel #9
0
    public void handleEvent(final Channel channel) {
      if (done) {
        if (channel instanceof StreamSinkChannel) {
          ((StreamSinkChannel) channel).suspendWrites();
        } else if (channel instanceof StreamSourceChannel) {
          ((StreamSourceChannel) channel).suspendReads();
        }
        return;
      }
      boolean noWrite = false;
      if (pooledBuffer == null) {
        pooledBuffer = pool.allocate();
        noWrite = true;
      } else if (channel instanceof StreamSourceChannel) {
        noWrite = true; // attempt a read first, as this is a read notification
        pooledBuffer.getResource().compact();
      }

      final ByteBuffer buffer = pooledBuffer.getResource();
      try {
        long read;

        for (; ; ) {
          boolean writeFailed = false;
          // always attempt to write first if we have the buffer
          if (!noWrite) {
            while (buffer.hasRemaining()) {
              final int res;
              try {
                res = sink.write(buffer);
              } catch (IOException e) {
                pooledBuffer.free();
                pooledBuffer = null;
                done = true;
                ChannelListeners.invokeChannelExceptionHandler(sink, writeExceptionHandler, e);
                return;
              }
              if (res == 0) {
                writeFailed = true;
                break;
              }
            }
            if (sourceDone && !buffer.hasRemaining()) {
              done = true;
              done(source, sink, sourceListener, sinkListener);
              return;
            }
            buffer.compact();
          }
          noWrite = false;

          if (buffer.hasRemaining() && !sourceDone) {
            try {
              read = source.read(buffer);
              buffer.flip();
            } catch (IOException e) {
              pooledBuffer.free();
              pooledBuffer = null;
              done = true;
              ChannelListeners.invokeChannelExceptionHandler(source, readExceptionHandler, e);
              return;
            }
            if (read == 0) {
              break;
            } else if (read == -1) {
              sourceDone = true;
              if (!buffer.hasRemaining()) {
                done = true;
                done(source, sink, sourceListener, sinkListener);
                return;
              }
            }
          } else {
            buffer.flip();
            if (writeFailed) {
              break;
            }
          }
        }
        // suspend writes if there is nothing to write
        if (!buffer.hasRemaining()) {
          sink.suspendWrites();
        } else if (!sink.isWriteResumed()) {
          sink.resumeWrites();
        }
        // suspend reads if there is nothing to read
        if (buffer.remaining() == buffer.capacity()) {
          source.suspendReads();
        } else if (!source.isReadResumed()) {
          source.resumeReads();
        }
      } finally {
        if (pooledBuffer != null && !buffer.hasRemaining()) {
          pooledBuffer.free();
          pooledBuffer = null;
        }
      }
    }
 public XnioExecutor getReadThread() {
   return underlyingRequestChannel.getReadThread();
 }
  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();
    }
  }
 @Override
 public void close() throws IOException {
   channel.shutdownReads();
   state |= FLAG_FINISHED | FLAG_CLOSED;
 }
 private void doParse(final StreamSourceChannel channel) throws IOException {
   int c = 0;
   final Pooled<ByteBuffer> pooled = exchange.getConnection().getBufferPool().allocate();
   try {
     final ByteBuffer buffer = pooled.getResource();
     do {
       buffer.clear();
       c = channel.read(buffer);
       if (c > 0) {
         buffer.flip();
         while (buffer.hasRemaining()) {
           byte n = buffer.get();
           switch (state) {
             case 0:
               {
                 if (n == '=') {
                   name = builder.toString();
                   builder.setLength(0);
                   state = 2;
                 } else if (n == '&') {
                   data.add(builder.toString(), "");
                   builder.setLength(0);
                   state = 0;
                 } else if (n == '%' || n == '+') {
                   state = 1;
                   builder.append((char) n);
                 } else {
                   builder.append((char) n);
                 }
                 break;
               }
             case 1:
               {
                 if (n == '=') {
                   name = URLDecoder.decode(builder.toString(), charset);
                   builder.setLength(0);
                   state = 2;
                 } else if (n == '&') {
                   data.add(URLDecoder.decode(builder.toString(), charset), "");
                   builder.setLength(0);
                   state = 0;
                 } else {
                   builder.append((char) n);
                 }
                 break;
               }
             case 2:
               {
                 if (n == '&') {
                   data.add(name, builder.toString());
                   builder.setLength(0);
                   state = 0;
                 } else if (n == '%' || n == '+') {
                   state = 3;
                   builder.append((char) n);
                 } else {
                   builder.append((char) n);
                 }
                 break;
               }
             case 3:
               {
                 if (n == '&') {
                   data.add(name, URLDecoder.decode(builder.toString(), charset));
                   builder.setLength(0);
                   state = 0;
                 } else {
                   builder.append((char) n);
                 }
                 break;
               }
           }
         }
       }
     } while (c > 0);
     if (c == -1) {
       if (state == 2) {
         data.add(name, builder.toString());
       } else if (state == 3) {
         data.add(name, URLDecoder.decode(builder.toString(), charset));
       } else if (builder.length() > 0) {
         if (state == 1) {
           data.add(URLDecoder.decode(builder.toString(), charset), "");
         } else {
           data.add(builder.toString(), "");
         }
       }
       state = 4;
       exchange.putAttachment(FORM_DATA, data);
     }
   } finally {
     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();
 }