void spewInternal() {
      if (pending.remaining() > 0) {
        com.koushikdutta.async.Util.emitAllData(BodySpewer.this, pending);
        if (pending.remaining() > 0) return;
      }

      // fill pending
      try {
        while (pending.remaining() == 0) {
          ByteBuffer buffer = ByteBuffer.allocate(8192);
          int read = cacheResponse.getBody().read(buffer.array());
          if (read == -1) {
            allowEnd = true;
            report(null);
            return;
          }
          buffer.limit(read);
          pending.add(buffer);
          com.koushikdutta.async.Util.emitAllData(BodySpewer.this, pending);
        }
      } catch (IOException e) {
        allowEnd = true;
        report(e);
      }
    }
  @Override
  public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
    try {
      ByteBufferList transformed = new ByteBufferList();
      ByteBuffer output = ByteBuffer.allocate(bb.remaining() * 2);
      int totalInflated = 0;
      int totalRead = 0;
      while (bb.size() > 0) {
        ByteBuffer b = bb.remove();
        if (b.hasRemaining()) {
          totalRead = +b.remaining();
          mInflater.setInput(b.array(), b.arrayOffset() + b.position(), b.remaining());
          do {
            int inflated =
                mInflater.inflate(
                    output.array(), output.arrayOffset() + output.position(), output.remaining());
            totalInflated += inflated;
            output.position(output.position() + inflated);
            if (!output.hasRemaining()) {
              output.limit(output.position());
              output.position(0);
              transformed.add(output);
              Assert.assertNotSame(totalRead, 0);
              int newSize = output.capacity() * 2;
              output = ByteBuffer.allocate(newSize);
            }
          } while (!mInflater.needsInput() && !mInflater.finished());
        }
      }
      output.limit(output.position());
      output.position(0);
      transformed.add(output);

      Util.emitAllData(this, transformed);
    } catch (Exception ex) {
      report(ex);
    }
  }
    @Override
    public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
      if (cached != null) {
        com.koushikdutta.async.Util.emitAllData(this, cached);
        // couldn't emit it all, so just wait for another day...
        if (cached.remaining() > 0) return;
        cached = null;
      }

      // write to cache... any data not consumed needs to be retained for the next callback
      try {
        if (cacheRequest != null) {
          OutputStream outputStream = cacheRequest.getBody();
          if (outputStream != null) {
            int count = bb.size();
            for (int i = 0; i < count; i++) {
              ByteBuffer b = bb.remove();
              outputStream.write(b.array(), b.arrayOffset() + b.position(), b.remaining());
              bb.add(b);
            }
          } else {
            abort();
          }
        }
      } catch (Exception e) {
        abort();
      }

      super.onDataAvailable(emitter, bb);

      if (cacheRequest != null && bb.remaining() > 0) {
        cached = new ByteBufferList();
        cached.add(bb);
        bb.clear();
      }
    }