[Android] Added UMA for search by image context menu.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / send_request.js
blob28798baafcbfd9fd65eab2569346043e383a5d80
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.
5 var lastError = require('lastError');
6 var logging = requireNative('logging');
7 var natives = requireNative('sendRequest');
8 var processNatives = requireNative('process');
9 var validate = require('schemaUtils').validate;
11 // All outstanding requests from sendRequest().
12 var requests = {};
14 // Used to prevent double Activity Logging for API calls that use both custom
15 // bindings and ExtensionFunctions (via sendRequest).
16 var calledSendRequest = false;
18 // Runs a user-supplied callback safely.
19 function safeCallbackApply(name, request, callback, args) {
20 try {
21 $Function.apply(callback, request, args);
22 } catch (e) {
23 var errorMessage = "Error in response to " + name + ": " + e;
24 if (request.stack && request.stack != '')
25 errorMessage += "\n" + request.stack;
26 console.error(errorMessage);
30 // Callback handling.
31 function handleResponse(requestId, name, success, responseList, error) {
32 // The chrome objects we will set lastError on. Really we should only be
33 // setting this on the callback's chrome object, but set on ours too since
34 // it's conceivable that something relies on that.
35 var chromesForLastError = [chrome];
37 try {
38 var request = requests[requestId];
39 logging.DCHECK(request != null);
41 // lastError needs to be set on the caller's chrome object no matter what,
42 // though chances are it's the same as ours (it will be different when
43 // calling API methods on other contexts).
44 if (request.callback) {
45 var chromeForCallback = natives.GetGlobal(request.callback).chrome;
46 if (chromeForCallback != chrome)
47 $Array.push(chromesForLastError, chromeForCallback);
50 $Array.forEach(chromesForLastError, function(c) {lastError.clear(c)});
51 if (!success) {
52 if (!error)
53 error = "Unknown error.";
54 $Array.forEach(chromesForLastError, function(c) {
55 lastError.set(name, error, request.stack, c)
56 });
59 if (request.customCallback) {
60 safeCallbackApply(name,
61 request,
62 request.customCallback,
63 $Array.concat([name, request], responseList));
66 if (request.callback) {
67 // Validate callback in debug only -- and only when the
68 // caller has provided a callback. Implementations of api
69 // calls may not return data if they observe the caller
70 // has not provided a callback.
71 if (logging.DCHECK_IS_ON() && !error) {
72 if (!request.callbackSchema.parameters)
73 throw new Error(name + ": no callback schema defined");
74 validate(responseList, request.callbackSchema.parameters);
76 safeCallbackApply(name, request, request.callback, responseList);
78 } finally {
79 delete requests[requestId];
80 $Array.forEach(chromesForLastError, function(c) {lastError.clear(c)});
84 function getExtensionStackTrace(call_name) {
85 var stack = $String.split(new Error().stack, '\n');
87 // Remove stack frames before and after that weren't associated with the
88 // extension.
89 var id = processNatives.GetExtensionId();
90 while (stack.length > 0 && stack[0].indexOf(id) == -1)
91 stack.shift();
92 while (stack.length > 0 && stack[stack.length - 1].indexOf(id) == -1)
93 stack.pop();
95 return stack.join('\n');
98 function prepareRequest(args, argSchemas) {
99 var request = {};
100 var argCount = args.length;
102 // Look for callback param.
103 if (argSchemas.length > 0 &&
104 argSchemas[argSchemas.length - 1].type == "function") {
105 request.callback = args[args.length - 1];
106 request.callbackSchema = argSchemas[argSchemas.length - 1];
107 --argCount;
110 request.args = [];
111 for (var k = 0; k < argCount; k++) {
112 request.args[k] = args[k];
115 return request;
118 // Send an API request and optionally register a callback.
119 // |optArgs| is an object with optional parameters as follows:
120 // - customCallback: a callback that should be called instead of the standard
121 // callback.
122 // - nativeFunction: the v8 native function to handle the request, or
123 // StartRequest if missing.
124 // - forIOThread: true if this function should be handled on the browser IO
125 // thread.
126 // - preserveNullInObjects: true if it is safe for null to be in objects.
127 function sendRequest(functionName, args, argSchemas, optArgs) {
128 calledSendRequest = true;
129 if (!optArgs)
130 optArgs = {};
131 var request = prepareRequest(args, argSchemas);
132 request.stack = getExtensionStackTrace();
133 if (optArgs.customCallback) {
134 request.customCallback = optArgs.customCallback;
137 var nativeFunction = optArgs.nativeFunction || natives.StartRequest;
139 var requestId = natives.GetNextRequestId();
140 request.id = requestId;
141 requests[requestId] = request;
143 var hasCallback = request.callback || optArgs.customCallback;
144 return nativeFunction(functionName,
145 request.args,
146 requestId,
147 hasCallback,
148 optArgs.forIOThread,
149 optArgs.preserveNullInObjects);
152 function getCalledSendRequest() {
153 return calledSendRequest;
156 function clearCalledSendRequest() {
157 calledSendRequest = false;
160 exports.sendRequest = sendRequest;
161 exports.getCalledSendRequest = getCalledSendRequest;
162 exports.clearCalledSendRequest = clearCalledSendRequest;
164 // Called by C++.
165 exports.handleResponse = handleResponse;