blob: 301a152c0ba4b7407bce3e06fcf69b6240687a2a [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/forensics/crash_reports/crash_server.h"
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include "src/developer/forensics/crash_reports/sized_data_reader.h"
#include "src/developer/forensics/utils/sized_data.h"
#include "third_party/crashpad/util/net/http_body.h"
#include "third_party/crashpad/util/net/http_headers.h"
#include "third_party/crashpad/util/net/http_multipart_builder.h"
#include "third_party/crashpad/util/net/http_transport.h"
#include "third_party/crashpad/util/net/url.h"
namespace forensics {
namespace crash_reports {
CrashServer::CrashServer(const std::string& url, SnapshotManager* snapshot_manager)
: url_(url), snapshot_manager_(snapshot_manager) {}
bool CrashServer::MakeRequest(const Report& report, std::string* server_report_id) {
std::vector<SizedDataReader> attachment_readers;
attachment_readers.reserve(report.Attachments().size() + 2u /*minidump and snapshot*/);
std::map<std::string, crashpad::FileReaderInterface*> file_readers;
for (const auto& [k, v] : report.Attachments()) {
if (k.empty()) {
continue;
}
attachment_readers.emplace_back(v);
file_readers.emplace(k, &attachment_readers.back());
}
if (report.Minidump().has_value()) {
attachment_readers.emplace_back(report.Minidump().value());
file_readers.emplace("uploadFileMinidump", &attachment_readers.back());
}
// We have to build the MIME multipart message ourselves as all the public Crashpad helpers are
// asynchronous and we won't be able to know the upload status nor the server report ID.
crashpad::HTTPMultipartBuilder http_multipart_builder;
http_multipart_builder.SetGzipEnabled(true);
for (const auto& [key, value] : report.Annotations()) {
http_multipart_builder.SetFormData(key, value);
}
// Add the snapshot archive and annotations.
auto snapshot = snapshot_manager_->GetSnapshot(report.SnapshotUuid());
if (const auto archive = snapshot.LockArchive(); archive) {
attachment_readers.emplace_back(archive->value);
file_readers.emplace(archive->key, &attachment_readers.back());
}
if (const auto annotations = snapshot.LockAnnotations(); annotations) {
for (const auto& [key, value] : *annotations) {
http_multipart_builder.SetFormData(key, value);
}
}
for (const auto& [filename, content] : file_readers) {
http_multipart_builder.SetFileAttachment(filename, filename, content,
"application/octet-stream");
}
crashpad::HTTPHeaders headers;
http_multipart_builder.PopulateContentHeaders(&headers);
std::unique_ptr<crashpad::HTTPTransport> http_transport(crashpad::HTTPTransport::Create());
for (const auto& header : headers) {
http_transport->SetHeader(header.first, header.second);
}
http_transport->SetBodyStream(http_multipart_builder.GetBodyStream());
http_transport->SetTimeout(60.0); // 1 minute.
http_transport->SetURL(url_);
// If the upload is successful, let |snapshot_manager_| know the snapshot isn't needed for this
// report any more.
if (http_transport->ExecuteSynchronously(server_report_id)) {
snapshot_manager_->Release(report.SnapshotUuid());
return true;
}
return false;
}
} // namespace crash_reports
} // namespace forensics