910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/api/web_request/upload_data_presenter.h"

#include <string_view>
#include <utility>

#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "extensions/browser/api/web_request/form_data_parser.h"
#include "extensions/browser/api/web_request/web_request_api_constants.h"
#include "extensions/buildflags/buildflags.h"
#include "net/base/upload_file_element_reader.h"

static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));

namespace keys = extension_web_request_api_constants;

namespace {

// Takes |dictionary| of <string, list of strings> pairs, and gets the list
// for |key|, creating it if necessary.
base::Value::List& GetOrCreateList(base::Value::Dict& dictionary,
                                   const std::string& key) {
  base::Value::List* list = dictionary.FindList(key);
  if (list) {
    return *list;
  }
  return dictionary.Set(key, base::Value::List())->GetList();
}

}  // namespace

namespace extensions {

namespace subtle {

void AppendKeyValuePair(const char* key,
                        base::Value value,
                        base::Value::List& list) {
  base::Value::Dict dictionary;
  dictionary.Set(key, std::move(value));
  list.Append(std::move(dictionary));
}

}  // namespace subtle

UploadDataPresenter::~UploadDataPresenter() = default;

RawDataPresenter::RawDataPresenter() = default;

RawDataPresenter::~RawDataPresenter() = default;

void RawDataPresenter::FeedBytes(std::string_view bytes) {
  FeedNextBytes(base::as_byte_span(bytes));
}

void RawDataPresenter::FeedFile(const base::FilePath& path) {
  FeedNextFile(path.AsUTF8Unsafe());
}

bool RawDataPresenter::Succeeded() {
  return true;
}

std::optional<base::Value> RawDataPresenter::TakeResult() {
  return base::Value(std::move(list_));
}

void RawDataPresenter::FeedNextBytes(base::span<const uint8_t> bytes) {
  subtle::AppendKeyValuePair(keys::kRequestBodyRawBytesKey, base::Value(bytes),
                             list_);
}

void RawDataPresenter::FeedNextFile(const std::string& filename) {
  // Insert the file path instead of the contents, which may be too large.
  subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
                             base::Value(filename), list_);
}

ParsedDataPresenter::ParsedDataPresenter(
    const net::HttpRequestHeaders& request_headers)
    : parser_(FormDataParser::Create(request_headers)),
      success_(parser_ != nullptr) {
  if (success_) {
    dictionary_.emplace();
  }
}

ParsedDataPresenter::~ParsedDataPresenter() = default;

void ParsedDataPresenter::FeedBytes(std::string_view bytes) {
  if (!success_) {
    return;
  }

  if (!parser_->SetSource(bytes)) {
    Abort();
    return;
  }

  FormDataParser::Result result;
  while (parser_->GetNextNameValue(&result)) {
    base::Value::List& list =
        GetOrCreateList(dictionary_.value(), result.name());
    list.Append(result.take_value());
  }
}

void ParsedDataPresenter::FeedFile(const base::FilePath& path) {}

bool ParsedDataPresenter::Succeeded() {
  if (success_ && !parser_->AllDataReadOK()) {
    Abort();
  }
  return success_;
}

std::optional<base::Value> ParsedDataPresenter::TakeResult() {
  if (!success_) {
    return std::nullopt;
  }
  return base::Value(std::move(dictionary_.value()));
}

// static
std::unique_ptr<ParsedDataPresenter> ParsedDataPresenter::CreateForTests() {
  return base::WrapUnique(
      new ParsedDataPresenter("application/x-www-form-urlencoded"));
}

ParsedDataPresenter::ParsedDataPresenter(const std::string& form_type)
    : parser_(FormDataParser::CreateFromContentTypeHeader(&form_type)),
      success_(parser_.get() != nullptr) {
  if (success_) {
    dictionary_.emplace();
  }
}

void ParsedDataPresenter::Abort() {
  success_ = false;
  dictionary_.reset();
  parser_.reset();
}

}  // namespace extensions