1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/metrics/histogram.h"
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/common/safe_browsing/csd.pb.h"
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "google_apis/google_api_keys.h"
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/base/escape.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/base/load_flags.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/http/http_status_code.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace safe_browsing {
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const char kSbIncidentReportUrl[] =
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    "https://sb-ssl.google.com/safebrowsing/clientreport/incident";
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// This is initialized here rather than in the class definition due to an
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// "extension" in MSVC that defies the standard.
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const int IncidentReportUploaderImpl::kTestUrlFetcherId = 47;
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportUploaderImpl::~IncidentReportUploaderImpl() {
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<IncidentReportUploader> IncidentReportUploaderImpl::UploadReport(
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const OnResultCallback& callback,
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const ClientIncidentReport& report) {
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string post_data;
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!report.SerializeToString(&post_data))
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return scoped_ptr<IncidentReportUploader>();
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return scoped_ptr<IncidentReportUploader>(new IncidentReportUploaderImpl(
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      callback, request_context_getter, post_data));
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)IncidentReportUploaderImpl::IncidentReportUploaderImpl(
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const OnResultCallback& callback,
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& post_data)
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : IncidentReportUploader(callback),
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      url_fetcher_(net::URLFetcher::Create(kTestUrlFetcherId,
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           GetIncidentReportUrl(),
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           net::URLFetcher::POST,
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           this)),
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      time_begin_(base::TimeTicks::Now()) {
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("SBIRS.ReportPayloadSize", post_data.size());
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  url_fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  url_fetcher_->SetAutomaticallyRetryOn5xx(false);
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  url_fetcher_->SetRequestContext(request_context_getter.get());
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  url_fetcher_->SetUploadData("application/octet-stream", post_data);
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  url_fetcher_->Start();
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GURL IncidentReportUploaderImpl::GetIncidentReportUrl() {
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GURL url(kSbIncidentReportUrl);
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string api_key(google_apis::GetAPIKey());
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (api_key.empty())
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return url;
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return url.Resolve("?key=" + net::EscapeQueryParamValue(api_key, true));
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void IncidentReportUploaderImpl::OnURLFetchComplete(
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const net::URLFetcher* source) {
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Take ownership of the fetcher in this scope (source == url_fetcher_).
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher(url_fetcher_.Pass());
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("SBIRS.ReportUploadTime",
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      base::TimeTicks::Now() - time_begin_);
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Result result = UPLOAD_REQUEST_FAILED;
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<ClientIncidentResponse> response;
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (source->GetStatus().is_success() &&
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      source->GetResponseCode() == net::HTTP_OK) {
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string data;
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    source->GetResponseAsString(&data);
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    response.reset(new ClientIncidentResponse());
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!response->ParseFromString(data)) {
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      response.reset();
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result = UPLOAD_INVALID_RESPONSE;
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result = UPLOAD_SUCCESS;
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Callbacks have a tendency to delete the uploader, so no touching anything
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // after this.
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  callback_.Run(result, response.Pass());
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace safe_browsing
100