1 // Copyright 2014 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.
5 #include "extensions/renderer/request_sender.h"
7 #include "base/values.h"
8 #include "content/public/renderer/render_view.h"
9 #include "extensions/common/extension_messages.h"
10 #include "extensions/renderer/dispatcher.h"
11 #include "extensions/renderer/script_context.h"
12 #include "third_party/WebKit/public/web/WebDocument.h"
13 #include "third_party/WebKit/public/web/WebLocalFrame.h"
14 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
15 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
16 #include "third_party/WebKit/public/web/WebUserGestureToken.h"
18 namespace extensions
{
20 // Contains info relevant to a pending API request.
21 struct PendingRequest
{
23 PendingRequest(const std::string
& name
,
24 RequestSender::Source
* source
,
25 blink::WebUserGestureToken token
)
26 : name(name
), source(source
), token(token
) {}
29 RequestSender::Source
* source
;
30 blink::WebUserGestureToken token
;
33 RequestSender::ScopedTabID::ScopedTabID(RequestSender
* request_sender
,
35 : request_sender_(request_sender
),
37 previous_tab_id_(request_sender
->source_tab_id_
) {
38 request_sender_
->source_tab_id_
= tab_id
;
41 RequestSender::ScopedTabID::~ScopedTabID() {
42 DCHECK_EQ(tab_id_
, request_sender_
->source_tab_id_
);
43 request_sender_
->source_tab_id_
= previous_tab_id_
;
46 RequestSender::RequestSender(Dispatcher
* dispatcher
)
47 : dispatcher_(dispatcher
), source_tab_id_(-1) {}
49 RequestSender::~RequestSender() {}
51 void RequestSender::InsertRequest(int request_id
,
52 PendingRequest
* pending_request
) {
53 DCHECK_EQ(0u, pending_requests_
.count(request_id
));
54 pending_requests_
[request_id
].reset(pending_request
);
57 linked_ptr
<PendingRequest
> RequestSender::RemoveRequest(int request_id
) {
58 PendingRequestMap::iterator i
= pending_requests_
.find(request_id
);
59 if (i
== pending_requests_
.end())
60 return linked_ptr
<PendingRequest
>();
61 linked_ptr
<PendingRequest
> result
= i
->second
;
62 pending_requests_
.erase(i
);
66 int RequestSender::GetNextRequestId() const {
67 static int next_request_id
= 0;
68 return next_request_id
++;
71 void RequestSender::StartRequest(Source
* source
,
72 const std::string
& name
,
76 base::ListValue
* value_args
) {
77 ScriptContext
* context
= source
->GetContext();
81 // Get the current RenderView so that we can send a routed IPC message from
82 // the correct source.
83 content::RenderView
* renderview
= context
->GetRenderView();
87 const std::set
<std::string
>& function_names
= dispatcher_
->function_names();
88 if (function_names
.find(name
) == function_names
.end()) {
90 << "Unexpected function " << name
91 << ". Did you remember to register it with ExtensionFunctionRegistry?";
95 // TODO(koz): See if we can make this a CHECK.
96 if (!context
->HasAccessOrThrowError(name
))
100 if (blink::WebLocalFrame
* webframe
= context
->web_frame())
101 source_url
= webframe
->document().url();
103 InsertRequest(request_id
, new PendingRequest(name
, source
,
104 blink::WebUserGestureIndicator::currentUserGestureToken()));
106 ExtensionHostMsg_Request_Params params
;
108 params
.arguments
.Swap(value_args
);
109 params
.extension_id
= context
->GetExtensionID();
110 params
.source_url
= source_url
;
111 params
.source_tab_id
= source_tab_id_
;
112 params
.request_id
= request_id
;
113 params
.has_callback
= has_callback
;
114 params
.user_gesture
=
115 blink::WebUserGestureIndicator::isProcessingUserGesture();
117 renderview
->Send(new ExtensionHostMsg_RequestForIOThread(
118 renderview
->GetRoutingID(), params
));
121 new ExtensionHostMsg_Request(renderview
->GetRoutingID(), params
));
125 void RequestSender::HandleResponse(int request_id
,
127 const base::ListValue
& response
,
128 const std::string
& error
) {
129 linked_ptr
<PendingRequest
> request
= RemoveRequest(request_id
);
131 if (!request
.get()) {
132 // This can happen if a context is destroyed while a request is in flight.
136 blink::WebScopedUserGesture
gesture(request
->token
);
137 request
->source
->OnResponseReceived(
138 request
->name
, request_id
, success
, response
, error
);
141 void RequestSender::InvalidateSource(Source
* source
) {
142 for (PendingRequestMap::iterator it
= pending_requests_
.begin();
143 it
!= pending_requests_
.end();) {
144 if (it
->second
->source
== source
)
145 pending_requests_
.erase(it
++);
151 } // namespace extensions