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().
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
) {
21 $Function
.apply(callback
, request
, args
);
23 exceptionHandler
.handle('Error in response to ' + name
, e
, request
.stack
);
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
;
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).
42 callerChrome
= natives
.GetGlobal(request
.callback
).chrome
;
44 lastError
.clear(chrome
);
45 if (callerChrome
!== chrome
)
46 lastError
.clear(callerChrome
);
50 error
= "Unknown error.";
51 lastError
.set(name
, error
, request
.stack
, chrome
);
52 if (callerChrome
!== chrome
)
53 lastError
.set(name
, error
, request
.stack
, callerChrome
);
56 if (request
.customCallback
) {
57 safeCallbackApply(name
,
59 request
.customCallback
,
60 $Array
.concat([name
, request
], responseList
));
63 if (request
.callback
) {
64 // Validate callback in debug only -- and only when the
65 // caller has provided a callback. Implementations of api
66 // calls may not return data if they observe the caller
67 // has not provided a callback.
68 if (logging
.DCHECK_IS_ON() && !error
) {
69 if (!request
.callbackSchema
.parameters
)
70 throw new Error(name
+ ": no callback schema defined");
71 validate(responseList
, request
.callbackSchema
.parameters
);
73 safeCallbackApply(name
, request
, request
.callback
, responseList
);
77 !lastError
.hasAccessed(chrome
) &&
78 !lastError
.hasAccessed(callerChrome
)) {
79 // The native call caused an error, but the developer didn't check
81 // Notify the developer of the error via the (error) console.
82 console
.error("Unchecked runtime.lastError while running " +
83 (name
|| "unknown") + ": " + error
+
84 (request
.stack
? "\n" + request
.stack
: ""));
87 delete requests
[requestId
];
88 lastError
.clear(chrome
);
89 if (callerChrome
!== chrome
)
90 lastError
.clear(callerChrome
);
94 function prepareRequest(args
, argSchemas
) {
96 var argCount
= args
.length
;
98 // Look for callback param.
99 if (argSchemas
.length
> 0 &&
100 argSchemas
[argSchemas
.length
- 1].type
== "function") {
101 request
.callback
= args
[args
.length
- 1];
102 request
.callbackSchema
= argSchemas
[argSchemas
.length
- 1];
107 for (var k
= 0; k
< argCount
; k
++) {
108 request
.args
[k
] = args
[k
];
114 // Send an API request and optionally register a callback.
115 // |optArgs| is an object with optional parameters as follows:
116 // - customCallback: a callback that should be called instead of the standard
118 // - nativeFunction: the v8 native function to handle the request, or
119 // StartRequest if missing.
120 // - forIOThread: true if this function should be handled on the browser IO
122 // - preserveNullInObjects: true if it is safe for null to be in objects.
123 function sendRequest(functionName
, args
, argSchemas
, optArgs
) {
124 calledSendRequest
= true;
127 var request
= prepareRequest(args
, argSchemas
);
128 request
.stack
= exceptionHandler
.getExtensionStackTrace();
129 if (optArgs
.customCallback
) {
130 request
.customCallback
= optArgs
.customCallback
;
133 var nativeFunction
= optArgs
.nativeFunction
|| natives
.StartRequest
;
135 var requestId
= natives
.GetNextRequestId();
136 request
.id
= requestId
;
137 requests
[requestId
] = request
;
139 var hasCallback
= request
.callback
|| optArgs
.customCallback
;
140 return nativeFunction(functionName
,
145 optArgs
.preserveNullInObjects
);
148 function getCalledSendRequest() {
149 return calledSendRequest
;
152 function clearCalledSendRequest() {
153 calledSendRequest
= false;
156 exports
.sendRequest
= sendRequest
;
157 exports
.getCalledSendRequest
= getCalledSendRequest
;
158 exports
.clearCalledSendRequest
= clearCalledSendRequest
;
159 exports
.safeCallbackApply
= safeCallbackApply
;
162 exports
.handleResponse
= handleResponse
;