size_t HTTPTransaction::sendDeferredBody()

in proxygen/lib/http/session/HTTPTransaction.cpp [1087:1155]


size_t HTTPTransaction::sendDeferredBody(uint32_t maxEgress) {
  const int32_t windowAvailable = sendWindow_.getSize();
  const uint32_t sendWindow =
      useFlowControl_
          ? std::min<uint32_t>(maxEgress,
                               windowAvailable > 0 ? windowAvailable : 0)
          : maxEgress;

  // We shouldn't be called if we have no pending body/EOM, egress is paused, or
  // the send window is closed
  const size_t bytesLeft = getOutstandingEgressBodyBytes();
  INVARIANT_RETURN((bytesLeft > 0 || isEgressEOMQueued()) && sendWindow > 0, 0);

  size_t canSend = std::min<size_t>(sendWindow, bytesLeft);
  if (maybeDelayForRateLimit()) {
    // Timeout will call notifyTransportPendingEgress again
    return 0;
  }

  size_t nbytes = 0;
  bool willSendEOM = false;

  if (chunkHeaders_.empty()) {
    if (deferredEgressBody_.chainLength() > 0) {
      INVARIANT_RETURN(deferredBufferMeta_.length == 0, 0);
      std::unique_ptr<IOBuf> body = deferredEgressBody_.split(canSend);
      nbytes = sendBodyNow(std::move(body), canSend, hasPendingEOM());
    }
    if (deferredBufferMeta_.length > 0) {
      INVARIANT_RETURN(delegatedTransactionChecks(), 0);
      nbytes += sendDeferredBufferMeta(canSend);
    }
  } else {
    size_t curLen = 0;
    // This body is expliticly chunked
    while (!chunkHeaders_.empty() && canSend > 0) {
      Chunk& chunk = chunkHeaders_.front();
      if (!chunk.headerSent) {
        nbytes += transport_.sendChunkHeader(this, chunk.length);
        chunk.headerSent = true;
      }
      curLen = std::min<size_t>(chunk.length, canSend);
      std::unique_ptr<folly::IOBuf> cur = deferredEgressBody_.split(curLen);
      VLOG(4) << "sending " << curLen << " fin=false";
      nbytes += sendBodyNow(std::move(cur), curLen, false);
      canSend -= curLen;
      chunk.length -= curLen;
      if (chunk.length == 0) {
        nbytes += transport_.sendChunkTerminator(this);
        chunkHeaders_.pop_front();
      } else {
        DCHECK_EQ(canSend, 0);
      }
    }
    willSendEOM = hasPendingEOM();
  }
  // Send any queued eom
  if (willSendEOM) {
    nbytes += sendEOMNow();
  }

  // Update the handler's pause state
  notifyTransportPendingEgress();

  if (transportCallback_) {
    transportCallback_->bodyBytesGenerated(nbytes);
  }
  return nbytes;
}