api_request_handler.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/renderer/bindings/api_request_handler.h"
  5. #include "base/bind.h"
  6. #include "base/guid.h"
  7. #include "base/logging.h"
  8. #include "base/values.h"
  9. #include "content/public/renderer/v8_value_converter.h"
  10. #include "extensions/renderer/bindings/api_binding_util.h"
  11. #include "extensions/renderer/bindings/api_response_validator.h"
  12. #include "extensions/renderer/bindings/exception_handler.h"
  13. #include "extensions/renderer/bindings/js_runner.h"
  14. #include "gin/arguments.h"
  15. #include "gin/converter.h"
  16. #include "gin/data_object_builder.h"
  17. namespace extensions {
  18. // Keys used for passing data back through a custom callback;
  19. constexpr const char kErrorKey[] = "error";
  20. constexpr const char kResolverKey[] = "resolver";
  21. constexpr const char kExceptionHandlerKey[] = "exceptionHandler";
  22. // A helper class to adapt base::Value-style response arguments to v8 arguments
  23. // lazily, or simply return v8 arguments directly (depending on which style of
  24. // arguments were used in construction).
  25. class APIRequestHandler::ArgumentAdapter {
  26. public:
  27. explicit ArgumentAdapter(const base::Value::List* base_argumements);
  28. explicit ArgumentAdapter(
  29. const std::vector<v8::Local<v8::Value>>& v8_arguments);
  30. ArgumentAdapter(const ArgumentAdapter&) = delete;
  31. ArgumentAdapter& operator=(const ArgumentAdapter&) = delete;
  32. ~ArgumentAdapter();
  33. const std::vector<v8::Local<v8::Value>>& GetArguments(
  34. v8::Local<v8::Context> context) const;
  35. private:
  36. const base::Value::List* base_arguments_ = nullptr;
  37. mutable std::vector<v8::Local<v8::Value>> v8_arguments_;
  38. };
  39. APIRequestHandler::ArgumentAdapter::ArgumentAdapter(
  40. const base::Value::List* base_arguments)
  41. : base_arguments_(base_arguments) {}
  42. APIRequestHandler::ArgumentAdapter::ArgumentAdapter(
  43. const std::vector<v8::Local<v8::Value>>& v8_arguments)
  44. : v8_arguments_(v8_arguments) {}
  45. APIRequestHandler::ArgumentAdapter::~ArgumentAdapter() = default;
  46. const std::vector<v8::Local<v8::Value>>&
  47. APIRequestHandler::ArgumentAdapter::GetArguments(
  48. v8::Local<v8::Context> context) const {
  49. v8::Isolate* isolate = context->GetIsolate();
  50. DCHECK(isolate->GetCurrentContext() == context);
  51. if (base_arguments_) {
  52. DCHECK(v8_arguments_.empty())
  53. << "GetArguments() should only be called once.";
  54. std::unique_ptr<content::V8ValueConverter> converter =
  55. content::V8ValueConverter::Create();
  56. v8_arguments_.reserve(base_arguments_->size());
  57. for (const auto& arg : *base_arguments_)
  58. v8_arguments_.push_back(converter->ToV8Value(arg, context));
  59. }
  60. return v8_arguments_;
  61. }
  62. // A helper class to handler delivering the results of an API call to a handler,
  63. // which can be either a callback or a promise.
  64. // TODO(devlin): The overlap in this class for handling a promise vs a callback
  65. // is pretty minimal, leading to a lot of if/else branching. This might be
  66. // cleaner with separate versions for the two cases.
  67. class APIRequestHandler::AsyncResultHandler {
  68. public:
  69. // A callback-based result handler.
  70. AsyncResultHandler(v8::Isolate* isolate,
  71. v8::Local<v8::Function> callback,
  72. v8::Local<v8::Function> custom_callback,
  73. binding::ResultModifierFunction result_modifier,
  74. ExceptionHandler* exception_handler);
  75. // A promise-based result handler.
  76. AsyncResultHandler(v8::Isolate* isolate,
  77. v8::Local<v8::Promise::Resolver> promise_resolver,
  78. v8::Local<v8::Function> custom_callback,
  79. binding::ResultModifierFunction result_modifier);
  80. AsyncResultHandler(const AsyncResultHandler&) = delete;
  81. AsyncResultHandler& operator=(const AsyncResultHandler&) = delete;
  82. ~AsyncResultHandler();
  83. // Resolve the request.
  84. // - Sets last error, if it's not promise-based.
  85. // - If the request had a custom callback, this calls the custom callback,
  86. // with a handle to then resolve the extension's callback or promise.
  87. // - Else, invokes the extension's callback or resolves the promise
  88. // immediately.
  89. void ResolveRequest(v8::Local<v8::Context> context,
  90. APILastError* last_error,
  91. const std::vector<v8::Local<v8::Value>>& response_args,
  92. const std::string& error);
  93. // Returns true if the request handler is using a custom callback.
  94. bool has_custom_callback() const { return !custom_callback_.IsEmpty(); }
  95. private:
  96. // Delivers the result to the promise resolver.
  97. static void ResolvePromise(
  98. v8::Local<v8::Context> context,
  99. const std::vector<v8::Local<v8::Value>>& response_args,
  100. const std::string& error,
  101. v8::Local<v8::Promise::Resolver> resolver);
  102. // Delivers the result to the callback provided by the extension.
  103. static void CallExtensionCallback(
  104. v8::Local<v8::Context> context,
  105. std::vector<v8::Local<v8::Value>> response_args,
  106. v8::Local<v8::Function> extension_callback,
  107. ExceptionHandler* exception_handler);
  108. // Helper function to handle the result after the bindings' custom callback
  109. // has completed.
  110. static void CustomCallbackAdaptor(
  111. const v8::FunctionCallbackInfo<v8::Value>& info);
  112. // Delivers the result to the custom callback.
  113. void CallCustomCallback(
  114. v8::Local<v8::Context> context,
  115. const std::vector<v8::Local<v8::Value>>& response_args,
  116. const std::string& error);
  117. // The type of asynchronous response this handler is for.
  118. const binding::AsyncResponseType async_type_;
  119. // Callback-based handlers. Mutually exclusive with promise-based handlers.
  120. v8::Global<v8::Function> extension_callback_;
  121. // Promise-based handlers. Mutually exclusive with callback-based handlers.
  122. v8::Global<v8::Promise::Resolver> promise_resolver_;
  123. // The ExceptionHandler used to catch any exceptions thrown when handling the
  124. // extension's callback. Only non-null for callback-based requests.
  125. // This is guaranteed to be valid while the AsyncResultHandler is valid
  126. // because the ExceptionHandler lives for the duration of the bindings
  127. // system, similar to the APIRequestHandler (which owns this).
  128. ExceptionHandler* exception_handler_ = nullptr;
  129. // Custom callback handlers.
  130. v8::Global<v8::Function> custom_callback_;
  131. // A OnceCallback that can be used to modify the return arguments.
  132. binding::ResultModifierFunction result_modifier_;
  133. };
  134. APIRequestHandler::AsyncResultHandler::AsyncResultHandler(
  135. v8::Isolate* isolate,
  136. v8::Local<v8::Function> extension_callback,
  137. v8::Local<v8::Function> custom_callback,
  138. binding::ResultModifierFunction result_modifier,
  139. ExceptionHandler* exception_handler)
  140. : async_type_(binding::AsyncResponseType::kCallback),
  141. exception_handler_(exception_handler),
  142. result_modifier_(std::move(result_modifier)) {
  143. DCHECK(!extension_callback.IsEmpty() || !custom_callback.IsEmpty());
  144. DCHECK(exception_handler_);
  145. if (!extension_callback.IsEmpty())
  146. extension_callback_.Reset(isolate, extension_callback);
  147. if (!custom_callback.IsEmpty())
  148. custom_callback_.Reset(isolate, custom_callback);
  149. }
  150. APIRequestHandler::AsyncResultHandler::AsyncResultHandler(
  151. v8::Isolate* isolate,
  152. v8::Local<v8::Promise::Resolver> promise_resolver,
  153. v8::Local<v8::Function> custom_callback,
  154. binding::ResultModifierFunction result_modifier)
  155. : async_type_(binding::AsyncResponseType::kPromise),
  156. result_modifier_(std::move(result_modifier)) {
  157. // NOTE(devlin): We'll need to handle an empty promise resolver if
  158. // v8::Promise::Resolver::New() isn't guaranteed.
  159. DCHECK(!promise_resolver.IsEmpty());
  160. promise_resolver_.Reset(isolate, promise_resolver);
  161. if (!custom_callback.IsEmpty())
  162. custom_callback_.Reset(isolate, custom_callback);
  163. }
  164. APIRequestHandler::AsyncResultHandler::~AsyncResultHandler() {}
  165. void APIRequestHandler::AsyncResultHandler::ResolveRequest(
  166. v8::Local<v8::Context> context,
  167. APILastError* last_error,
  168. const std::vector<v8::Local<v8::Value>>& response_args,
  169. const std::string& error) {
  170. v8::Isolate* isolate = context->GetIsolate();
  171. // Set runtime.lastError if there is an error and this isn't a promise-based
  172. // request (promise-based requests instead reject to indicate failure).
  173. bool set_last_error = promise_resolver_.IsEmpty() && !error.empty();
  174. if (set_last_error) {
  175. last_error->SetError(context, error);
  176. }
  177. // If there is a result modifier for this async request and the response args
  178. // are not empty, run the result modifier and allow it to massage the return
  179. // arguments before we send them back.
  180. // Note: a request can end up with a result modifier and be returning an empty
  181. // set of args if we are responding that an error occurred.
  182. const std::vector<v8::Local<v8::Value>> args =
  183. result_modifier_.is_null() || response_args.empty()
  184. ? response_args
  185. : std::move(result_modifier_)
  186. .Run(response_args, context, async_type_);
  187. if (has_custom_callback()) {
  188. // Custom callback case; the custom callback will invoke a curried-in
  189. // callback, which will trigger the response in the extension (either
  190. // promise or callback).
  191. CallCustomCallback(context, args, error);
  192. } else if (!promise_resolver_.IsEmpty()) { // Promise-based request.
  193. DCHECK(extension_callback_.IsEmpty());
  194. ResolvePromise(context, args, error, promise_resolver_.Get(isolate));
  195. } else { // Callback-based request.
  196. DCHECK(!extension_callback_.IsEmpty());
  197. DCHECK(exception_handler_);
  198. CallExtensionCallback(context, std::move(args),
  199. extension_callback_.Get(isolate), exception_handler_);
  200. }
  201. // Since arbitrary JS was run the context might have been invalidated, so only
  202. // clear last error if the context is still valid.
  203. if (set_last_error && binding::IsContextValid(context))
  204. last_error->ClearError(context, true);
  205. }
  206. // static
  207. void APIRequestHandler::AsyncResultHandler::ResolvePromise(
  208. v8::Local<v8::Context> context,
  209. const std::vector<v8::Local<v8::Value>>& response_args,
  210. const std::string& error,
  211. v8::Local<v8::Promise::Resolver> resolver) {
  212. DCHECK_LE(response_args.size(), 1u);
  213. v8::Isolate* isolate = context->GetIsolate();
  214. v8::MicrotasksScope microtasks_scope(
  215. isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
  216. if (error.empty()) {
  217. v8::Local<v8::Value> result;
  218. if (!response_args.empty())
  219. result = response_args[0];
  220. else
  221. result = v8::Undefined(isolate);
  222. v8::Maybe<bool> promise_result = resolver->Resolve(context, result);
  223. // TODO(devlin): It's potentially possible that this could throw if V8
  224. // is terminating on a worker thread; however, it's unclear what happens in
  225. // that scenario (we may appropriately shutdown the thread, or any future
  226. // access of v8 may cause crashes). Make this a CHECK() to flush out any
  227. // situations in which this is a concern. If there are no crashes after
  228. // some time, we may be able to downgrade this.
  229. CHECK(promise_result.IsJust());
  230. } else {
  231. v8::Local<v8::Value> v8_error =
  232. v8::Exception::Error(gin::StringToV8(isolate, error));
  233. v8::Maybe<bool> promise_result = resolver->Reject(context, v8_error);
  234. // See comment above.
  235. CHECK(promise_result.IsJust());
  236. }
  237. }
  238. // static
  239. void APIRequestHandler::AsyncResultHandler::CallExtensionCallback(
  240. v8::Local<v8::Context> context,
  241. std::vector<v8::Local<v8::Value>> args,
  242. v8::Local<v8::Function> extension_callback,
  243. ExceptionHandler* exception_handler) {
  244. DCHECK(exception_handler);
  245. // TODO(devlin): Integrate the API method name in the error message. This
  246. // will require currying it around a bit more.
  247. exception_handler->RunExtensionCallback(
  248. context, extension_callback, std::move(args), "Error handling response");
  249. }
  250. // static
  251. void APIRequestHandler::AsyncResultHandler::CustomCallbackAdaptor(
  252. const v8::FunctionCallbackInfo<v8::Value>& info) {
  253. gin::Arguments arguments(info);
  254. v8::Isolate* isolate = arguments.isolate();
  255. v8::HandleScope handle_scope(isolate);
  256. v8::Local<v8::Context> context = isolate->GetCurrentContext();
  257. v8::Local<v8::Object> data = info.Data().As<v8::Object>();
  258. v8::Local<v8::Value> resolver =
  259. data->Get(context, gin::StringToSymbol(isolate, kResolverKey))
  260. .ToLocalChecked();
  261. if (resolver->IsFunction()) {
  262. v8::Local<v8::Value> exception_handler_value =
  263. data->Get(context, gin::StringToSymbol(isolate, kExceptionHandlerKey))
  264. .ToLocalChecked();
  265. ExceptionHandler* exception_handler =
  266. ExceptionHandler::FromV8Wrapper(isolate, exception_handler_value);
  267. // `exception_handler` could be null if the context were invalidated.
  268. // Since this can be invoked arbitrarily from running JS, we need to
  269. // handle this case gracefully.
  270. if (!exception_handler)
  271. return;
  272. CallExtensionCallback(context, arguments.GetAll(),
  273. resolver.As<v8::Function>(), exception_handler);
  274. } else {
  275. v8::Local<v8::Value> error_value =
  276. data->Get(context, gin::StringToSymbol(isolate, kErrorKey))
  277. .ToLocalChecked();
  278. const std::string error = gin::V8ToString(isolate, error_value);
  279. CHECK(resolver->IsPromise());
  280. ResolvePromise(context, arguments.GetAll(), error,
  281. resolver.As<v8::Promise::Resolver>());
  282. }
  283. }
  284. void APIRequestHandler::AsyncResultHandler::CallCustomCallback(
  285. v8::Local<v8::Context> context,
  286. const std::vector<v8::Local<v8::Value>>& response_args,
  287. const std::string& error) {
  288. v8::Isolate* isolate = context->GetIsolate();
  289. v8::Local<v8::Value> callback_to_pass = v8::Undefined(isolate);
  290. if (!extension_callback_.IsEmpty() || !promise_resolver_.IsEmpty()) {
  291. gin::DataObjectBuilder data_builder(isolate);
  292. v8::Local<v8::Value> resolver_value;
  293. if (!promise_resolver_.IsEmpty()) {
  294. resolver_value = promise_resolver_.Get(isolate);
  295. } else {
  296. DCHECK(exception_handler_);
  297. resolver_value = extension_callback_.Get(isolate);
  298. data_builder.Set(kExceptionHandlerKey,
  299. exception_handler_->GetV8Wrapper(isolate));
  300. }
  301. v8::Local<v8::Object> data = data_builder.Set(kResolverKey, resolver_value)
  302. .Set(kErrorKey, error)
  303. .Build();
  304. // Rather than passing the original callback, we create a function which
  305. // calls back to an adpator which will invoke the original callback or
  306. // resolve the promises, depending on the type of request that was made to
  307. // the API.
  308. callback_to_pass = v8::Function::New(context, &CustomCallbackAdaptor, data)
  309. .ToLocalChecked();
  310. }
  311. // Custom callbacks in the JS bindings are called with the arguments of the
  312. // callback function and the response from the API.
  313. std::vector<v8::Local<v8::Value>> custom_callback_args;
  314. custom_callback_args.reserve(1 + response_args.size());
  315. custom_callback_args.push_back(callback_to_pass);
  316. custom_callback_args.insert(custom_callback_args.end(), response_args.begin(),
  317. response_args.end());
  318. JSRunner::Get(context)->RunJSFunction(custom_callback_.Get(isolate), context,
  319. custom_callback_args.size(),
  320. custom_callback_args.data());
  321. }
  322. APIRequestHandler::Request::Request() = default;
  323. APIRequestHandler::Request::~Request() = default;
  324. APIRequestHandler::RequestDetails::RequestDetails(
  325. int request_id,
  326. v8::Local<v8::Promise> promise)
  327. : request_id(request_id), promise(promise) {}
  328. APIRequestHandler::RequestDetails::~RequestDetails() = default;
  329. APIRequestHandler::RequestDetails::RequestDetails(const RequestDetails& other) =
  330. default;
  331. APIRequestHandler::PendingRequest::PendingRequest(
  332. v8::Isolate* isolate,
  333. v8::Local<v8::Context> context,
  334. const std::string& method_name,
  335. std::unique_ptr<AsyncResultHandler> async_handler,
  336. std::unique_ptr<InteractionProvider::Token> gesture_token)
  337. : isolate(isolate),
  338. context(isolate, context),
  339. method_name(method_name),
  340. async_handler(std::move(async_handler)) {
  341. // Only curry the user gesture through if there's something to handle the
  342. // response.
  343. if (this->async_handler)
  344. user_gesture_token = std::move(gesture_token);
  345. }
  346. APIRequestHandler::PendingRequest::~PendingRequest() {}
  347. APIRequestHandler::PendingRequest::PendingRequest(PendingRequest&&) = default;
  348. APIRequestHandler::PendingRequest& APIRequestHandler::PendingRequest::operator=(
  349. PendingRequest&&) = default;
  350. APIRequestHandler::APIRequestHandler(
  351. SendRequestMethod send_request,
  352. APILastError last_error,
  353. ExceptionHandler* exception_handler,
  354. const InteractionProvider* interaction_provider)
  355. : send_request_(std::move(send_request)),
  356. last_error_(std::move(last_error)),
  357. exception_handler_(exception_handler),
  358. interaction_provider_(interaction_provider) {}
  359. APIRequestHandler::~APIRequestHandler() {}
  360. v8::Local<v8::Promise> APIRequestHandler::StartRequest(
  361. v8::Local<v8::Context> context,
  362. const std::string& method,
  363. std::unique_ptr<base::Value> arguments_list,
  364. binding::AsyncResponseType async_type,
  365. v8::Local<v8::Function> callback,
  366. v8::Local<v8::Function> custom_callback,
  367. binding::ResultModifierFunction result_modifier) {
  368. v8::Isolate* isolate = context->GetIsolate();
  369. v8::Local<v8::Promise> promise;
  370. std::unique_ptr<AsyncResultHandler> async_handler =
  371. GetAsyncResultHandler(context, async_type, callback, custom_callback,
  372. std::move(result_modifier), &promise);
  373. DCHECK_EQ(async_type == binding::AsyncResponseType::kPromise,
  374. !promise.IsEmpty());
  375. int request_id = GetNextRequestId();
  376. auto request = std::make_unique<Request>();
  377. request->request_id = request_id;
  378. std::unique_ptr<InteractionProvider::Token> user_gesture_token;
  379. if (async_handler) {
  380. user_gesture_token = interaction_provider_->GetCurrentToken(context);
  381. request->has_async_response_handler = true;
  382. }
  383. pending_requests_.emplace(
  384. request_id,
  385. PendingRequest(isolate, context, method, std::move(async_handler),
  386. std::move(user_gesture_token)));
  387. request->has_user_gesture =
  388. interaction_provider_->HasActiveInteraction(context);
  389. request->arguments_list = std::move(arguments_list);
  390. request->method_name = method;
  391. last_sent_request_id_ = request_id;
  392. send_request_.Run(std::move(request), context);
  393. return promise;
  394. }
  395. void APIRequestHandler::CompleteRequest(int request_id,
  396. const base::Value::List& response_args,
  397. const std::string& error) {
  398. CompleteRequestImpl(request_id, ArgumentAdapter(&response_args), error);
  399. }
  400. void APIRequestHandler::CompleteRequest(
  401. int request_id,
  402. const std::vector<v8::Local<v8::Value>>& response_args,
  403. const std::string& error) {
  404. CompleteRequestImpl(request_id, ArgumentAdapter(response_args), error);
  405. }
  406. APIRequestHandler::RequestDetails APIRequestHandler::AddPendingRequest(
  407. v8::Local<v8::Context> context,
  408. binding::AsyncResponseType async_type,
  409. v8::Local<v8::Function> callback,
  410. binding::ResultModifierFunction result_modifier) {
  411. v8::Isolate* isolate = context->GetIsolate();
  412. v8::Local<v8::Promise> promise;
  413. std::unique_ptr<AsyncResultHandler> async_handler = GetAsyncResultHandler(
  414. context, async_type, callback, v8::Local<v8::Function>(),
  415. std::move(result_modifier), &promise);
  416. DCHECK_EQ(async_type == binding::AsyncResponseType::kPromise,
  417. !promise.IsEmpty());
  418. int request_id = GetNextRequestId();
  419. // NOTE(devlin): We ignore the UserGestureToken for synthesized requests like
  420. // these that aren't sent to the browser. It is the caller's responsibility to
  421. // handle any user gesture behavior. This prevents an issue where messaging
  422. // handling would create an extra scoped user gesture, causing issues. See
  423. // https://crbug.com/921141.
  424. std::unique_ptr<InteractionProvider::Token> null_user_gesture_token;
  425. pending_requests_.emplace(
  426. request_id,
  427. PendingRequest(isolate, context, std::string(), std::move(async_handler),
  428. std::move(null_user_gesture_token)));
  429. return RequestDetails(request_id, promise);
  430. }
  431. void APIRequestHandler::InvalidateContext(v8::Local<v8::Context> context) {
  432. for (auto iter = pending_requests_.begin();
  433. iter != pending_requests_.end();) {
  434. if (iter->second.context == context)
  435. iter = pending_requests_.erase(iter);
  436. else
  437. ++iter;
  438. }
  439. }
  440. void APIRequestHandler::SetResponseValidator(
  441. std::unique_ptr<APIResponseValidator> response_validator) {
  442. DCHECK(!response_validator_);
  443. response_validator_ = std::move(response_validator);
  444. }
  445. std::set<int> APIRequestHandler::GetPendingRequestIdsForTesting() const {
  446. std::set<int> result;
  447. for (const auto& pair : pending_requests_)
  448. result.insert(pair.first);
  449. return result;
  450. }
  451. int APIRequestHandler::GetNextRequestId() {
  452. // The request id is primarily used in the renderer to associate an API
  453. // request with the associated callback, but it's also used in the browser as
  454. // an identifier for the extension function (e.g. by the pageCapture API).
  455. // TODO(devlin): We should probably fix this, since the request id is only
  456. // unique per-isolate, rather than globally.
  457. // TODO(devlin): We could *probably* get away with just using an integer
  458. // here, but it's a little less foolproof. How slow is GenerateGUID? Should
  459. // we use that instead? It means updating the IPC
  460. // (ExtensionHostMsg_Request).
  461. // base::UnguessableToken is another good option.
  462. return next_request_id_++;
  463. }
  464. std::unique_ptr<APIRequestHandler::AsyncResultHandler>
  465. APIRequestHandler::GetAsyncResultHandler(
  466. v8::Local<v8::Context> context,
  467. binding::AsyncResponseType async_type,
  468. v8::Local<v8::Function> extension_callback,
  469. v8::Local<v8::Function> custom_callback,
  470. binding::ResultModifierFunction result_modifier,
  471. v8::Local<v8::Promise>* promise_out) {
  472. v8::Isolate* isolate = context->GetIsolate();
  473. std::unique_ptr<AsyncResultHandler> async_handler;
  474. if (async_type == binding::AsyncResponseType::kPromise) {
  475. DCHECK(extension_callback.IsEmpty())
  476. << "Promise based requests should never be "
  477. "started with a callback being passed in.";
  478. v8::Local<v8::Promise::Resolver> resolver =
  479. v8::Promise::Resolver::New(context).ToLocalChecked();
  480. async_handler = std::make_unique<AsyncResultHandler>(
  481. isolate, resolver, custom_callback, std::move(result_modifier));
  482. *promise_out = resolver->GetPromise();
  483. } else if (!custom_callback.IsEmpty() || !extension_callback.IsEmpty()) {
  484. async_handler = std::make_unique<AsyncResultHandler>(
  485. isolate, extension_callback, custom_callback,
  486. std::move(result_modifier), exception_handler_);
  487. }
  488. return async_handler;
  489. }
  490. void APIRequestHandler::CompleteRequestImpl(int request_id,
  491. const ArgumentAdapter& arguments,
  492. const std::string& error) {
  493. auto iter = pending_requests_.find(request_id);
  494. // The request may have been removed if the context was invalidated before a
  495. // response is ready.
  496. if (iter == pending_requests_.end())
  497. return;
  498. PendingRequest pending_request = std::move(iter->second);
  499. pending_requests_.erase(iter);
  500. v8::Isolate* isolate = pending_request.isolate;
  501. v8::HandleScope handle_scope(isolate);
  502. v8::Local<v8::Context> context = pending_request.context.Get(isolate);
  503. v8::Context::Scope context_scope(context);
  504. if (!pending_request.async_handler) {
  505. // If there's no async handler associated with the request, but there is an
  506. // error, report the error as if it were unchecked.
  507. if (!error.empty()) {
  508. // TODO(devlin): Use pending_requeset.method_name here?
  509. last_error_.ReportUncheckedError(context, error);
  510. }
  511. // No async handler to trigger, so we're done!
  512. return;
  513. }
  514. const std::vector<v8::Local<v8::Value>>& response_args =
  515. arguments.GetArguments(context);
  516. std::unique_ptr<InteractionProvider::Scope> user_gesture;
  517. if (pending_request.user_gesture_token) {
  518. user_gesture = interaction_provider_->CreateScopedInteraction(
  519. context, std::move(pending_request.user_gesture_token));
  520. }
  521. if (response_validator_) {
  522. bool has_custom_callback =
  523. pending_request.async_handler->has_custom_callback();
  524. response_validator_->ValidateResponse(
  525. context, pending_request.method_name, response_args, error,
  526. has_custom_callback
  527. ? APIResponseValidator::CallbackType::kAPIProvided
  528. : APIResponseValidator::CallbackType::kCallerProvided);
  529. }
  530. v8::TryCatch try_catch(isolate);
  531. pending_request.async_handler->ResolveRequest(context, &last_error_,
  532. response_args, error);
  533. // Since arbitrary JS has ran, the context may have been invalidated. If it
  534. // was, bail.
  535. if (!binding::IsContextValid(context))
  536. return;
  537. if (try_catch.HasCaught()) {
  538. v8::Local<v8::Message> v8_message = try_catch.Message();
  539. absl::optional<std::string> message;
  540. if (!v8_message.IsEmpty())
  541. message = gin::V8ToString(isolate, v8_message->Get());
  542. exception_handler_->HandleException(context, "Error handling response",
  543. &try_catch);
  544. }
  545. }
  546. } // namespace extensions