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().
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 var errorMessage
= "Error in response to " + name
+ ": " + e
;
24 if (request
.stack
&& request
.stack
!= '')
25 errorMessage
+= "\n" + request
.stack
;
26 console
.error(errorMessage
);
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 callerChrome
= chrome
;
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).
45 callerChrome
= natives
.GetGlobal(request
.callback
).chrome
;
47 lastError
.clear(chrome
);
48 if (callerChrome
!== chrome
)
49 lastError
.clear(callerChrome
);
53 error
= "Unknown error.";
54 lastError
.set(name
, error
, request
.stack
, chrome
);
55 if (callerChrome
!== chrome
)
56 lastError
.set(name
, error
, request
.stack
, callerChrome
);
59 if (request
.customCallback
) {
60 safeCallbackApply(name
,
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
);
79 delete requests
[requestId
];
80 lastError
.clear(chrome
);
81 if (callerChrome
!== chrome
)
82 lastError
.clear(callerChrome
);
86 function getExtensionStackTrace(call_name
) {
87 var stack
= $String
.split(new Error().stack
, '\n');
88 var id
= processNatives
.GetExtensionId();
90 // Remove stack frames before and after that weren't associated with the
92 return $Array
.join(stack
.filter(function(line
) {
93 return line
.indexOf(id
) != -1;
97 function prepareRequest(args
, argSchemas
) {
99 var argCount
= args
.length
;
101 // Look for callback param.
102 if (argSchemas
.length
> 0 &&
103 argSchemas
[argSchemas
.length
- 1].type
== "function") {
104 request
.callback
= args
[args
.length
- 1];
105 request
.callbackSchema
= argSchemas
[argSchemas
.length
- 1];
110 for (var k
= 0; k
< argCount
; k
++) {
111 request
.args
[k
] = args
[k
];
117 // Send an API request and optionally register a callback.
118 // |optArgs| is an object with optional parameters as follows:
119 // - customCallback: a callback that should be called instead of the standard
121 // - nativeFunction: the v8 native function to handle the request, or
122 // StartRequest if missing.
123 // - forIOThread: true if this function should be handled on the browser IO
125 // - preserveNullInObjects: true if it is safe for null to be in objects.
126 function sendRequest(functionName
, args
, argSchemas
, optArgs
) {
127 calledSendRequest
= true;
130 var request
= prepareRequest(args
, argSchemas
);
131 request
.stack
= getExtensionStackTrace();
132 if (optArgs
.customCallback
) {
133 request
.customCallback
= optArgs
.customCallback
;
136 var nativeFunction
= optArgs
.nativeFunction
|| natives
.StartRequest
;
138 var requestId
= natives
.GetNextRequestId();
139 request
.id
= requestId
;
140 requests
[requestId
] = request
;
142 var hasCallback
= request
.callback
|| optArgs
.customCallback
;
143 return nativeFunction(functionName
,
148 optArgs
.preserveNullInObjects
);
151 function getCalledSendRequest() {
152 return calledSendRequest
;
155 function clearCalledSendRequest() {
156 calledSendRequest
= false;
159 exports
.sendRequest
= sendRequest
;
160 exports
.getCalledSendRequest
= getCalledSendRequest
;
161 exports
.clearCalledSendRequest
= clearCalledSendRequest
;
162 exports
.safeCallbackApply
= safeCallbackApply
;
163 exports
.getExtensionStackTrace
= getExtensionStackTrace
;
166 exports
.handleResponse
= handleResponse
;