OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/api_request_handler.h" | 5 #include "extensions/renderer/api_request_handler.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/guid.h" | 8 #include "base/guid.h" |
9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 for (const auto& arg : local_callback_args) | 29 for (const auto& arg : local_callback_args) |
30 callback_arguments.push_back(v8::Global<v8::Value>(isolate, arg)); | 30 callback_arguments.push_back(v8::Global<v8::Value>(isolate, arg)); |
31 } | 31 } |
32 } | 32 } |
33 | 33 |
34 APIRequestHandler::PendingRequest::~PendingRequest() {} | 34 APIRequestHandler::PendingRequest::~PendingRequest() {} |
35 APIRequestHandler::PendingRequest::PendingRequest(PendingRequest&&) = default; | 35 APIRequestHandler::PendingRequest::PendingRequest(PendingRequest&&) = default; |
36 APIRequestHandler::PendingRequest& APIRequestHandler::PendingRequest::operator=( | 36 APIRequestHandler::PendingRequest& APIRequestHandler::PendingRequest::operator=( |
37 PendingRequest&&) = default; | 37 PendingRequest&&) = default; |
38 | 38 |
39 APIRequestHandler::APIRequestHandler(const CallJSFunction& call_js) | 39 APIRequestHandler::APIRequestHandler(const CallJSFunction& call_js, |
40 : call_js_(call_js) {} | 40 APILastError last_error) |
| 41 : call_js_(call_js), last_error_(std::move(last_error)) {} |
41 | 42 |
42 APIRequestHandler::~APIRequestHandler() {} | 43 APIRequestHandler::~APIRequestHandler() {} |
43 | 44 |
44 int APIRequestHandler::AddPendingRequest( | 45 int APIRequestHandler::AddPendingRequest( |
45 v8::Isolate* isolate, | 46 v8::Isolate* isolate, |
46 v8::Local<v8::Function> callback, | 47 v8::Local<v8::Function> callback, |
47 v8::Local<v8::Context> context, | 48 v8::Local<v8::Context> context, |
48 const std::vector<v8::Local<v8::Value>>& callback_args) { | 49 const std::vector<v8::Local<v8::Value>>& callback_args) { |
49 // TODO(devlin): We could *probably* get away with just using an integer here, | 50 // TODO(devlin): We could *probably* get away with just using an integer here, |
50 // but it's a little less foolproof. How slow is GenerateGUID? Should we use | 51 // but it's a little less foolproof. How slow is GenerateGUID? Should we use |
51 // that instead? It means updating the IPC (ExtensionHostMsg_Request). | 52 // that instead? It means updating the IPC (ExtensionHostMsg_Request). |
52 // base::UnguessableToken is another good option. | 53 // base::UnguessableToken is another good option. |
53 int id = next_request_id_++; | 54 int id = next_request_id_++; |
54 pending_requests_.insert(std::make_pair( | 55 pending_requests_.insert(std::make_pair( |
55 id, PendingRequest(isolate, callback, context, callback_args))); | 56 id, PendingRequest(isolate, callback, context, callback_args))); |
56 return id; | 57 return id; |
57 } | 58 } |
58 | 59 |
59 void APIRequestHandler::CompleteRequest(int request_id, | 60 void APIRequestHandler::CompleteRequest(int request_id, |
60 const base::ListValue& response_args) { | 61 const base::ListValue& response_args, |
| 62 const std::string& error) { |
61 auto iter = pending_requests_.find(request_id); | 63 auto iter = pending_requests_.find(request_id); |
62 // The request may have been removed if the context was invalidated before a | 64 // The request may have been removed if the context was invalidated before a |
63 // response is ready. | 65 // response is ready. |
64 if (iter == pending_requests_.end()) | 66 if (iter == pending_requests_.end()) |
65 return; | 67 return; |
66 | 68 |
67 PendingRequest pending_request = std::move(iter->second); | 69 PendingRequest pending_request = std::move(iter->second); |
68 pending_requests_.erase(iter); | 70 pending_requests_.erase(iter); |
69 | 71 |
70 v8::Isolate* isolate = pending_request.isolate; | 72 v8::Isolate* isolate = pending_request.isolate; |
71 v8::HandleScope handle_scope(isolate); | 73 v8::HandleScope handle_scope(isolate); |
72 v8::Local<v8::Context> context = pending_request.context.Get(isolate); | 74 v8::Local<v8::Context> context = pending_request.context.Get(isolate); |
| 75 v8::Context::Scope context_scope(context); |
73 std::unique_ptr<content::V8ValueConverter> converter( | 76 std::unique_ptr<content::V8ValueConverter> converter( |
74 content::V8ValueConverter::create()); | 77 content::V8ValueConverter::create()); |
75 std::vector<v8::Local<v8::Value>> args; | 78 std::vector<v8::Local<v8::Value>> args; |
76 args.reserve(response_args.GetSize() + | 79 args.reserve(response_args.GetSize() + |
77 pending_request.callback_arguments.size()); | 80 pending_request.callback_arguments.size()); |
78 for (const auto& arg : pending_request.callback_arguments) | 81 for (const auto& arg : pending_request.callback_arguments) |
79 args.push_back(arg.Get(isolate)); | 82 args.push_back(arg.Get(isolate)); |
80 for (const auto& arg : response_args) | 83 for (const auto& arg : response_args) |
81 args.push_back(converter->ToV8Value(arg.get(), context)); | 84 args.push_back(converter->ToV8Value(arg.get(), context)); |
82 | 85 |
83 blink::WebScopedUserGesture user_gesture(pending_request.user_gesture_token); | 86 blink::WebScopedUserGesture user_gesture(pending_request.user_gesture_token); |
| 87 if (!error.empty()) |
| 88 last_error_.SetError(context, error); |
| 89 |
84 // args.size() is converted to int, but args is controlled by chrome and is | 90 // args.size() is converted to int, but args is controlled by chrome and is |
85 // never close to std::numeric_limits<int>::max. | 91 // never close to std::numeric_limits<int>::max. |
86 call_js_.Run(pending_request.callback.Get(isolate), context, args.size(), | 92 call_js_.Run(pending_request.callback.Get(isolate), context, args.size(), |
87 args.data()); | 93 args.data()); |
| 94 |
| 95 if (!error.empty()) |
| 96 last_error_.ClearError(context, true); |
88 } | 97 } |
89 | 98 |
90 void APIRequestHandler::InvalidateContext(v8::Local<v8::Context> context) { | 99 void APIRequestHandler::InvalidateContext(v8::Local<v8::Context> context) { |
91 for (auto iter = pending_requests_.begin(); | 100 for (auto iter = pending_requests_.begin(); |
92 iter != pending_requests_.end();) { | 101 iter != pending_requests_.end();) { |
93 if (iter->second.context == context) | 102 if (iter->second.context == context) |
94 iter = pending_requests_.erase(iter); | 103 iter = pending_requests_.erase(iter); |
95 else | 104 else |
96 ++iter; | 105 ++iter; |
97 } | 106 } |
98 } | 107 } |
99 | 108 |
100 std::set<int> APIRequestHandler::GetPendingRequestIdsForTesting() const { | 109 std::set<int> APIRequestHandler::GetPendingRequestIdsForTesting() const { |
101 std::set<int> result; | 110 std::set<int> result; |
102 for (const auto& pair : pending_requests_) | 111 for (const auto& pair : pending_requests_) |
103 result.insert(pair.first); | 112 result.insert(pair.first); |
104 return result; | 113 return result; |
105 } | 114 } |
106 | 115 |
107 } // namespace extensions | 116 } // namespace extensions |
OLD | NEW |