forked from Pissandshittium/pissandshittium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuploader.cc
223 lines (191 loc) · 8.17 KB
/
uploader.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Copyright 2014 The Chromium 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 "components/domain_reliability/uploader.h"
#include <utility>
#include "base/callback.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/logging.h"
#include "base/supports_user_data.h"
#include "components/domain_reliability/util.h"
#include "net/base/elements_upload_data_stream.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
namespace domain_reliability {
namespace {
const char kJsonMimeType[] = "application/json; charset=utf-8";
// Each DR upload is tagged with an instance of this class, which identifies the
// depth of the upload. This is to prevent infinite loops of DR uploads about DR
// uploads, leading to an unbounded number of requests.
// Deeper requests will still generate a report beacon, but they won't trigger a
// separate upload. See DomainReliabilityContext::kMaxUploadDepthToSchedule.
struct UploadDepthData : public base::SupportsUserData::Data {
explicit UploadDepthData(int depth) : depth(depth) {}
// Key that identifies this data within SupportsUserData's map of data.
static const void* const kUserDataKey;
// This is 0 if the report being uploaded does not contain a beacon about a
// DR upload request. Otherwise, it is 1 + the depth of the deepest DR upload
// described in the report.
int depth;
};
const void* const UploadDepthData::kUserDataKey =
&UploadDepthData::kUserDataKey;
} // namespace
class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
public net::URLRequest::Delegate {
public:
DomainReliabilityUploaderImpl(MockableTime* time,
net::URLRequestContext* url_request_context)
: time_(time),
url_request_context_(url_request_context),
discard_uploads_(true),
shutdown_(false),
discarded_upload_count_(0u) {
DCHECK(url_request_context_);
}
~DomainReliabilityUploaderImpl() override {
DCHECK(shutdown_);
}
// DomainReliabilityUploader implementation:
void UploadReport(
const std::string& report_json,
int max_upload_depth,
const GURL& upload_url,
DomainReliabilityUploader::UploadCallback callback) override {
DVLOG(1) << "Uploading report to " << upload_url;
DVLOG(2) << "Report JSON: " << report_json;
if (discard_uploads_)
discarded_upload_count_++;
if (discard_uploads_ || shutdown_) {
DVLOG(1) << "Discarding report instead of uploading.";
UploadResult result;
result.status = UploadResult::SUCCESS;
std::move(callback).Run(result);
return;
}
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("domain_reliability_report_upload",
R"(
semantics {
sender: "Domain Reliability"
description:
"If Chromium has trouble reaching certain Google sites or "
"services, Domain Reliability may report the problems back to "
"Google."
trigger: "Failure to load certain Google sites or services."
data:
"Details of the failed request, including the URL, any IP "
"addresses the browser tried to connect to, error(s) "
"encountered loading the resource, and other connection details."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"Users can enable or disable Domain Reliability on desktop, via "
"toggling 'Automatically send usage statistics and crash reports "
"to Google' in Chromium's settings under Privacy. On ChromeOS, "
"the setting is named 'Automatically send diagnostic and usage "
"data to Google'."
policy_exception_justification: "Not implemented."
})");
std::unique_ptr<net::URLRequest> request =
url_request_context_->CreateRequest(
upload_url, net::RequestPriority::IDLE, this /* delegate */,
traffic_annotation);
request->set_method("POST");
request->set_allow_credentials(false);
request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType,
kJsonMimeType, true /* overwrite */);
std::vector<char> report_data(report_json.begin(), report_json.end());
auto upload_reader =
std::make_unique<net::UploadOwnedBytesElementReader>(&report_data);
request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
std::move(upload_reader), 0 /* identifier */));
request->SetUserData(
UploadDepthData::kUserDataKey,
std::make_unique<UploadDepthData>(max_upload_depth + 1));
UploadMap::iterator it;
bool inserted;
std::tie(it, inserted) = uploads_.insert(
std::make_pair(std::move(request), std::move(callback)));
DCHECK(inserted);
it->first->Start();
}
void SetDiscardUploads(bool discard_uploads) override {
discard_uploads_ = discard_uploads;
DVLOG(1) << "Setting discard_uploads to " << discard_uploads;
}
void Shutdown() override {
DCHECK(!shutdown_);
shutdown_ = true;
uploads_.clear();
}
int GetDiscardedUploadCount() const override {
return discarded_upload_count_;
}
// net::URLRequest::Delegate implementation:
void OnResponseStarted(net::URLRequest* request, int net_error) override {
DCHECK(!shutdown_);
auto request_it = uploads_.find(request);
DCHECK(request_it != uploads_.end());
int http_response_code = -1;
base::TimeDelta retry_after;
if (net_error == net::OK) {
http_response_code = request->GetResponseCode();
std::string retry_after_string;
if (request->response_headers() &&
request->response_headers()->EnumerateHeader(nullptr, "Retry-After",
&retry_after_string)) {
net::HttpUtil::ParseRetryAfterHeader(retry_after_string, time_->Now(),
&retry_after);
}
}
DVLOG(1) << "Upload finished with net error " << net_error
<< ", response code " << http_response_code << ", retry after "
<< retry_after;
std::move(request_it->second)
.Run(GetUploadResultFromResponseDetails(net_error, http_response_code,
retry_after));
uploads_.erase(request_it);
}
// Requests are cancelled in OnResponseStarted() once response headers are
// read, without reading the body, so this is not needed.
void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
NOTREACHED();
}
private:
MockableTime* time_;
net::URLRequestContext* url_request_context_;
// Stores each in-flight upload request with the callback to notify its
// initiating DRContext of its completion.
using UploadMap = std::map<std::unique_ptr<net::URLRequest>,
UploadCallback,
base::UniquePtrComparator>;
UploadMap uploads_;
bool discard_uploads_;
bool shutdown_;
int discarded_upload_count_;
};
DomainReliabilityUploader::DomainReliabilityUploader() {}
DomainReliabilityUploader::~DomainReliabilityUploader() {}
// static
std::unique_ptr<DomainReliabilityUploader> DomainReliabilityUploader::Create(
MockableTime* time,
net::URLRequestContext* url_request_context) {
return std::make_unique<DomainReliabilityUploaderImpl>(time,
url_request_context);
}
// static
int DomainReliabilityUploader::GetURLRequestUploadDepth(
const net::URLRequest& request) {
UploadDepthData* data = static_cast<UploadDepthData*>(
request.GetUserData(UploadDepthData::kUserDataKey));
return data ? data->depth : 0;
}
} // namespace domain_reliability