File: server_uploader.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (176 lines) | stat: -rw-r--r-- 6,501 bytes parent folder | download | duplicates (6)
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
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/policy/messaging_layer/upload/server_uploader.h"

#include <memory>
#include <utility>
#include <vector>

#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner.h"
#include "base/types/expected.h"
#include "chrome/browser/policy/messaging_layer/util/upload_declarations.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/resources/resource_manager.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status_macros.h"
#include "components/reporting/util/statusor.h"
#include "components/reporting/util/task_runner_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"

namespace reporting {

ServerUploader::ServerUploader(
    bool need_encryption_key,
    int config_file_version,
    std::vector<EncryptedRecord> records,
    ScopedReservation scoped_reservation,
    std::unique_ptr<RecordHandler> handler,
    UploadEnqueuedCallback enqueued_cb,
    ReportSuccessfulUploadCallback report_success_upload_cb,
    EncryptionKeyAttachedCallback encryption_key_attached_cb,
    ConfigFileAttachedCallback config_file_attached_cb,
    CompletionCallback completion_cb,
    scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner)
    : TaskRunnerContext<CompletionResponse>(std::move(completion_cb),
                                            sequenced_task_runner),
      need_encryption_key_(need_encryption_key),
      config_file_version_(config_file_version),
      encrypted_records_(std::move(records)),
      scoped_reservation_(std::move(scoped_reservation)),
      enqueued_cb_(std::move(enqueued_cb)),
      report_success_upload_cb_(std::move(report_success_upload_cb)),
      encryption_key_attached_cb_(std::move(encryption_key_attached_cb)),
      config_file_attached_cb_(std::move(config_file_attached_cb)),
      handler_(std::move(handler)) {
  DETACH_FROM_SEQUENCE(sequence_checker_);
}

ServerUploader::~ServerUploader() = default;

void ServerUploader::OnStart() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!handler_) {
    Finalize(
        base::unexpected(Status(error::INVALID_ARGUMENT, "handler was null")));
    return;
  }
  // Early exit if we don't have any records and do not need encryption key.
  if (encrypted_records_.empty() && !need_encryption_key_) {
    Finalize(base::unexpected(
        Status(error::INVALID_ARGUMENT, "No records received for upload.")));
    return;
  }

  if (!encrypted_records_.empty()) {
    const auto process_status = ProcessRecords();
    if (!process_status.ok()) {
      Finalize(base::unexpected(process_status));
      return;
    }
  }

  HandleRecords();
}

Status ServerUploader::ProcessRecords() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  Status process_status;

  const int64_t expected_generation_id =
      encrypted_records_.front().sequence_information().generation_id();
  int64_t expected_sequencing_id =
      encrypted_records_.front().sequence_information().sequencing_id();

  // Will stop processing records on the first record that fails to pass.
  size_t records_added = 0;
  for (const auto& encrypted_record : encrypted_records_) {
    process_status = IsRecordValid(encrypted_record, expected_generation_id,
                                   expected_sequencing_id);
    if (!process_status.ok()) {
      LOG(ERROR) << "Record was invalid or received out of order";
      break;
    }
    ++records_added;
    ++expected_sequencing_id;
  }

  if (records_added == 0) {
    // No valid records found, report failure.
    return process_status;
  }

  // Some records are valid, discard the rest and continue.
  encrypted_records_.resize(records_added);
  return Status::StatusOK();
}

void ServerUploader::HandleRecords() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  handler_->HandleRecords(
      need_encryption_key_, config_file_version_, std::move(encrypted_records_),
      std::move(scoped_reservation_), std::move(enqueued_cb_),
      base::BindPostTaskToCurrentDefault(
          base::BindOnce(&ServerUploader::Finalize, base::Unretained(this))),
      std::move(encryption_key_attached_cb_),
      std::move(config_file_attached_cb_));
}

void ServerUploader::Finalize(CompletionResponse upload_result) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (enqueued_cb_) {
    // Finalized before upload has been enqueued - make a call now.
    std::move(enqueued_cb_)
        .Run(base::unexpected(
            Status(error::NOT_FOUND, "Upload failed to enqueue")));
  }

  if (upload_result.has_value()) {
    std::move(report_success_upload_cb_)
        .Run(upload_result.value().sequence_information,
             upload_result.value().force_confirm);
  } else {
    // Log any error except those listed below:
    static constexpr std::array<error::Code, 2> kIgnoredCodes = {
        // a transient state for managed device and an uninteresting one for
        // unmanaged ones
        error::NOT_FOUND,
        // too many upload requests, tripped rate limiting and rejecting the
        // upload (it will be resent later, so it does not cause any loss of
        // data)
        error::OUT_OF_RANGE,
    };
    LOG_IF(WARNING,
           !base::Contains(kIgnoredCodes, upload_result.error().code()))
        << upload_result.error();
  }
  Response(upload_result);
}

Status ServerUploader::IsRecordValid(
    const EncryptedRecord& encrypted_record,
    const int64_t expected_generation_id,
    const int64_t expected_sequencing_id) const {
  // Test to ensure all records are in the same generation.
  if (encrypted_record.sequence_information().generation_id() !=
      expected_generation_id) {
    return Status(error::INVALID_ARGUMENT,
                  "Record does not have the correct generation");
  }

  if (encrypted_record.sequence_information().sequencing_id() !=
      expected_sequencing_id) {
    return Status(error::INVALID_ARGUMENT, "Out of order sequencing_id");
  }

  return Status::StatusOK();
}
}  // namespace reporting