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;
}