in tensorflow_serving/util/net_http/compression/gzip_zlib.cc [553:677]
int ZLib::UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen,
int flush_mode) { // Z_SYNC_FLUSH or Z_FINISH
int err = Z_OK;
if (first_chunk_) {
gzip_footer_bytes_ = -1;
// If we haven't read our first chunk of actual compressed data,
// and we're expecting gzip headers, then parse some more bytes
// from the gzip headers.
const Bytef *bodyBegin = nullptr;
GZipHeader::Status status = gzip_header_->ReadMore(
reinterpret_cast<const char *>(source), *sourceLen,
reinterpret_cast<const char **>(&bodyBegin));
switch (status) {
case GZipHeader::INCOMPLETE_HEADER: // don't have the complete header
*destLen = 0;
*sourceLen = 0; // GZipHeader used all the input
return Z_OK;
case GZipHeader::INVALID_HEADER: // bogus header
Reset();
return Z_DATA_ERROR;
case GZipHeader::COMPLETE_HEADER: // we have the full header
*sourceLen -= (bodyBegin - source); // skip past header bytes
source = bodyBegin;
crc_ = crc32(0, nullptr, 0); // initialize CRC
break;
default:
NET_LOG(FATAL, "Unexpected gzip header parsing result: %d", status);
}
} else if (gzip_footer_bytes_ >= 0) {
// We're now just reading the gzip footer. We already read all the data.
if (gzip_footer_bytes_ + *sourceLen > sizeof(gzip_footer_)) {
Reset();
return Z_DATA_ERROR;
}
uLong len = sizeof(gzip_footer_) - gzip_footer_bytes_;
if (len > *sourceLen) len = *sourceLen;
if (len > 0) {
memcpy(gzip_footer_ + gzip_footer_bytes_, source, len);
gzip_footer_bytes_ += len;
}
*sourceLen -= len;
*destLen = 0;
return Z_OK;
}
if ((err = UncompressInit(dest, destLen, source, sourceLen)) != Z_OK) {
NET_LOG(WARNING,
"UncompressInit: Error: %d "
" SourceLen: %zu",
err, *sourceLen);
return err;
}
// This is used to figure out how many output bytes we wrote *this chunk*:
const uLong old_total_out = uncomp_stream_.total_out;
// This is used to figure out how many input bytes we read *this chunk*:
const uLong old_total_in = uncomp_stream_.total_in;
if (first_chunk_) {
first_chunk_ = false; // so we don't do this again
// For the first chunk *only* (to avoid infinite troubles), we let
// there be no actual data to uncompress. This sometimes triggers
// when the input is only the gzip header.
if (*sourceLen == 0) {
*destLen = 0;
return Z_OK;
}
}
// We'll uncompress as much as we can. If we end OK great, otherwise
// if we get an error that seems to be the gzip footer, we store the
// gzip footer and return OK, otherwise we return the error.
// flush_mode is Z_SYNC_FLUSH for chunked mode, Z_FINISH for all mode.
err = inflate(&uncomp_stream_, flush_mode);
// Figure out how many bytes of the input zlib slurped up:
const uLong bytes_read = uncomp_stream_.total_in - old_total_in;
assert((source + bytes_read) <= (source + *sourceLen));
*sourceLen = uncomp_stream_.avail_in;
// Next we look at the footer, if any. Note that we might currently
// have just part of the footer (eg, if this data is arriving over a
// socket). After looking for a footer, log a warning if there is data.
if ((err == Z_STREAM_END) &&
((gzip_footer_bytes_ == -1) ||
(static_cast<size_t>(gzip_footer_bytes_) < sizeof(gzip_footer_))) &&
(uncomp_stream_.avail_in <= sizeof(gzip_footer_))) {
// Store gzip footer bytes so we can check for footer consistency
// in UncompressChunkDone(). (If we have the whole footer, we
// could do the checking here, but we don't to keep consistency
// with CompressChunkDone().)
gzip_footer_bytes_ =
std::min(absl::implicit_cast<size_t>(uncomp_stream_.avail_in),
sizeof(gzip_footer_));
memcpy(gzip_footer_, source + bytes_read, gzip_footer_bytes_);
*sourceLen -= gzip_footer_bytes_;
} else if ((err == Z_STREAM_END || err == Z_OK) // everything went ok
&& uncomp_stream_.avail_in == 0) { // and we read it all
} else if (err == Z_STREAM_END && uncomp_stream_.avail_in > 0) {
UncompressErrorInit();
return Z_DATA_ERROR;
} else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
UncompressErrorInit();
return err;
} else if (uncomp_stream_.avail_out == 0) {
err = Z_BUF_ERROR;
}
assert(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END);
if (err == Z_STREAM_END && !settings_.dont_hide_zstream_end_) err = Z_OK;
// update the crc and other metadata
uncompressed_size_ = uncomp_stream_.total_out;
*destLen = uncomp_stream_.total_out - old_total_out; // size for this call
crc_ = crc32(crc_, dest, *destLen);
return err;
}