@Override
 protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback) {
   try {
     HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
     ByteBufferPool bufferPool = client.getByteBufferPool();
     ByteBuffer chunk = null;
     while (true) {
       ByteBuffer contentBuffer = content.getByteBuffer();
       boolean lastContent = content.isLast();
       HttpGenerator.Result result =
           generator.generateRequest(null, null, chunk, contentBuffer, lastContent);
       switch (result) {
         case NEED_CHUNK:
           {
             chunk = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false);
             break;
           }
         case FLUSH:
           {
             EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
             if (chunk != null)
               endPoint.write(
                   new ByteBufferRecyclerCallback(callback, bufferPool, chunk),
                   chunk,
                   contentBuffer);
             else endPoint.write(callback, contentBuffer);
             return;
           }
         case SHUTDOWN_OUT:
           {
             shutdownOutput();
             break;
           }
         case CONTINUE:
           {
             break;
           }
         case DONE:
           {
             assert generator.isEnd();
             callback.succeeded();
             return;
           }
         default:
           {
             throw new IllegalStateException();
           }
       }
     }
   } catch (Exception x) {
     LOG.debug(x);
     callback.failed(x);
   }
 }
  @Test
  public void testCachedPut() throws Exception {
    HttpFields header = new HttpFields();

    header.put("Connection", "Keep-Alive");
    header.put("tRansfer-EncOding", "CHUNKED");
    header.put("CONTENT-ENCODING", "gZIP");

    ByteBuffer buffer = BufferUtil.allocate(1024);
    BufferUtil.flipToFill(buffer);
    HttpGenerator.putTo(header, buffer);
    BufferUtil.flipToFlush(buffer, 0);
    String out = BufferUtil.toString(buffer).toLowerCase();

    Assert.assertThat(
        out,
        Matchers.containsString(
            (HttpHeader.CONNECTION + ": " + HttpHeaderValue.KEEP_ALIVE).toLowerCase()));
    Assert.assertThat(
        out,
        Matchers.containsString(
            (HttpHeader.TRANSFER_ENCODING + ": " + HttpHeaderValue.CHUNKED).toLowerCase()));
    Assert.assertThat(
        out,
        Matchers.containsString(
            (HttpHeader.CONTENT_ENCODING + ": " + HttpHeaderValue.GZIP).toLowerCase()));
  }
 @Override
 protected RequestState dispose() {
   generator.abort();
   RequestState result = super.dispose();
   shutdownOutput();
   return result;
 }
  /* ------------------------------------------------------------ */
  @Override
  protected void doStart() throws Exception {
    if (getStopAtShutdown()) ShutdownThread.register(this);

    LOG.info("jetty-" + __version);
    HttpGenerator.setServerVersion(__version);
    MultiException mex = new MultiException();

    if (_threadPool == null) setThreadPool(new QueuedThreadPool());

    try {
      super.doStart();
    } catch (Throwable e) {
      mex.add(e);
    }

    if (_connectors != null) {
      for (int i = 0; i < _connectors.length; i++) {
        try {
          _connectors[i].start();
        } catch (Throwable e) {
          mex.add(e);
        }
      }
    }

    if (isDumpAfterStart()) dumpStdErr();

    mex.ifExceptionThrow();
  }
  @Test
  public void testCRLF() throws Exception {
    HttpFields header = new HttpFields();

    header.put("name0", "value\r\n0");
    header.put("name\r\n1", "value1");
    header.put("name:2", "value:\r\n2");

    ByteBuffer buffer = BufferUtil.allocate(1024);
    BufferUtil.flipToFill(buffer);
    HttpGenerator.putTo(header, buffer);
    BufferUtil.flipToFlush(buffer, 0);
    String out = BufferUtil.toString(buffer);
    assertThat(out, containsString("name0: value??0"));
    assertThat(out, containsString("name??1: value1"));
    assertThat(out, containsString("name?2: value:??2"));
  }
  /**
   * Get the inputStream from the connection.
   *
   * <p>If the associated response has the Expect header set to 100 Continue, then accessing the
   * input stream indicates that the handler/servlet is ready for the request body and thus a 100
   * Continue response is sent.
   *
   * @return The input stream for this connection. The stream will be created if it does not already
   *     exist.
   */
  public ServletInputStream getInputStream() throws IOException {
    // If the client is expecting 100 CONTINUE, then send it now.
    if (_expect100Continue) {
      // is content missing?
      if (((HttpParser) _parser).getHeaderBuffer() == null
          || ((HttpParser) _parser).getHeaderBuffer().length() < 2) {
        if (_generator.isCommitted())
          throw new IllegalStateException("Committed before 100 Continues");

        ((HttpGenerator) _generator).send1xx(HttpStatus.CONTINUE_100);
      }
      _expect100Continue = false;
    }

    if (_in == null) _in = new HttpInput(HttpConnection.this);
    return _in;
  }
  @Test
  public void testPutTo() throws Exception {
    HttpFields header = new HttpFields();

    header.put("name0", "value0");
    header.put("name1", "value:A");
    header.add("name1", "value:B");
    header.add("name2", "");

    ByteBuffer buffer = BufferUtil.allocate(1024);
    BufferUtil.flipToFill(buffer);
    HttpGenerator.putTo(header, buffer);
    BufferUtil.flipToFlush(buffer, 0);
    String result = BufferUtil.toString(buffer);

    assertThat(result, Matchers.containsString("name0: value0"));
    assertThat(result, Matchers.containsString("name1: value:A"));
    assertThat(result, Matchers.containsString("name1: value:B"));
  }
  @Override
  protected void sendHeaders(HttpExchange exchange, HttpContent content, Callback callback) {
    Request request = exchange.getRequest();
    ContentProvider requestContent = request.getContent();
    long contentLength = requestContent == null ? -1 : requestContent.getLength();
    String path = request.getPath();
    String query = request.getQuery();
    if (query != null) path += "?" + query;
    HttpGenerator.RequestInfo requestInfo =
        new HttpGenerator.RequestInfo(
            request.getVersion(), request.getHeaders(), contentLength, request.getMethod(), path);

    try {
      HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
      ByteBufferPool bufferPool = client.getByteBufferPool();
      ByteBuffer header = bufferPool.acquire(client.getRequestBufferSize(), false);
      ByteBuffer chunk = null;

      ByteBuffer contentBuffer = null;
      boolean lastContent = false;
      if (!expects100Continue(request)) {
        content.advance();
        contentBuffer = content.getByteBuffer();
        lastContent = content.isLast();
      }
      while (true) {
        HttpGenerator.Result result =
            generator.generateRequest(requestInfo, header, chunk, contentBuffer, lastContent);
        switch (result) {
          case NEED_CHUNK:
            {
              chunk = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false);
              break;
            }
          case FLUSH:
            {
              int size = 1;
              boolean hasChunk = chunk != null;
              if (hasChunk) ++size;
              boolean hasContent = contentBuffer != null;
              if (hasContent) ++size;
              ByteBuffer[] toWrite = new ByteBuffer[size];
              ByteBuffer[] toRecycle = new ByteBuffer[hasChunk ? 2 : 1];
              toWrite[0] = header;
              toRecycle[0] = header;
              if (hasChunk) {
                toWrite[1] = chunk;
                toRecycle[1] = chunk;
              }
              if (hasContent) toWrite[toWrite.length - 1] = contentBuffer;
              EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
              endPoint.write(
                  new ByteBufferRecyclerCallback(callback, bufferPool, toRecycle), toWrite);
              return;
            }
          default:
            {
              throw new IllegalStateException();
            }
        }
      }
    } catch (Exception x) {
      LOG.debug(x);
      callback.failed(x);
    }
  }
 @Override
 protected void reset() {
   generator.reset();
   super.reset();
 }
  @Test
  public void testPOSTRequestNoContent() throws Exception {
    ByteBuffer header = BufferUtil.allocate(2048);
    HttpGenerator gen = new HttpGenerator();

    HttpGenerator.Result result = gen.generateRequest(null, null, null, null, true);
    Assert.assertEquals(HttpGenerator.Result.NEED_INFO, result);
    Assert.assertEquals(HttpGenerator.State.START, gen.getState());

    Info info = new Info("POST", "/index.html");
    info.getFields().add("Host", "something");
    info.getFields().add("User-Agent", "test");
    Assert.assertTrue(!gen.isChunking());

    result = gen.generateRequest(info, null, null, null, true);
    Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result);
    Assert.assertEquals(HttpGenerator.State.START, gen.getState());

    result = gen.generateRequest(info, header, null, null, true);
    Assert.assertEquals(HttpGenerator.Result.FLUSH, result);
    Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
    Assert.assertTrue(!gen.isChunking());
    String out = BufferUtil.toString(header);
    BufferUtil.clear(header);

    result = gen.generateResponse(null, null, null, null, false);
    Assert.assertEquals(HttpGenerator.Result.DONE, result);
    Assert.assertEquals(HttpGenerator.State.END, gen.getState());
    Assert.assertTrue(!gen.isChunking());

    Assert.assertEquals(0, gen.getContentPrepared());
    Assert.assertThat(out, Matchers.containsString("POST /index.html HTTP/1.1"));
    Assert.assertThat(out, Matchers.containsString("Content-Length: 0"));
  }
  @Test
  public void testRequestWithKnownContent() throws Exception {
    String out;
    ByteBuffer header = BufferUtil.allocate(4096);
    ByteBuffer chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
    ByteBuffer content0 = BufferUtil.toBuffer("Hello World. ");
    ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog.");
    HttpGenerator gen = new HttpGenerator();

    HttpGenerator.Result result = gen.generateRequest(null, null, null, content0, false);
    Assert.assertEquals(HttpGenerator.Result.NEED_INFO, result);
    Assert.assertEquals(HttpGenerator.State.START, gen.getState());

    Info info = new Info("POST", "/index.html", 58);
    info.getFields().add("Host", "something");
    info.getFields().add("User-Agent", "test");

    result = gen.generateRequest(info, null, null, content0, false);
    Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result);
    Assert.assertEquals(HttpGenerator.State.START, gen.getState());

    result = gen.generateRequest(info, header, null, content0, false);
    Assert.assertEquals(HttpGenerator.Result.FLUSH, result);
    Assert.assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
    Assert.assertTrue(!gen.isChunking());
    out = BufferUtil.toString(header);
    BufferUtil.clear(header);
    out += BufferUtil.toString(content0);
    BufferUtil.clear(content0);

    result = gen.generateRequest(null, null, null, content1, false);
    Assert.assertEquals(HttpGenerator.Result.FLUSH, result);
    Assert.assertEquals(HttpGenerator.State.COMMITTED, gen.getState());
    Assert.assertTrue(!gen.isChunking());
    out += BufferUtil.toString(content1);
    BufferUtil.clear(content1);

    result = gen.generateResponse(null, null, null, null, true);
    Assert.assertEquals(HttpGenerator.Result.CONTINUE, result);
    Assert.assertEquals(HttpGenerator.State.COMPLETING, gen.getState());
    Assert.assertTrue(!gen.isChunking());

    result = gen.generateResponse(null, null, null, null, true);
    Assert.assertEquals(HttpGenerator.Result.DONE, result);
    Assert.assertEquals(HttpGenerator.State.END, gen.getState());
    out += BufferUtil.toString(chunk);
    BufferUtil.clear(chunk);

    Assert.assertThat(out, Matchers.containsString("POST /index.html HTTP/1.1"));
    Assert.assertThat(out, Matchers.containsString("Host: something"));
    Assert.assertThat(out, Matchers.containsString("Content-Length: 58"));
    Assert.assertThat(
        out,
        Matchers.containsString(
            "\r\n\r\nHello World. The quick brown fox jumped over the lazy dog."));

    Assert.assertEquals(58, gen.getContentPrepared());
  }