Home | History | Annotate | Download | only in extensions
      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/common/extensions/extension_messages.h"
      9 #include "chrome/renderer/extensions/chrome_v8_context.h"
     10 #include "chrome/renderer/extensions/dispatcher.h"
     11 #include "content/public/renderer/render_view.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::RequestSender(Dispatcher* dispatcher) : dispatcher_(dispatcher) {
     30 }
     31 
     32 RequestSender::~RequestSender() {
     33 }
     34 
     35 void RequestSender::InsertRequest(int request_id,
     36                                   PendingRequest* pending_request) {
     37   DCHECK_EQ(0u, pending_requests_.count(request_id));
     38   pending_requests_[request_id].reset(pending_request);
     39 }
     40 
     41 linked_ptr<PendingRequest> RequestSender::RemoveRequest(int request_id) {
     42   PendingRequestMap::iterator i = pending_requests_.find(request_id);
     43   if (i == pending_requests_.end())
     44     return linked_ptr<PendingRequest>();
     45   linked_ptr<PendingRequest> result = i->second;
     46   pending_requests_.erase(i);
     47   return result;
     48 }
     49 
     50 int RequestSender::GetNextRequestId() const {
     51   static int next_request_id = 0;
     52   return next_request_id++;
     53 }
     54 
     55 void RequestSender::StartRequest(Source* source,
     56                                  const std::string& name,
     57                                  int request_id,
     58                                  bool has_callback,
     59                                  bool for_io_thread,
     60                                  base::ListValue* value_args) {
     61   ChromeV8Context* context = source->GetContext();
     62   if (!context)
     63     return;
     64 
     65   // Get the current RenderView so that we can send a routed IPC message from
     66   // the correct source.
     67   content::RenderView* renderview = context->GetRenderView();
     68   if (!renderview)
     69     return;
     70 
     71   const std::set<std::string>& function_names = dispatcher_->function_names();
     72   if (function_names.find(name) == function_names.end()) {
     73     NOTREACHED() << "Unexpected function " << name <<
     74         ". Did you remember to register it with ExtensionFunctionRegistry?";
     75     return;
     76   }
     77 
     78   // TODO(koz): See if we can make this a CHECK.
     79   if (!dispatcher_->CheckContextAccessToExtensionAPI(name, context))
     80     return;
     81 
     82   GURL source_url;
     83   if (WebKit::WebFrame* webframe = context->web_frame())
     84     source_url = webframe->document().url();
     85 
     86   InsertRequest(request_id, new PendingRequest(name, source));
     87 
     88   ExtensionHostMsg_Request_Params params;
     89   params.name = name;
     90   params.arguments.Swap(value_args);
     91   params.extension_id = context->GetExtensionID();
     92   params.source_url = source_url;
     93   params.request_id = request_id;
     94   params.has_callback = has_callback;
     95   params.user_gesture =
     96       WebKit::WebUserGestureIndicator::isProcessingUserGesture();
     97   if (for_io_thread) {
     98     renderview->Send(new ExtensionHostMsg_RequestForIOThread(
     99         renderview->GetRoutingID(), params));
    100   } else {
    101     renderview->Send(new ExtensionHostMsg_Request(
    102         renderview->GetRoutingID(), params));
    103   }
    104 }
    105 
    106 void RequestSender::HandleResponse(int request_id,
    107                                    bool success,
    108                                    const base::ListValue& response,
    109                                    const std::string& error) {
    110   linked_ptr<PendingRequest> request = RemoveRequest(request_id);
    111 
    112   if (!request.get()) {
    113     // This can happen if a context is destroyed while a request is in flight.
    114     return;
    115   }
    116 
    117   request->source->OnResponseReceived(request->name, request_id, success,
    118                                       response, error);
    119 }
    120 
    121 void RequestSender::InvalidateSource(Source* source) {
    122   for (PendingRequestMap::iterator it = pending_requests_.begin();
    123        it != pending_requests_.end();) {
    124     if (it->second->source == source)
    125       pending_requests_.erase(it++);
    126     else
    127       ++it;
    128   }
    129 }
    130 
    131 }  // namespace extensions
    132