Scanner: Define protos and implement ScannerProvider::Call method.

Includes validation for input and output objects. Has logic to wrap the
protos within a Proto3Any.

Added more tests to cover the InvalidInput, MalformedResponse and
BlockedOutputs errors.

Bug: 363101024
Test: autoninja -C out/Default components_unittests
Change-Id: I32ccc041e256ac0f4e53b68006d64859f2425dd5
Cq-Include-Trybots: luci.chromium.try:linux-chromeos-rel;luci.chrome.try:linux-chromeos-chrome
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5921060
Reviewed-by: Xinglong Luan <[email protected]>
Commit-Queue: Callistus Tan <[email protected]>
Reviewed-by: Michael Cui <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1368101}
diff --git a/components/manta/scanner_provider.cc b/components/manta/scanner_provider.cc
index b7a0fd70..4f053a2f 100644
--- a/components/manta/scanner_provider.cc
+++ b/components/manta/scanner_provider.cc
@@ -6,15 +6,18 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/check.h"
 #include "base/functional/bind.h"
+#include "base/strings/strcat.h"
 #include "base/time/time.h"
 #include "components/endpoint_fetcher/endpoint_fetcher.h"
 #include "components/manta/base_provider.h"
 #include "components/manta/features.h"
 #include "components/manta/manta_service_callbacks.h"
 #include "components/manta/manta_status.h"
+#include "components/manta/proto/common.pb.h"
 #include "components/manta/proto/manta.pb.h"
 #include "components/manta/proto/scanner.pb.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -27,22 +30,78 @@
 constexpr char kOauthConsumerName[] = "manta_scanner";
 constexpr base::TimeDelta kTimeout = base::Seconds(30);
 
+bool IsValidScannerInput(const proto::ScannerInput& scanner_input) {
+  return scanner_input.image().size() > 0;
+}
+
+std::unique_ptr<proto::ScannerOutput> GetScannerOutput(
+    const proto::Response& manta_response) {
+  // There should only be one output data.
+  if (manta_response.output_data_size() != 1) {
+    return nullptr;
+  }
+  const proto::OutputData& output_data = manta_response.output_data(0);
+
+  // There should be a custom proto.
+  if (!output_data.has_custom()) {
+    return nullptr;
+  }
+
+  // The custom proto should be a ScannerOutput.
+  if (output_data.custom().type_url() != kScannerOutputTypeUrl) {
+    return nullptr;
+  }
+
+  const proto::Proto3Any& custom_data = output_data.custom();
+
+  auto scanner_output = std::make_unique<proto::ScannerOutput>();
+  scanner_output->ParseFromString(custom_data.value());
+
+  return scanner_output;
+}
+
 void OnServerResponseOrErrorReceived(
     ScannerProvider::ScannerProtoResponseCallback callback,
     std::unique_ptr<proto::Response> manta_response,
     MantaStatus manta_status) {
+  // Check for Manta error status.
   if (manta_status.status_code != MantaStatusCode::kOk) {
     std::move(callback).Run(nullptr, std::move(manta_status));
     return;
   }
 
-  DCHECK(manta_response != nullptr);
+  // Check for a valid Manta response.
+  if (manta_response == nullptr) {
+    std::move(callback).Run(nullptr, {MantaStatusCode::kMalformedResponse});
+    return;
+  }
 
-  // TODO: b/363101024 - Parse ScannerResponse from manta_response.
-  std::unique_ptr<proto::ScannerResponse> scanner_response =
-      std::make_unique<proto::ScannerResponse>();
+  // Check that the Manta response has output data.
+  if (manta_response->output_data_size() == 0) {
+    std::string message;
 
-  std::move(callback).Run(std::move(scanner_response), std::move(manta_status));
+    // If there are no outputs, the response might have been filtered.
+    if (manta_response->filtered_data_size() > 0 &&
+        manta_response->filtered_data(0).is_output_data()) {
+      message = base::StrCat({"filtered output for: ",
+                              proto::FilteredReason_Name(
+                                  manta_response->filtered_data(0).reason())});
+    }
+    std::move(callback).Run(nullptr,
+                            {MantaStatusCode::kBlockedOutputs, message});
+    return;
+  }
+
+  // Try to extract a ScannerOutput object from the Manta response.
+  std::unique_ptr<proto::ScannerOutput> scanner_output =
+      GetScannerOutput(*manta_response);
+  if (scanner_output == nullptr) {
+    std::move(callback).Run(nullptr, {MantaStatusCode::kMalformedResponse});
+    return;
+  }
+
+  // All checks passed, run callback with valid ScannerOutput.
+  std::move(callback).Run(std::move(scanner_output), std::move(manta_status));
 }
 
 }  // namespace
@@ -56,10 +115,25 @@
 ScannerProvider::~ScannerProvider() = default;
 
 void ScannerProvider::Call(
+    const manta::proto::ScannerInput& scanner_input,
     ScannerProvider::ScannerProtoResponseCallback done_callback) {
+  // Check for valid ScannerInput.
+  if (!IsValidScannerInput(scanner_input)) {
+    std::move(done_callback).Run(nullptr, {MantaStatusCode::kInvalidInput});
+    return;
+  }
+  // Populate Manta request with the specified ScannerInput as the custom input
+  // data.
   proto::Request request;
   request.set_feature_name(proto::FeatureName::CHROMEOS_SCANNER);
 
+  proto::InputData* input_data = request.add_input_data();
+  input_data->set_tag("scanner_input");
+
+  proto::Proto3Any& custom = *input_data->mutable_custom();
+  custom.set_type_url(kScannerInputTypeUrl);
+  custom.set_value(scanner_input.SerializeAsString());
+
   // TODO: b/363101024 - Populate annotation tag.
   RequestInternal(
       GURL{GetProviderEndpoint(features::IsScannerUseProdServerEnabled())},