2022-09-06 19:14:07 -04:00
|
|
|
|
// Copyright 2017 The Crashpad Authors
|
2017-02-15 19:54:19 -05:00
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#include "util/net/http_body_gzip.h"
|
|
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2023-10-18 12:08:10 -07:00
|
|
|
|
#include "base/check_op.h"
|
2017-02-15 19:54:19 -05:00
|
|
|
|
#include "base/logging.h"
|
|
|
|
|
#include "base/numerics/safe_conversions.h"
|
|
|
|
|
#include "third_party/zlib/zlib_crashpad.h"
|
|
|
|
|
#include "util/misc/zlib.h"
|
|
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
|
|
|
|
|
|
GzipHTTPBodyStream::GzipHTTPBodyStream(std::unique_ptr<HTTPBodyStream> source)
|
|
|
|
|
: input_(),
|
|
|
|
|
source_(std::move(source)),
|
|
|
|
|
z_stream_(new z_stream()),
|
|
|
|
|
state_(State::kUninitialized) {}
|
|
|
|
|
|
|
|
|
|
GzipHTTPBodyStream::~GzipHTTPBodyStream() {
|
|
|
|
|
DCHECK(state_ == State::kUninitialized ||
|
|
|
|
|
state_ == State::kFinished ||
|
|
|
|
|
state_ == State::kError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileOperationResult GzipHTTPBodyStream::GetBytesBuffer(uint8_t* buffer,
|
|
|
|
|
size_t max_len) {
|
|
|
|
|
if (state_ == State::kError) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state_ == State::kFinished) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state_ == State::kUninitialized) {
|
|
|
|
|
z_stream_->zalloc = Z_NULL;
|
|
|
|
|
z_stream_->zfree = Z_NULL;
|
|
|
|
|
z_stream_->opaque = Z_NULL;
|
|
|
|
|
|
|
|
|
|
// The default values for zlib’s internal MAX_WBITS and DEF_MEM_LEVEL. These
|
|
|
|
|
// are the values that deflateInit() would use, but they’re not exported
|
|
|
|
|
// from zlib. deflateInit2() is used instead of deflateInit() to get the
|
|
|
|
|
// gzip wrapper.
|
2017-07-25 19:15:48 -04:00
|
|
|
|
constexpr int kZlibMaxWindowBits = 15;
|
|
|
|
|
constexpr int kZlibDefaultMemoryLevel = 8;
|
2017-02-15 19:54:19 -05:00
|
|
|
|
|
|
|
|
|
int zr = deflateInit2(z_stream_.get(),
|
|
|
|
|
Z_DEFAULT_COMPRESSION,
|
|
|
|
|
Z_DEFLATED,
|
|
|
|
|
ZlibWindowBitsWithGzipWrapper(kZlibMaxWindowBits),
|
|
|
|
|
kZlibDefaultMemoryLevel,
|
|
|
|
|
Z_DEFAULT_STRATEGY);
|
|
|
|
|
if (zr != Z_OK) {
|
|
|
|
|
LOG(ERROR) << "deflateInit2: " << ZlibErrorString(zr);
|
|
|
|
|
state_ = State::kError;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state_ = State::kOperating;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
z_stream_->next_out = buffer;
|
|
|
|
|
z_stream_->avail_out = base::saturated_cast<uInt>(max_len);
|
|
|
|
|
|
|
|
|
|
while (state_ != State::kFinished && z_stream_->avail_out > 0) {
|
|
|
|
|
if (state_ != State::kInputEOF && z_stream_->avail_in == 0) {
|
|
|
|
|
FileOperationResult input_bytes =
|
|
|
|
|
source_->GetBytesBuffer(input_, sizeof(input_));
|
|
|
|
|
if (input_bytes == -1) {
|
|
|
|
|
Done(State::kError);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (input_bytes == 0) {
|
|
|
|
|
state_ = State::kInputEOF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
z_stream_->next_in = input_;
|
|
|
|
|
z_stream_->avail_in = base::checked_cast<uInt>(input_bytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zr = deflate(z_stream_.get(),
|
|
|
|
|
state_ == State::kInputEOF ? Z_FINISH : Z_NO_FLUSH);
|
|
|
|
|
if (state_ == State::kInputEOF && zr == Z_STREAM_END) {
|
|
|
|
|
Done(State::kFinished);
|
|
|
|
|
if (state_ == State::kError) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} else if (zr != Z_OK) {
|
|
|
|
|
LOG(ERROR) << "deflate: " << ZlibErrorString(zr);
|
|
|
|
|
Done(State::kError);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DCHECK_LE(z_stream_->avail_out, max_len);
|
|
|
|
|
return max_len - z_stream_->avail_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GzipHTTPBodyStream::Done(State state) {
|
|
|
|
|
DCHECK(state_ == State::kOperating || state_ == State::kInputEOF) << state_;
|
|
|
|
|
DCHECK(state == State::kFinished || state == State::kError) << state;
|
|
|
|
|
|
|
|
|
|
int zr = deflateEnd(z_stream_.get());
|
|
|
|
|
if (zr != Z_OK) {
|
|
|
|
|
LOG(ERROR) << "deflateEnd: " << ZlibErrorString(zr);
|
|
|
|
|
state_ = State::kError;
|
|
|
|
|
} else {
|
|
|
|
|
state_ = state;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace crashpad
|