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 chromesForLastError
= [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).
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
)});
53 error
= "Unknown error.";
54 $Array
.forEach(chromesForLastError
, function(c
) {
55 lastError
.set(name
, error
, request
.stack
, c
)
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 $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
89 var id
= processNatives
.GetExtensionId();
90 while (stack
.length
> 0 && stack
[0].indexOf(id
) == -1)
92 while (stack
.length
> 0 && stack
[stack
.length
- 1].indexOf(id
) == -1)
95 return stack
.join('\n');
98 function prepareRequest(args
, argSchemas
) {
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];
111 for (var k
= 0; k
< argCount
; k
++) {
112 request
.args
[k
] = args
[k
];
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
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
126 // - preserveNullInObjects: true if it is safe for null to be in objects.
127 function sendRequest(functionName
, args
, argSchemas
, optArgs
) {
128 calledSendRequest
= true;
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
,
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
;
165 exports
.handleResponse
= handleResponse
;