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
, request
.callback
],
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
);
72 safeCallbackApply(name
, request
, request
.callback
, responseList
);
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
);
81 delete requests
[requestId
];
82 lastError
.clear(chrome
);
83 if (callerChrome
!== chrome
)
84 lastError
.clear(callerChrome
);
88 function prepareRequest(args
, argSchemas
) {
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];
101 for (var k
= 0; k
< argCount
; k
++) {
102 request
.args
[k
] = args
[k
];
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
112 // - nativeFunction: the v8 native function to handle the request, or
113 // StartRequest if missing.
114 // - forIOThread: true if this function should be handled on the browser IO
116 // - preserveNullInObjects: true if it is safe for null to be in objects.
117 // - stack: An optional string that contains the stack trace, to be displayed
118 // to the user if an error occurs.
119 function sendRequest(functionName
, args
, argSchemas
, optArgs
) {
120 calledSendRequest
= true;
123 var request
= prepareRequest(args
, argSchemas
);
124 request
.stack
= optArgs
.stack
|| exceptionHandler
.getExtensionStackTrace();
125 if (optArgs
.customCallback
) {
126 request
.customCallback
= optArgs
.customCallback
;
129 var nativeFunction
= optArgs
.nativeFunction
|| natives
.StartRequest
;
131 var requestId
= natives
.GetNextRequestId();
132 request
.id
= requestId
;
133 requests
[requestId
] = request
;
135 var hasCallback
= request
.callback
|| optArgs
.customCallback
;
136 return nativeFunction(functionName
,
141 optArgs
.preserveNullInObjects
);
144 function getCalledSendRequest() {
145 return calledSendRequest
;
148 function clearCalledSendRequest() {
149 calledSendRequest
= false;
152 exports
.sendRequest
= sendRequest
;
153 exports
.getCalledSendRequest
= getCalledSendRequest
;
154 exports
.clearCalledSendRequest
= clearCalledSendRequest
;
155 exports
.safeCallbackApply
= safeCallbackApply
;
158 exports
.handleResponse
= handleResponse
;