Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / extensions / request_sender.cc
1 // Copyright (c) 2012 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
5 #include "chrome/renderer/extensions/request_sender.h"
6
7 #include "base/values.h"
8 #include "chrome/renderer/extensions/chrome_v8_context.h"
9 #include "chrome/renderer/extensions/dispatcher.h"
10 #include "content/public/renderer/render_view.h"
11 #include "extensions/common/extension_messages.h"
12 #include "third_party/WebKit/public/web/WebDocument.h"
13 #include "third_party/WebKit/public/web/WebFrame.h"
14 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
15
16 namespace extensions {
17
18 // Contains info relevant to a pending API request.
19 struct PendingRequest {
20  public :
21   PendingRequest(const std::string& name, RequestSender::Source* source)
22       : name(name), source(source) {
23   }
24
25   std::string name;
26   RequestSender::Source* source;
27 };
28
29 RequestSender::ScopedTabID::ScopedTabID(RequestSender* request_sender,
30                                         int tab_id)
31     : request_sender_(request_sender),
32       tab_id_(tab_id),
33       previous_tab_id_(request_sender->source_tab_id_) {
34   request_sender_->source_tab_id_ = tab_id;
35 }
36
37 RequestSender::ScopedTabID::~ScopedTabID() {
38   DCHECK_EQ(tab_id_, request_sender_->source_tab_id_);
39   request_sender_->source_tab_id_ = previous_tab_id_;
40 }
41
42 RequestSender::RequestSender(Dispatcher* dispatcher)
43     : dispatcher_(dispatcher),
44       source_tab_id_(-1) {
45 }
46
47 RequestSender::~RequestSender() {
48 }
49
50 void RequestSender::InsertRequest(int request_id,
51                                   PendingRequest* pending_request) {
52   DCHECK_EQ(0u, pending_requests_.count(request_id));
53   pending_requests_[request_id].reset(pending_request);
54 }
55
56 linked_ptr<PendingRequest> RequestSender::RemoveRequest(int request_id) {
57   PendingRequestMap::iterator i = pending_requests_.find(request_id);
58   if (i == pending_requests_.end())
59     return linked_ptr<PendingRequest>();
60   linked_ptr<PendingRequest> result = i->second;
61   pending_requests_.erase(i);
62   return result;
63 }
64
65 int RequestSender::GetNextRequestId() const {
66   static int next_request_id = 0;
67   return next_request_id++;
68 }
69
70 void RequestSender::StartRequest(Source* source,
71                                  const std::string& name,
72                                  int request_id,
73                                  bool has_callback,
74                                  bool for_io_thread,
75                                  base::ListValue* value_args) {
76   ChromeV8Context* context = source->GetContext();
77   if (!context)
78     return;
79
80   // Get the current RenderView so that we can send a routed IPC message from
81   // the correct source.
82   content::RenderView* renderview = context->GetRenderView();
83   if (!renderview)
84     return;
85
86   const std::set<std::string>& function_names = dispatcher_->function_names();
87   if (function_names.find(name) == function_names.end()) {
88     NOTREACHED() << "Unexpected function " << name <<
89         ". Did you remember to register it with ExtensionFunctionRegistry?";
90     return;
91   }
92
93   // TODO(koz): See if we can make this a CHECK.
94   if (!dispatcher_->CheckContextAccessToExtensionAPI(name, context))
95     return;
96
97   GURL source_url;
98   if (blink::WebFrame* webframe = context->web_frame())
99     source_url = webframe->document().url();
100
101   InsertRequest(request_id, new PendingRequest(name, source));
102
103   ExtensionHostMsg_Request_Params params;
104   params.name = name;
105   params.arguments.Swap(value_args);
106   params.extension_id = context->GetExtensionID();
107   params.source_url = source_url;
108   params.source_tab_id = source_tab_id_;
109   params.request_id = request_id;
110   params.has_callback = has_callback;
111   params.user_gesture =
112       blink::WebUserGestureIndicator::isProcessingUserGesture();
113   if (for_io_thread) {
114     renderview->Send(new ExtensionHostMsg_RequestForIOThread(
115         renderview->GetRoutingID(), params));
116   } else {
117     renderview->Send(new ExtensionHostMsg_Request(
118         renderview->GetRoutingID(), params));
119   }
120 }
121
122 void RequestSender::HandleResponse(int request_id,
123                                    bool success,
124                                    const base::ListValue& response,
125                                    const std::string& error) {
126   linked_ptr<PendingRequest> request = RemoveRequest(request_id);
127
128   if (!request.get()) {
129     // This can happen if a context is destroyed while a request is in flight.
130     return;
131   }
132
133   request->source->OnResponseReceived(request->name, request_id, success,
134                                       response, error);
135 }
136
137 void RequestSender::InvalidateSource(Source* source) {
138   for (PendingRequestMap::iterator it = pending_requests_.begin();
139        it != pending_requests_.end();) {
140     if (it->second->source == source)
141       pending_requests_.erase(it++);
142     else
143       ++it;
144   }
145 }
146
147 }  // namespace extensions