Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / renderer / resources / send_request.js
blob3dc523c4f6951933006477d86ac35c531731c7da
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 var exceptionHandler = require('uncaught_exception_handler');
6 var lastError = require('lastError');
7 var logging = requireNative('logging');
8 var natives = requireNative('sendRequest');
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     exceptionHandler.handle('Error in response to ' + name, e, request.stack);
24   }
27 // Callback handling.
28 function handleResponse(requestId, name, success, responseList, error) {
29   // The chrome objects we will set lastError on. Really we should only be
30   // setting this on the callback's chrome object, but set on ours too since
31   // it's conceivable that something relies on that.
32   var callerChrome = chrome;
34   try {
35     var request = requests[requestId];
36     logging.DCHECK(request != null);
38     // lastError needs to be set on the caller's chrome object no matter what,
39     // though chances are it's the same as ours (it will be different when
40     // calling API methods on other contexts).
41     if (request.callback)
42       callerChrome = natives.GetGlobal(request.callback).chrome;
44     lastError.clear(chrome);
45     if (callerChrome !== chrome)
46       lastError.clear(callerChrome);
48     if (!success) {
49       if (!error)
50         error = "Unknown error.";
51       lastError.set(name, error, request.stack, chrome);
52       if (callerChrome !== chrome)
53         lastError.set(name, error, request.stack, callerChrome);
54     }
56     if (request.customCallback) {
57       safeCallbackApply(name,
58                         request,
59                         request.customCallback,
60                         $Array.concat([name, request, request.callback],
61                                       responseList));
62     } else if (request.callback) {
63       // Validate callback in debug only -- and only when the
64       // caller has provided a callback. Implementations of api
65       // calls may not return data if they observe the caller
66       // has not provided a callback.
67       if (logging.DCHECK_IS_ON() && !error) {
68         if (!request.callbackSchema.parameters)
69           throw new Error(name + ": no callback schema defined");
70         validate(responseList, request.callbackSchema.parameters);
71       }
72       safeCallbackApply(name, request, request.callback, responseList);
73     }
75     if (error && !lastError.hasAccessed(chrome)) {
76       // The native call caused an error, but the developer might not have
77       // checked runtime.lastError.
78       lastError.reportIfUnchecked(name, callerChrome, request.stack);
79     }
80   } finally {
81     delete requests[requestId];
82     lastError.clear(chrome);
83     if (callerChrome !== chrome)
84       lastError.clear(callerChrome);
85   }
88 function prepareRequest(args, argSchemas) {
89   var request = {};
90   var argCount = args.length;
92   // Look for callback param.
93   if (argSchemas.length > 0 &&
94       argSchemas[argSchemas.length - 1].type == "function") {
95     request.callback = args[args.length - 1];
96     request.callbackSchema = argSchemas[argSchemas.length - 1];
97     --argCount;
98   }
100   request.args = [];
101   for (var k = 0; k < argCount; k++) {
102     request.args[k] = args[k];
103   }
105   return request;
108 // Send an API request and optionally register a callback.
109 // |optArgs| is an object with optional parameters as follows:
110 // - customCallback: a callback that should be called instead of the standard
111 //   callback.
112 // - forIOThread: true if this function should be handled on the browser IO
113 //   thread.
114 // - preserveNullInObjects: true if it is safe for null to be in objects.
115 // - stack: An optional string that contains the stack trace, to be displayed
116 //   to the user if an error occurs.
117 function sendRequest(functionName, args, argSchemas, optArgs) {
118   calledSendRequest = true;
119   if (!optArgs)
120     optArgs = {};
121   var request = prepareRequest(args, argSchemas);
122   request.stack = optArgs.stack || exceptionHandler.getExtensionStackTrace();
123   if (optArgs.customCallback) {
124     request.customCallback = optArgs.customCallback;
125   }
127   var hasCallback = request.callback || optArgs.customCallback;
128   var requestId =
129       natives.StartRequest(functionName, request.args, hasCallback,
130                            optArgs.forIOThread, optArgs.preserveNullInObjects);
131   request.id = requestId;
132   requests[requestId] = request;
135 function getCalledSendRequest() {
136   return calledSendRequest;
139 function clearCalledSendRequest() {
140   calledSendRequest = false;
143 exports.sendRequest = sendRequest;
144 exports.getCalledSendRequest = getCalledSendRequest;
145 exports.clearCalledSendRequest = clearCalledSendRequest;
146 exports.safeCallbackApply = safeCallbackApply;
148 // Called by C++.
149 exports.handleResponse = handleResponse;