Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chrome / test / ext_auto / auto_provider / connection_handler.js
blob4e744b43b66455d8f639fad2bb6a1b755ec7c675
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 // Automation connection handler is responsible for reading requests from the
6 // stream, finding and executing appropriate extension API method.
7 function ConnectionHandler() {
8 // Event listener registration map socket->event->callback
9 this.eventListener_ = {};
12 ConnectionHandler.prototype = {
13 // Stream delegate callback.
14 onStreamError: function(stream) {
15 this.unregisterListeners_(stream);
18 // Stream delegate callback.
19 onStreamTerminated: function(stream) {
20 this.unregisterListeners_(stream);
23 // Pairs event |listenerMethod| with a given |stream|.
24 registerListener_: function(stream, eventName, eventObject,
25 listenerMethod) {
26 if (!this.eventListener_[stream.socketId_])
27 this.eventListener_[stream.socketId_] = {};
29 if (!this.eventListener_[stream.socketId_][eventName]) {
30 this.eventListener_[stream.socketId_][eventName] = {
31 'event': eventObject,
32 'method': listenerMethod };
36 // Removes event listeners.
37 unregisterListeners_: function(stream) {
38 if (!this.eventListener_[stream.socketId_])
39 return;
41 for (var eventName in this.eventListener_[stream.socketId_]) {
42 var listenerDefinition = this.eventListener_[stream.socketId_][eventName];
43 var removeFunction = listenerDefinition.event['removeListener'];
44 if (removeFunction) {
45 removeFunction.call(listenerDefinition.event,
46 listenerDefinition.method);
49 delete this.eventListener_[stream.socketId_];
52 // Finds appropriate method/event to invoke/register.
53 findExecutionTarget_: function(functionName) {
54 var funcSegments = functionName.split('.');
55 if (funcSegments.size < 2)
56 return null;
58 if (funcSegments[0] != 'chrome')
59 return null;
61 var eventName = "";
62 var prevSegName = null;
63 var prevSegment = null;
64 var segmentObject = null;
65 var segName = null;
66 for (var i = 0; i < funcSegments.length; i++) {
67 if (prevSegName) {
68 if (eventName.length)
69 eventName += '.';
71 eventName += prevSegName;
74 segName = funcSegments[i];
75 prevSegName = segName;
76 if (!segmentObject) {
77 // TODO(zelidrag): Get rid of this eval.
78 segmentObject = eval(segName);
79 continue;
82 prevSegment = segmentObject;
83 if (segmentObject[segName])
84 segmentObject = segmentObject[segName];
85 else
86 segmentObject = null;
88 if (segmentObject == window)
89 return null;
91 var isEventMethod = segName == 'addListener';
92 return {'method': segmentObject,
93 'eventName': (isEventMethod ? eventName : null),
94 'event': (isEventMethod ? prevSegment : null)};
97 // TODO(zelidrag): Figure out how to automatically detect or generate list of
98 // sync API methods.
99 isSyncFunction_: function(funcName) {
100 if (funcName == 'chrome.omnibox.setDefaultSuggestion')
101 return true;
103 return false;
106 // Parses |command|, finds appropriate JS method runs it with |argsJson|.
107 // If the method is an event registration, it will register an event listener
108 // method and start sending data from its callback.
109 processCommand_: function(stream, command, argsJson) {
110 var target = this.findExecutionTarget_(command);
111 if (!target || !target.method) {
112 return {'result': false,
113 'objectName': command};
116 var args = JSON.parse(decodeURIComponent(argsJson));
117 if (!args)
118 args = [];
120 console.log(command + '(' + decodeURIComponent(argsJson) + ')',
121 stream.socketId_);
122 // Check if we need to register an event listener.
123 if (target.event) {
124 // Register listener method.
125 var listener = function() {
126 stream.write(JSON.stringify({ 'type': 'eventCallback',
127 'eventName': target.eventName,
128 'arguments' : arguments}));
129 }.bind(this);
130 // Add event handler method to arguments.
131 args.push(listener);
132 args.push(null); // for |filters|.
133 target.method.apply(target.event, args);
134 this.registerListener_(stream, target.eventName,
135 target.event, listener);
136 stream.write(JSON.stringify({'type': 'eventRegistration',
137 'eventName': command}));
138 return {'result': true,
139 'wasEvent': true};
142 // Run extension method directly.
143 if (this.isSyncFunction_(command)) {
144 // Run sync method.
145 console.log(command + '(' + unescape(argsJson) + ')');
146 var result = target.method.apply(undefined, args);
147 stream.write(JSON.stringify({'type': 'methodResult',
148 'methodName': command,
149 'isCallback': false,
150 'result' : result}));
151 } else { // Async method.
152 // Add callback method to arguments.
153 args.push(function() {
154 stream.write(JSON.stringify({'type': 'methodCallback',
155 'methodName': command,
156 'isCallback': true,
157 'arguments' : arguments}));
158 }.bind(this));
159 target.method.apply(undefined, args);
161 return {'result': true,
162 'wasEvent': false};
165 arrayBufferToString_: function(buffer) {
166 var str = '';
167 var uArrayVal = new Uint8Array(buffer);
168 for(var s = 0; s < uArrayVal.length; s++) {
169 str += String.fromCharCode(uArrayVal[s]);
171 return str;
174 // Callback for stream read requests.
175 onStreamRead_: function(stream, readInfo) {
176 console.log("READ", readInfo);
177 // Parse the request.
178 var data = this.arrayBufferToString_(readInfo.data);
179 var spacePos = data.indexOf(" ");
180 try {
181 if (spacePos == -1) {
182 spacePos = data.indexOf("\r\n");
183 if (spacePos == -1)
184 throw {'code': 400, 'description': 'Bad Request'};
187 var verb = data.substring(0, spacePos);
188 var isEvent = false;
189 switch (verb) {
190 case 'TERMINATE':
191 throw {'code': 200, 'description': 'OK'};
192 break;
193 case 'RUN':
194 break;
195 case 'LISTEN':
196 this.isEvent = true;
197 break;
198 default:
199 throw {'code': 400, 'description': 'Bad Request: ' + verb};
200 return;
203 var command = data.substring(verb.length + 1);
204 var endLine = command.indexOf('\r\n');
205 if (endLine)
206 command = command.substring(0, endLine);
208 var objectNames = command;
209 var argsJson = null;
210 var funcNameEnd = command.indexOf("?");
211 if (funcNameEnd >= 0) {
212 objectNames = command.substring(0, funcNameEnd);
213 argsJson = command.substring(funcNameEnd + 1);
215 var functions = objectNames.split(',');
216 for (var i = 0; i < functions.length; i++) {
217 var objectName = functions[i];
218 var commandStatus =
219 this.processCommand_(stream, objectName, argsJson);
220 if (!commandStatus.result) {
221 throw {'code': 404,
222 'description': 'Not Found: ' + commandStatus.objectName};
224 // If we have run all requested commands, read the socket again.
225 if (i == (functions.length - 1)) {
226 setTimeout(function() {
227 this.readRequest_(stream);
228 }.bind(this), 0);
231 } catch(err) {
232 console.warn('Error', err);
233 stream.writeError(err.code, err.description);
237 // Reads next request from the |stream|.
238 readRequest_: function(stream) {
239 console.log("Reading socket " + stream.socketId_);
240 // Read in the data
241 stream.read(this.onStreamRead_.bind(this));