19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Copyright (c) 2012 The Chromium Authors. All rights reserved.
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Use of this source code is governed by a BSD-style license that can be
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// found in the LICENSE file.
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "chrome/renderer/extensions/request_sender.h"
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "base/values.h"
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "chrome/common/extensions/extension_messages.h"
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "chrome/renderer/extensions/chrome_v8_context.h"
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "chrome/renderer/extensions/dispatcher.h"
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "content/public/renderer/render_view.h"
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "third_party/WebKit/public/web/WebDocument.h"
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "third_party/WebKit/public/web/WebFrame.h"
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace extensions {
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Contains info relevant to a pending API request.
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct PendingRequest {
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public :
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  PendingRequest(const std::string& name, RequestSender::Source* source)
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      : name(name), source(source) {
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  std::string name;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  RequestSender::Source* source;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectRequestSender::RequestSender(Dispatcher* dispatcher) : dispatcher_(dispatcher) {
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectRequestSender::~RequestSender() {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid RequestSender::InsertRequest(int request_id,
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                  PendingRequest* pending_request) {
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  DCHECK_EQ(0u, pending_requests_.count(request_id));
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  pending_requests_[request_id].reset(pending_request);
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectlinked_ptr<PendingRequest> RequestSender::RemoveRequest(int request_id) {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  PendingRequestMap::iterator i = pending_requests_.find(request_id);
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (i == pending_requests_.end())
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return linked_ptr<PendingRequest>();
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  linked_ptr<PendingRequest> result = i->second;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  pending_requests_.erase(i);
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  return result;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint RequestSender::GetNextRequestId() const {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  static int next_request_id = 0;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  return next_request_id++;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
540f9ae274b4a9641d8e6933108466dc432f5a0474Gilles Debunne
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid RequestSender::StartRequest(Source* source,
560f9ae274b4a9641d8e6933108466dc432f5a0474Gilles Debunne                                 const std::string& name,
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 int request_id,
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 bool has_callback,
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 bool for_io_thread,
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 base::ListValue* value_args) {
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  ChromeV8Context* context = source->GetContext();
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (!context)
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  // Get the current RenderView so that we can send a routed IPC message from
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  // the correct source.
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  content::RenderView* renderview = context->GetRenderView();
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (!renderview)
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
71d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  const std::set<std::string>& function_names = dispatcher_->function_names();
72d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  if (function_names.find(name) == function_names.end()) {
73d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien    NOTREACHED() << "Unexpected function " << name <<
74d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien        ". Did you remember to register it with ExtensionFunctionRegistry?";
75d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien    return;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
77d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien
78d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  // TODO(koz): See if we can make this a CHECK.
79d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  if (!dispatcher_->CheckContextAccessToExtensionAPI(name, context))
80d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien    return;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
82d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  GURL source_url;
83d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  if (blink::WebFrame* webframe = context->web_frame())
84d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien    source_url = webframe->document().url();
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  InsertRequest(request_id, new PendingRequest(name, source));
87d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien
88d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  ExtensionHostMsg_Request_Params params;
89d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  params.name = name;
90d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  params.arguments.Swap(value_args);
91d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  params.extension_id = context->GetExtensionID();
92d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  params.source_url = source_url;
93d570e8987ae50ee101c3d4cfa973e1a6b6ecc8f5Raph Levien  params.request_id = request_id;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  params.has_callback = has_callback;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  params.user_gesture =
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      blink::WebUserGestureIndicator::isProcessingUserGesture();
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (for_io_thread) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    renderview->Send(new ExtensionHostMsg_RequestForIOThread(
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        renderview->GetRoutingID(), params));
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  } else {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    renderview->Send(new ExtensionHostMsg_Request(
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        renderview->GetRoutingID(), params));
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid RequestSender::HandleResponse(int request_id,
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   bool success,
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   const base::ListValue& response,
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   const std::string& error) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  linked_ptr<PendingRequest> request = RemoveRequest(request_id);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  if (!request.get()) {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // This can happen if a context is destroyed while a request is in flight.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  request->source->OnResponseReceived(request->name, request_id, success,
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                      response, error);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid RequestSender::InvalidateSource(Source* source) {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  for (PendingRequestMap::iterator it = pending_requests_.begin();
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       it != pending_requests_.end();) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (it->second->source == source)
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      pending_requests_.erase(it++);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      ++it;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project  }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}  // namespace extensions
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project