| Index: third_party/crashpad/crashpad/util/net/http_body_gzip_test.cc
|
| diff --git a/third_party/crashpad/crashpad/util/net/http_body_gzip_test.cc b/third_party/crashpad/crashpad/util/net/http_body_gzip_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a7b97b93a15b12700812691b4b1ade56d43304ae
|
| --- /dev/null
|
| +++ b/third_party/crashpad/crashpad/util/net/http_body_gzip_test.cc
|
| @@ -0,0 +1,178 @@
|
| +// Copyright 2017 The Crashpad Authors. All rights reserved.
|
| +//
|
| +// 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 <string.h>
|
| +
|
| +#include <algorithm>
|
| +#include <memory>
|
| +#include <string>
|
| +#include <utility>
|
| +
|
| +#include "base/macros.h"
|
| +#include "base/rand_util.h"
|
| +#include "base/numerics/safe_conversions.h"
|
| +#include "gtest/gtest.h"
|
| +#include "third_party/zlib/zlib_crashpad.h"
|
| +#include "util/misc/zlib.h"
|
| +#include "util/net/http_body.h"
|
| +
|
| +namespace crashpad {
|
| +namespace test {
|
| +namespace {
|
| +
|
| +class ScopedZlibInflateStream {
|
| + public:
|
| + explicit ScopedZlibInflateStream(z_stream* zlib) : zlib_(zlib) {}
|
| + ~ScopedZlibInflateStream() {
|
| + int zr = inflateEnd(zlib_);
|
| + EXPECT_EQ(Z_OK, zr) << "inflateEnd: " << ZlibErrorString(zr);
|
| + }
|
| +
|
| + private:
|
| + z_stream* zlib_; // weak
|
| + DISALLOW_COPY_AND_ASSIGN(ScopedZlibInflateStream);
|
| +};
|
| +
|
| +void GzipInflate(const std::string& compressed,
|
| + std::string* decompressed,
|
| + size_t buf_size) {
|
| + decompressed->clear();
|
| +
|
| + // There’s got to be at least a small buffer.
|
| + buf_size = std::max(buf_size, static_cast<size_t>(1));
|
| +
|
| + std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size]);
|
| + z_stream zlib = {};
|
| + zlib.zalloc = Z_NULL;
|
| + zlib.zfree = Z_NULL;
|
| + zlib.opaque = Z_NULL;
|
| + zlib.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(&compressed[0]));
|
| + zlib.avail_in = base::checked_cast<uInt>(compressed.size());
|
| + zlib.next_out = buf.get();
|
| + zlib.avail_out = base::checked_cast<uInt>(buf_size);
|
| +
|
| + int zr = inflateInit2(&zlib, ZlibWindowBitsWithGzipWrapper(0));
|
| + ASSERT_EQ(Z_OK, zr) << "inflateInit2: " << ZlibErrorString(zr);
|
| + ScopedZlibInflateStream zlib_inflate(&zlib);
|
| +
|
| + zr = inflate(&zlib, Z_FINISH);
|
| + ASSERT_EQ(Z_STREAM_END, zr) << "inflate: " << ZlibErrorString(zr);
|
| +
|
| + ASSERT_LE(zlib.avail_out, buf_size);
|
| + decompressed->assign(reinterpret_cast<char*>(buf.get()),
|
| + buf_size - zlib.avail_out);
|
| +}
|
| +
|
| +void TestGzipDeflateInflate(const std::string& string) {
|
| + std::unique_ptr<HTTPBodyStream> string_stream(
|
| + new StringHTTPBodyStream(string));
|
| + GzipHTTPBodyStream gzip_stream(std::move(string_stream));
|
| +
|
| + // The minimum size of a gzip wrapper per RFC 1952: a 10-byte header and an
|
| + // 8-byte trailer.
|
| + const size_t kGzipHeaderSize = 18;
|
| +
|
| + // Per http://www.zlib.net/zlib_tech.html, in the worst case, zlib will store
|
| + // uncompressed data as-is, at an overhead of 5 bytes per 16384-byte block.
|
| + // Zero-length input will “compress” to a 2-byte zlib stream. Add the overhead
|
| + // of the gzip wrapper, assuming no optional fields are present.
|
| + size_t buf_size =
|
| + string.size() + kGzipHeaderSize +
|
| + (string.empty() ? 2 : (((string.size() + 16383) / 16384) * 5));
|
| + std::unique_ptr<uint8_t[]> buf(new uint8_t[buf_size]);
|
| + FileOperationResult compressed_bytes =
|
| + gzip_stream.GetBytesBuffer(buf.get(), buf_size);
|
| + ASSERT_NE(compressed_bytes, -1);
|
| + ASSERT_LE(static_cast<size_t>(compressed_bytes), buf_size);
|
| +
|
| + // Make sure that the stream is really at EOF.
|
| + uint8_t eof_buf[16];
|
| + ASSERT_EQ(0, gzip_stream.GetBytesBuffer(eof_buf, sizeof(eof_buf)));
|
| +
|
| + std::string compressed(reinterpret_cast<char*>(buf.get()), compressed_bytes);
|
| +
|
| + ASSERT_GE(compressed.size(), kGzipHeaderSize);
|
| + EXPECT_EQ('\37', compressed[0]);
|
| + EXPECT_EQ('\213', compressed[1]);
|
| + EXPECT_EQ(Z_DEFLATED, compressed[2]);
|
| +
|
| + std::string decompressed;
|
| + ASSERT_NO_FATAL_FAILURE(
|
| + GzipInflate(compressed, &decompressed, string.size()));
|
| +
|
| + EXPECT_EQ(string, decompressed);
|
| +
|
| + // In block mode, compression should be identical.
|
| + string_stream.reset(new StringHTTPBodyStream(string));
|
| + GzipHTTPBodyStream block_gzip_stream(std::move(string_stream));
|
| + uint8_t block_buf[4096];
|
| + std::string block_compressed;
|
| + FileOperationResult block_compressed_bytes;
|
| + while ((block_compressed_bytes = block_gzip_stream.GetBytesBuffer(
|
| + block_buf, sizeof(block_buf))) > 0) {
|
| + block_compressed.append(reinterpret_cast<char*>(block_buf),
|
| + block_compressed_bytes);
|
| + }
|
| + ASSERT_EQ(0, block_compressed_bytes);
|
| + EXPECT_EQ(compressed, block_compressed);
|
| +}
|
| +
|
| +std::string MakeString(size_t size) {
|
| + std::string string;
|
| + for (size_t i = 0; i < size; ++i) {
|
| + string.append(1, (i % 256) ^ ((i >> 8) % 256));
|
| + }
|
| + return string;
|
| +}
|
| +
|
| +constexpr size_t kFourKBytes = 4096;
|
| +constexpr size_t kManyBytes = 375017;
|
| +
|
| +TEST(GzipHTTPBodyStream, Empty) {
|
| + TestGzipDeflateInflate(std::string());
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, OneByte) {
|
| + TestGzipDeflateInflate(std::string("Z"));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, FourKBytes_NUL) {
|
| + TestGzipDeflateInflate(std::string(kFourKBytes, '\0'));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, ManyBytes_NUL) {
|
| + TestGzipDeflateInflate(std::string(kManyBytes, '\0'));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, FourKBytes_Deterministic) {
|
| + TestGzipDeflateInflate(MakeString(kFourKBytes));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, ManyBytes_Deterministic) {
|
| + TestGzipDeflateInflate(MakeString(kManyBytes));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, FourKBytes_Random) {
|
| + TestGzipDeflateInflate(base::RandBytesAsString(kFourKBytes));
|
| +}
|
| +
|
| +TEST(GzipHTTPBodyStream, ManyBytes_Random) {
|
| + TestGzipDeflateInflate(base::RandBytesAsString(kManyBytes));
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace test
|
| +} // namespace crashpad
|
|
|