| OLD | NEW |
| (Empty) |
| 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. | |
| 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 |