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
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
#define EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "extensions/renderer/bindings/api_binding_types.h"
#include "extensions/renderer/bindings/binding_access_checker.h"
#include "v8/include/v8.h"
namespace extensions {
class APITypeReferenceMap;
class ArgumentSpec;
class BindingAccessChecker;
// Whether promises are allowed to be used for a given call to an API.
enum class PromisesAllowed {
kAllowed,
kDisallowed,
};
// A representation of the expected signature for an API, along with the
// ability to match provided arguments and convert them to base::Values.
// This is primarily used for API methods, but can also be used for API event
// signatures.
class APISignature {
public:
// Struct that bundles all the details about an asynchronous return.
struct ReturnsAsync {
ReturnsAsync();
~ReturnsAsync();
// The list of expected arguments for the asynchronous return. Can be
// nullopt if response validation isn't enabled, as it is only used when
// validating a response from the API.
std::optional<std::vector<std::unique_ptr<ArgumentSpec>>> signature;
// Indicates if passing the callback when calling the API is optional for
// contexts or APIs which do not support promises (passing the callback is
// always inheriently optional if promises are supported).
bool optional = false;
// Indicates if this API supports allowing promises for the asynchronous
// return. Note that this is distinct from whether an actual call to the API
// is allowed to use the promise based form, as that also depends on if the
// calling context being checked by the access_checker.
binding::APIPromiseSupport promise_support =
binding::APIPromiseSupport::kUnsupported;
};
APISignature(std::vector<std::unique_ptr<ArgumentSpec>> signature,
std::unique_ptr<APISignature::ReturnsAsync> returns_async,
BindingAccessChecker* access_checker);
APISignature(const APISignature&) = delete;
APISignature& operator=(const APISignature&) = delete;
~APISignature();
// Creates an APISignature object from the raw Value representations of an
// API schema.
static std::unique_ptr<APISignature> CreateFromValues(
const base::Value& specification_list,
const base::Value* returns_async,
BindingAccessChecker* access_checker);
struct V8ParseResult {
// Appease the Chromium style plugin (out of line ctor/dtor).
V8ParseResult();
~V8ParseResult();
V8ParseResult(V8ParseResult&& other);
V8ParseResult& operator=(V8ParseResult&& other);
bool succeeded() const { return arguments.has_value(); }
// The parsed v8 arguments. These may differ from the original v8 arguments
// since it will include null-filled optional arguments. Populated if
// parsing was successful. Note that the callback, if any, is included in
// this list.
std::optional<v8::LocalVector<v8::Value>> arguments;
// Whether the asynchronous response is handled by a callback or a promise.
binding::AsyncResponseType async_type = binding::AsyncResponseType::kNone;
// The parse error, if parsing failed.
std::optional<std::string> error;
};
struct JSONParseResult {
// Appease the Chromium style plugin (out of line ctor/dtor).
JSONParseResult();
~JSONParseResult();
JSONParseResult(JSONParseResult&& other);
JSONParseResult& operator=(JSONParseResult&& other);
bool succeeded() const { return arguments_list.has_value(); }
// The parsed JSON arguments, with null-filled optional arguments filled in.
// Populated if parsing was successful. Does not include the callback (if
// any).
std::optional<base::Value::List> arguments_list;
// The callback, if one was provided.
v8::Local<v8::Function> callback;
// Whether the asynchronous response is handled by a callback or a promise.
binding::AsyncResponseType async_type = binding::AsyncResponseType::kNone;
// The parse error, if parsing failed.
std::optional<std::string> error;
};
// Parses `arguments` against this signature, returning the result and
// performing no argument conversion.
V8ParseResult ParseArgumentsToV8(v8::Local<v8::Context> context,
const v8::LocalVector<v8::Value>& arguments,
const APITypeReferenceMap& type_refs) const;
// Parses `arguments` against this signature, returning the result after
// converting to base::Values.
JSONParseResult ParseArgumentsToJSON(
v8::Local<v8::Context> context,
const v8::LocalVector<v8::Value>& arguments,
const APITypeReferenceMap& type_refs) const;
// Converts `arguments` to base::Values, ignoring the defined signature.
// This is used when custom bindings modify the passed arguments to a form
// that doesn't match the documented signature. Since we ignore the schema,
// this parsing will never fail.
JSONParseResult ConvertArgumentsIgnoringSchema(
v8::Local<v8::Context> context,
const v8::LocalVector<v8::Value>& arguments) const;
// Validates the provided `arguments` as if they were returned as a response
// to an API call. This validation is much stricter than the versions above,
// since response arguments are not allowed to have optional inner parameters.
bool ValidateResponse(v8::Local<v8::Context> context,
const v8::LocalVector<v8::Value>& arguments,
const APITypeReferenceMap& type_refs,
std::string* error) const;
// Same as `ValidateResponse`, but verifies the given `arguments` against the
// `signature_` instead of the `returns_async_` types. This can be used when
// validating that APIs return proper values to an event (which has a
// signature, but no return).
bool ValidateCall(v8::Local<v8::Context> context,
const v8::LocalVector<v8::Value>& arguments,
const APITypeReferenceMap& type_refs,
std::string* error) const;
// Returns a developer-readable string of the expected signature. For
// instance, if this signature expects a string 'someStr' and an optional int
// 'someInt', this would return "string someStr, optional integer someInt".
std::string GetExpectedSignature() const;
bool has_async_return() const { return returns_async_ != nullptr; }
bool has_async_return_signature() const {
return has_async_return() && returns_async_->signature.has_value();
}
private:
// Checks if promises are allowed to be used for a call to an API from a given
// `context`.
PromisesAllowed CheckPromisesAllowed(v8::Local<v8::Context> context) const;
// The list of expected arguments for the API signature.
std::vector<std::unique_ptr<ArgumentSpec>> signature_;
// The details of any asynchronous return an API method may have. This will be
// nullptr if the the API doesn't have an asynchronous return.
std::unique_ptr<APISignature::ReturnsAsync> returns_async_;
// The associated access checker; required to outlive this object.
raw_ptr<const BindingAccessChecker, DanglingUntriaged> access_checker_;
// A developer-readable method signature string, lazily set.
mutable std::string expected_signature_;
};
} // namespace extensions
#endif // EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
|