Skip to content

Commit

Permalink
[symupload] Upload compressed symbol files on Windows
Browse files Browse the repository at this point in the history
When supported at build-time (by defining HAVE_ZLIB and ensuring that
zlib.h is in the include path), use zlib to deflate symbol files before
uploading. In case of failure (or when not supported), fall-back to
uploading the raw data as before.

Bug: chromium:349736158
Change-Id: I9345b87e42a03c87a43247e418b5cc05cd19b2b5
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/5701147
Reviewed-by: Ivan Penkov <[email protected]>
  • Loading branch information
GregTho authored and Ivan Penkov committed Jul 12, 2024
1 parent 2c5ac8a commit 466cc92
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 2 deletions.
69 changes: 68 additions & 1 deletion src/common/windows/http_upload.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@
#include <config.h> // Must come first
#endif

#include <algorithm>

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <wchar.h>
#include <windows.h>

#if defined(HAVE_ZLIB)
#include <zlib.h>
#endif

// Disable exception handler warnings.
#pragma warning(disable:4530)

Expand All @@ -49,6 +56,56 @@ namespace {
using std::ios;
using std::unique_ptr;

// Compresses the contents of `data` into `deflated` using the deflate
// algorithm, if supported. Returns true on success, or false if not supported
// or in case of any error. The contents of `deflated` are undefined in the
// latter case.
bool Deflate(const string& data, string& deflated) {
#if defined(HAVE_ZLIB)
z_stream stream{};

// Start with an output buffer sufficient for 75% compression to avoid
// reallocations.
deflated.resize(data.size() / 4);
stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data.data()));
stream.avail_in = data.size();
stream.next_out = reinterpret_cast<Bytef*>(&deflated[0]);
stream.avail_out = deflated.size();
stream.data_type = Z_TEXT;

// Z_BEST_SPEED is chosen because, in practice, it offers excellent speed with
// comparable compression for the symbol data typically being uploaded.
// Z_BEST_COMPRESSION: 2151202094 bytes compressed 84.27% in 74.440s.
// Z_DEFAULT_COMPRESSION: 2151202094 bytes compressed 84.08% in 36.016s.
// Z_BEST_SPEED: 2151202094 bytes compressed 80.39% in 13.73s.
int result = deflateInit(&stream, Z_BEST_SPEED);
if (result != Z_OK) {
return false;
}

while (true) {
result = deflate(&stream, /*flush=*/Z_FINISH);
if (result == Z_STREAM_END) { // All data processed.
deflated.resize(stream.total_out);
break;
}
if (result != Z_OK && result != Z_BUF_ERROR) {
fwprintf(stderr, L"Compression failed with zlib error %d\n", result);
break; // Error condition.
}
// Grow `deflated` by at least 1k to accept the rest of the data.
deflated.resize(deflated.size() + std::max(stream.avail_in, 1024U));
stream.next_out = reinterpret_cast<Bytef*>(&deflated[stream.total_out]);
stream.avail_out = deflated.size() - stream.total_out;
}
deflateEnd(&stream);

return result == Z_STREAM_END;
#else
return false;
#endif // defined(HAVE_ZLIB)
}

const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";

// Helper class which closes an internet handle when it goes away
Expand Down Expand Up @@ -490,10 +547,20 @@ namespace google_breakpad {
return false;
}

static const wchar_t kNoEncoding[] = L"";
static const wchar_t kDeflateEncoding[] = L"Content-Encoding: deflate\r\n";
const wchar_t* encoding_header = &kNoEncoding[0];
string compressed_body;
if (Deflate(request_body, compressed_body)) {
request_body.swap(compressed_body);
encoding_header = &kDeflateEncoding[0];
} // else deflate unsupported or failed; send the raw data.
string().swap(compressed_body); // Free memory.

return SendRequestInner(
url,
L"PUT",
L"",
encoding_header,
request_body,
timeout_ms,
response_body,
Expand Down
3 changes: 2 additions & 1 deletion src/common/windows/http_upload.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ using std::map;
class HTTPUpload {
public:
// Sends a PUT request containing the data in |path| to the given
// URL.
// URL. The data is encoded via the deflate algorithm, if support for such
// is available at build-time.
// Only HTTP(S) URLs are currently supported. Returns true on success.
// If the request is successful and response_body is non-NULL,
// the response body will be returned in response_body.
Expand Down

0 comments on commit 466cc92

Please sign in to comment.