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_frame.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 RenderFrame so that we can send a routed IPC message from
82 // the correct source.
83 content::RenderFrame
* render_frame
= context
->GetRenderFrame();
87 // TODO(koz): See if we can make this a CHECK.
88 if (!context
->HasAccessOrThrowError(name
))
92 if (blink::WebLocalFrame
* webframe
= context
->web_frame())
93 source_url
= webframe
->document().url();
95 InsertRequest(request_id
, new PendingRequest(name
, source
,
96 blink::WebUserGestureIndicator::currentUserGestureToken()));
98 ExtensionHostMsg_Request_Params params
;
100 params
.arguments
.Swap(value_args
);
101 params
.extension_id
= context
->GetExtensionID();
102 params
.source_url
= source_url
;
103 params
.source_tab_id
= source_tab_id_
;
104 params
.request_id
= request_id
;
105 params
.has_callback
= has_callback
;
106 params
.user_gesture
=
107 blink::WebUserGestureIndicator::isProcessingUserGesture();
109 render_frame
->Send(new ExtensionHostMsg_RequestForIOThread(
110 render_frame
->GetRoutingID(), params
));
113 new ExtensionHostMsg_Request(render_frame
->GetRoutingID(), params
));
117 void RequestSender::HandleResponse(int request_id
,
119 const base::ListValue
& response
,
120 const std::string
& error
) {
121 linked_ptr
<PendingRequest
> request
= RemoveRequest(request_id
);
123 if (!request
.get()) {
124 // This can happen if a context is destroyed while a request is in flight.
128 blink::WebScopedUserGesture
gesture(request
->token
);
129 request
->source
->OnResponseReceived(
130 request
->name
, request_id
, success
, response
, error
);
133 void RequestSender::InvalidateSource(Source
* source
) {
134 for (PendingRequestMap::iterator it
= pending_requests_
.begin();
135 it
!= pending_requests_
.end();) {
136 if (it
->second
->source
== source
)
137 pending_requests_
.erase(it
++);
143 } // namespace extensions