| OLD | NEW | 
|---|
|  | (Empty) | 
| 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. |  | 
| 4 |  | 
| 5 var handleUncaughtException = require('uncaught_exception_handler').handle; |  | 
| 6 var lastError = require('lastError'); |  | 
| 7 var logging = requireNative('logging'); |  | 
| 8 var natives = requireNative('sendRequest'); |  | 
| 9 var processNatives = requireNative('process'); |  | 
| 10 var validate = require('schemaUtils').validate; |  | 
| 11 |  | 
| 12 // All outstanding requests from sendRequest(). |  | 
| 13 var requests = {}; |  | 
| 14 |  | 
| 15 // Used to prevent double Activity Logging for API calls that use both custom |  | 
| 16 // bindings and ExtensionFunctions (via sendRequest). |  | 
| 17 var calledSendRequest = false; |  | 
| 18 |  | 
| 19 // Runs a user-supplied callback safely. |  | 
| 20 function safeCallbackApply(name, request, callback, args) { |  | 
| 21   try { |  | 
| 22     $Function.apply(callback, request, args); |  | 
| 23   } catch (e) { |  | 
| 24     var errorMessage = "Error in response to " + name + ": " + e; |  | 
| 25     if (request.stack && request.stack != '') |  | 
| 26       errorMessage += "\n" + request.stack; |  | 
| 27     handleUncaughtException(errorMessage, e); |  | 
| 28   } |  | 
| 29 } |  | 
| 30 |  | 
| 31 // Callback handling. |  | 
| 32 function handleResponse(requestId, name, success, responseList, error) { |  | 
| 33   // The chrome objects we will set lastError on. Really we should only be |  | 
| 34   // setting this on the callback's chrome object, but set on ours too since |  | 
| 35   // it's conceivable that something relies on that. |  | 
| 36   var callerChrome = chrome; |  | 
| 37 |  | 
| 38   try { |  | 
| 39     var request = requests[requestId]; |  | 
| 40     logging.DCHECK(request != null); |  | 
| 41 |  | 
| 42     // lastError needs to be set on the caller's chrome object no matter what, |  | 
| 43     // though chances are it's the same as ours (it will be different when |  | 
| 44     // calling API methods on other contexts). |  | 
| 45     if (request.callback) |  | 
| 46       callerChrome = natives.GetGlobal(request.callback).chrome; |  | 
| 47 |  | 
| 48     lastError.clear(chrome); |  | 
| 49     if (callerChrome !== chrome) |  | 
| 50       lastError.clear(callerChrome); |  | 
| 51 |  | 
| 52     if (!success) { |  | 
| 53       if (!error) |  | 
| 54         error = "Unknown error."; |  | 
| 55       lastError.set(name, error, request.stack, chrome); |  | 
| 56       if (callerChrome !== chrome) |  | 
| 57         lastError.set(name, error, request.stack, callerChrome); |  | 
| 58     } |  | 
| 59 |  | 
| 60     if (request.customCallback) { |  | 
| 61       safeCallbackApply(name, |  | 
| 62                         request, |  | 
| 63                         request.customCallback, |  | 
| 64                         $Array.concat([name, request], responseList)); |  | 
| 65     } |  | 
| 66 |  | 
| 67     if (request.callback) { |  | 
| 68       // Validate callback in debug only -- and only when the |  | 
| 69       // caller has provided a callback. Implementations of api |  | 
| 70       // calls may not return data if they observe the caller |  | 
| 71       // has not provided a callback. |  | 
| 72       if (logging.DCHECK_IS_ON() && !error) { |  | 
| 73         if (!request.callbackSchema.parameters) |  | 
| 74           throw new Error(name + ": no callback schema defined"); |  | 
| 75         validate(responseList, request.callbackSchema.parameters); |  | 
| 76       } |  | 
| 77       safeCallbackApply(name, request, request.callback, responseList); |  | 
| 78     } |  | 
| 79 |  | 
| 80     if (error && |  | 
| 81         !lastError.hasAccessed(chrome) && |  | 
| 82         !lastError.hasAccessed(callerChrome)) { |  | 
| 83       // The native call caused an error, but the developer didn't check |  | 
| 84       // runtime.lastError. |  | 
| 85       // Notify the developer of the error via the (error) console. |  | 
| 86       console.error("Unchecked runtime.lastError while running " + |  | 
| 87           (name || "unknown") + ": " + error + |  | 
| 88           (request.stack ? "\n" + request.stack : "")); |  | 
| 89     } |  | 
| 90   } finally { |  | 
| 91     delete requests[requestId]; |  | 
| 92     lastError.clear(chrome); |  | 
| 93     if (callerChrome !== chrome) |  | 
| 94       lastError.clear(callerChrome); |  | 
| 95   } |  | 
| 96 }; |  | 
| 97 |  | 
| 98 function getExtensionStackTrace(call_name) { |  | 
| 99   var stack = $String.split(new Error().stack, '\n'); |  | 
| 100   var id = processNatives.GetExtensionId(); |  | 
| 101 |  | 
| 102   // Remove stack frames before and after that weren't associated with the |  | 
| 103   // extension. |  | 
| 104   return $Array.join(stack.filter(function(line) { |  | 
| 105     return line.indexOf(id) != -1; |  | 
| 106   }), '\n'); |  | 
| 107 } |  | 
| 108 |  | 
| 109 function prepareRequest(args, argSchemas) { |  | 
| 110   var request = {}; |  | 
| 111   var argCount = args.length; |  | 
| 112 |  | 
| 113   // Look for callback param. |  | 
| 114   if (argSchemas.length > 0 && |  | 
| 115       argSchemas[argSchemas.length - 1].type == "function") { |  | 
| 116     request.callback = args[args.length - 1]; |  | 
| 117     request.callbackSchema = argSchemas[argSchemas.length - 1]; |  | 
| 118     --argCount; |  | 
| 119   } |  | 
| 120 |  | 
| 121   request.args = []; |  | 
| 122   for (var k = 0; k < argCount; k++) { |  | 
| 123     request.args[k] = args[k]; |  | 
| 124   } |  | 
| 125 |  | 
| 126   return request; |  | 
| 127 } |  | 
| 128 |  | 
| 129 // Send an API request and optionally register a callback. |  | 
| 130 // |optArgs| is an object with optional parameters as follows: |  | 
| 131 // - customCallback: a callback that should be called instead of the standard |  | 
| 132 //   callback. |  | 
| 133 // - nativeFunction: the v8 native function to handle the request, or |  | 
| 134 //   StartRequest if missing. |  | 
| 135 // - forIOThread: true if this function should be handled on the browser IO |  | 
| 136 //   thread. |  | 
| 137 // - preserveNullInObjects: true if it is safe for null to be in objects. |  | 
| 138 function sendRequest(functionName, args, argSchemas, optArgs) { |  | 
| 139   calledSendRequest = true; |  | 
| 140   if (!optArgs) |  | 
| 141     optArgs = {}; |  | 
| 142   var request = prepareRequest(args, argSchemas); |  | 
| 143   request.stack = getExtensionStackTrace(); |  | 
| 144   if (optArgs.customCallback) { |  | 
| 145     request.customCallback = optArgs.customCallback; |  | 
| 146   } |  | 
| 147 |  | 
| 148   var nativeFunction = optArgs.nativeFunction || natives.StartRequest; |  | 
| 149 |  | 
| 150   var requestId = natives.GetNextRequestId(); |  | 
| 151   request.id = requestId; |  | 
| 152   requests[requestId] = request; |  | 
| 153 |  | 
| 154   var hasCallback = request.callback || optArgs.customCallback; |  | 
| 155   return nativeFunction(functionName, |  | 
| 156                         request.args, |  | 
| 157                         requestId, |  | 
| 158                         hasCallback, |  | 
| 159                         optArgs.forIOThread, |  | 
| 160                         optArgs.preserveNullInObjects); |  | 
| 161 } |  | 
| 162 |  | 
| 163 function getCalledSendRequest() { |  | 
| 164   return calledSendRequest; |  | 
| 165 } |  | 
| 166 |  | 
| 167 function clearCalledSendRequest() { |  | 
| 168   calledSendRequest = false; |  | 
| 169 } |  | 
| 170 |  | 
| 171 exports.sendRequest = sendRequest; |  | 
| 172 exports.getCalledSendRequest = getCalledSendRequest; |  | 
| 173 exports.clearCalledSendRequest = clearCalledSendRequest; |  | 
| 174 exports.safeCallbackApply = safeCallbackApply; |  | 
| 175 exports.getExtensionStackTrace = getExtensionStackTrace; |  | 
| 176 |  | 
| 177 // Called by C++. |  | 
| 178 exports.handleResponse = handleResponse; |  | 
| OLD | NEW | 
|---|