Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Side by Side Diff: remoting/webapp/crd/js/format_iq.js

Issue 1133913002: [Chromoting] Move shared webapp JS files from crd/js -> base/js (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 /**
6 * @fileoverview
7 * Module to format IQ messages so they can be displayed in the debug log.
8 */
9
10 'use strict';
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 /**
16 * @constructor
17 * @param {string} clientJid
18 * @param {string} hostJid
19 */
20 remoting.FormatIq = function(clientJid, hostJid) {
21 /** @private */
22 this.clientJid_ = clientJid;
23 /** @private */
24 this.hostJid_ = hostJid;
25 };
26
27 /**
28 * Verify that the only attributes on the given |node| are those specified
29 * in the |attrs| string.
30 *
31 * @param {Node} node The node to verify.
32 * @param {string} validAttrs Comma-separated list of valid attributes.
33 *
34 * @return {boolean} True if the node contains only valid attributes.
35 */
36 remoting.FormatIq.prototype.verifyAttributes = function(node, validAttrs) {
37 var attrs = ',' + validAttrs + ',';
38 var len = node.attributes.length;
39 for (var i = 0; i < len; i++) {
40 /** @type {Node} */
41 var attrNode = node.attributes[i];
42 var attr = attrNode.nodeName;
43 if (attrs.indexOf(',' + attr + ',') == -1) {
44 return false;
45 }
46 }
47 return true;
48 };
49
50 /**
51 * Calculate the 'pretty' version of data from the |server| node.
52 *
53 * @param {Node} server Xml node with server info.
54 *
55 * @return {?string} Formatted server string. Null if error.
56 */
57 remoting.FormatIq.prototype.calcServerString = function(server) {
58 if (!this.verifyAttributes(server, 'host,udp,tcp,tcpssl')) {
59 return null;
60 }
61 var host = server.getAttribute('host');
62 var udp = server.getAttribute('udp');
63 var tcp = server.getAttribute('tcp');
64 var tcpssl = server.getAttribute('tcpssl');
65
66 var str = "'" + host + "'";
67 if (udp)
68 str += ' udp:' + udp;
69 if (tcp)
70 str += ' tcp:' + tcp;
71 if (tcpssl)
72 str += ' tcpssl:' + tcpssl;
73
74 str += '; ';
75 return str;
76 };
77
78 /**
79 * Calc the 'pretty' version of channel data.
80 *
81 * @param {Node} channel Xml node with channel info.
82 *
83 * @return {?string} Formatted channel string. Null if error.
84 */
85 remoting.FormatIq.prototype.calcChannelString = function(channel) {
86 var name = channel.nodeName;
87 if (!this.verifyAttributes(channel, 'transport,version,codec')) {
88 return null;
89 }
90 var transport = channel.getAttribute('transport');
91 var version = channel.getAttribute('version');
92
93 var str = name + ' ' + transport + ' v' + version;
94 if (name == 'video') {
95 str += ' codec=' + channel.getAttribute('codec');
96 }
97 str += '; ';
98 return str;
99 };
100
101 /**
102 * Pretty print the jingleinfo from the given Xml node.
103 *
104 * @param {Node} query Xml query node with jingleinfo in the child nodes.
105 *
106 * @return {?string} Pretty version of jingleinfo. Null if error.
107 */
108 remoting.FormatIq.prototype.prettyJingleinfo = function(query) {
109 var nodes = query.childNodes;
110 var stun_servers = '';
111 var result = '';
112 for (var i = 0; i < nodes.length; i++) {
113 /** @type {Node} */
114 var node = nodes[i];
115 var name = node.nodeName;
116 if (name == 'stun') {
117 var sserver = '';
118 var stun_nodes = node.childNodes;
119 for(var s = 0; s < stun_nodes.length; s++) {
120 /** @type {Node} */
121 var stun_node = stun_nodes[s];
122 var sname = stun_node.nodeName;
123 if (sname == 'server') {
124 var stun_str = this.calcServerString(stun_node);
125 if (!stun_str) {
126 return null;
127 }
128 sserver += stun_str;
129 }
130 }
131 result += '\n stun ' + sserver;
132 } else if (name == 'relay') {
133 var token = '';
134 var rserver = '';
135 var relay_nodes = node.childNodes;
136 for(var r = 0; r < relay_nodes.length; r++) {
137 /** @type {Node} */
138 var relay_node = relay_nodes[r];
139 var rname = relay_node.nodeName;
140 if (rname == 'token') {
141 token = token + relay_node.textContent;
142 }
143 if (rname == 'server') {
144 var relay_str = this.calcServerString(relay_node);
145 if (!relay_str) {
146 return null;
147 }
148 rserver += relay_str;
149 }
150 }
151 result += '\n relay ' + rserver + ' token: ' + token;
152 } else {
153 return null;
154 }
155 }
156
157 return result;
158 };
159
160 /**
161 * Pretty print the session-initiate or session-accept info from the given
162 * Xml node.
163 *
164 * @param {Node} jingle Xml node with jingle session-initiate or session-accept
165 * info contained in child nodes.
166 *
167 * @return {?string} Pretty version of jingle stanza. Null if error.
168 */
169 remoting.FormatIq.prototype.prettySessionInitiateAccept = function(jingle) {
170 if (jingle.childNodes.length != 1) {
171 return null;
172 }
173 var content = jingle.firstChild;
174 if (content.nodeName != 'content') {
175 return null;
176 }
177 var content_children = content.childNodes;
178 var result = '';
179 for (var c = 0; c < content_children.length; c++) {
180 /** @type {Node} */
181 var content_child = content_children[c];
182 var cname = content_child.nodeName;
183 if (cname == 'description') {
184 var channels = '';
185 var resolution = '';
186 var auth = '';
187 var desc_children = content_child.childNodes;
188 for (var d = 0; d < desc_children.length; d++) {
189 /** @type {Node} */
190 var desc = desc_children[d];
191 var dname = desc.nodeName;
192 if (dname == 'control' || dname == 'event' || dname == 'video') {
193 var channel_str = this.calcChannelString(desc);
194 if (!channel_str) {
195 return null;
196 }
197 channels += channel_str;
198 } else if (dname == 'initial-resolution') {
199 resolution = desc.getAttribute('width') + 'x' +
200 desc.getAttribute('height');
201 } else if (dname == 'authentication') {
202 var auth_children = desc.childNodes;
203 for (var a = 0; a < auth_children.length; a++) {
204 /** @type {Node} */
205 var auth_info = auth_children[a];
206 if (auth_info.nodeName == 'auth-token') {
207 auth = auth + ' (auth-token) ' + auth_info.textContent;
208 } else if (auth_info.nodeName == 'certificate') {
209 auth = auth + ' (certificate) ' + auth_info.textContent;
210 } else if (auth_info.nodeName == 'master-key') {
211 auth = auth + ' (master-key) ' + auth_info.textContent;
212 } else {
213 return null;
214 }
215 }
216 } else {
217 return null;
218 }
219 }
220 result += '\n channels: ' + channels;
221 result += '\n auth: ' + auth;
222 result += '\n initial resolution: ' + resolution;
223 } else if (cname == 'transport') {
224 // The 'transport' node is currently empty.
225 var transport_children = content_child.childNodes;
226 if (transport_children.length != 0) {
227 return null;
228 }
229 } else {
230 return null;
231 }
232 }
233 return result;
234 };
235
236 /**
237 * Pretty print the session-terminate info from the given Xml node.
238 *
239 * @param {Node} jingle Xml node with jingle session-terminate info contained in
240 * child nodes.
241 *
242 * @return {?string} Pretty version of jingle session-terminate stanza. Null if
243 * error.
244 */
245 remoting.FormatIq.prototype.prettySessionTerminate = function(jingle) {
246 if (jingle.childNodes.length != 1) {
247 return null;
248 }
249 var reason = jingle.firstChild;
250 if (reason.nodeName != 'reason' || reason.childNodes.length != 1) {
251 return null;
252 }
253 var info = reason.firstChild;
254 if (info.nodeName == 'success' || info.nodeName == 'general-error') {
255 return '\n reason=' + info.nodeName;
256 }
257 return null;
258 };
259
260 /**
261 * Pretty print the transport-info info from the given Xml node.
262 *
263 * @param {Node} jingle Xml node with jingle transport info contained in child
264 * nodes.
265 *
266 * @return {?string} Pretty version of jingle transport-info stanza. Null if
267 * error.
268 */
269 remoting.FormatIq.prototype.prettyTransportInfo = function(jingle) {
270 if (jingle.childNodes.length != 1) {
271 return null;
272 }
273 var content = jingle.firstChild;
274 if (content.nodeName != 'content') {
275 return null;
276 }
277 var transport = content.firstChild;
278 if (transport.nodeName != 'transport') {
279 return null;
280 }
281 var transport_children = transport.childNodes;
282 var result = '';
283 for (var t = 0; t < transport_children.length; t++) {
284 /** @type {Node} */
285 var candidate = transport_children[t];
286 if (candidate.nodeName != 'candidate') {
287 return null;
288 }
289 if (!this.verifyAttributes(candidate, 'name,address,port,preference,' +
290 'username,protocol,generation,password,type,' +
291 'network')) {
292 return null;
293 }
294 var name = candidate.getAttribute('name');
295 var address = candidate.getAttribute('address');
296 var port = candidate.getAttribute('port');
297 var pref = candidate.getAttribute('preference');
298 var username = candidate.getAttribute('username');
299 var protocol = candidate.getAttribute('protocol');
300 var generation = candidate.getAttribute('generation');
301 var password = candidate.getAttribute('password');
302 var type = candidate.getAttribute('type');
303 var network = candidate.getAttribute('network');
304
305 var info = name + ': ' + address + ':' + port + ' ' + protocol +
306 ' name:' + username + ' pwd:' + password +
307 ' pref:' + pref +
308 ' ' + type;
309 if (network) {
310 info = info + " network:'" + network + "'";
311 }
312 result += '\n ' + info;
313 }
314 return result;
315 };
316
317 /**
318 * Pretty print the jingle action contained in the given Xml node.
319 *
320 * @param {Node} jingle Xml node with jingle action contained in child nodes.
321 * @param {string} action String containing the jingle action.
322 *
323 * @return {?string} Pretty version of jingle action stanze. Null if error.
324 */
325 remoting.FormatIq.prototype.prettyJingleAction = function(jingle, action) {
326 if (action == 'session-initiate' || action == 'session-accept') {
327 return this.prettySessionInitiateAccept(jingle);
328 }
329 if (action == 'session-terminate') {
330 return this.prettySessionTerminate(jingle);
331 }
332 if (action == 'transport-info') {
333 return this.prettyTransportInfo(jingle);
334 }
335 return null;
336 };
337
338 /**
339 * Pretty print the jingle error information contained in the given Xml node.
340 *
341 * @param {Node} error Xml node containing error information in child nodes.
342 *
343 * @return {?string} Pretty version of error stanze. Null if error.
344 */
345 remoting.FormatIq.prototype.prettyError = function(error) {
346 if (!this.verifyAttributes(error, 'xmlns:err,code,type,err:hostname,' +
347 'err:bnsname,err:stacktrace')) {
348 return null;
349 }
350 var code = error.getAttribute('code');
351 var type = error.getAttribute('type');
352 var hostname = error.getAttribute('err:hostname');
353 var bnsname = error.getAttribute('err:bnsname');
354 var stacktrace = error.getAttribute('err:stacktrace');
355
356 var result = '\n error ' + code + ' ' + type + " hostname:'" +
357 hostname + "' bnsname:'" + bnsname + "'";
358 var children = error.childNodes;
359 for (var i = 0; i < children.length; i++) {
360 /** @type {Node} */
361 var child = children[i];
362 result += '\n ' + child.nodeName;
363 }
364 if (stacktrace) {
365 var stack = stacktrace.split(' | ');
366 result += '\n stacktrace:';
367 // We use 'length-1' because the stack trace ends with " | " which results
368 // in an empty string at the end after the split.
369 for (var s = 0; s < stack.length - 1; s++) {
370 result += '\n ' + stack[s];
371 }
372 }
373 return result;
374 };
375
376 /**
377 * Print out the heading line for an iq node.
378 *
379 * @param {string} action String describing action (send/receive).
380 * @param {string} id Packet id.
381 * @param {string} desc Description of iq action for this node.
382 * @param {string|null} sid Session id.
383 *
384 * @return {string} Pretty version of stanza heading info.
385 */
386 remoting.FormatIq.prototype.prettyIqHeading = function(action, id, desc,
387 sid) {
388 var message = 'iq ' + action + ' id=' + id;
389 if (desc) {
390 message = message + ' ' + desc;
391 }
392 if (sid) {
393 message = message + ' sid=' + sid;
394 }
395 return message;
396 };
397
398 /**
399 * Print out an iq 'result'-type node.
400 *
401 * @param {string} action String describing action (send/receive).
402 * @param {NodeList} iq_list Node list containing the 'result' xml.
403 *
404 * @return {?string} Pretty version of Iq result stanza. Null if error.
405 */
406 remoting.FormatIq.prototype.prettyIqResult = function(action, iq_list) {
407 /** @type {Node} */
408 var iq = iq_list[0];
409 var id = iq.getAttribute('id');
410 var iq_children = iq.childNodes;
411
412 if (iq_children.length == 0) {
413 return this.prettyIqHeading(action, id, 'result (empty)', null);
414 } else if (iq_children.length == 1) {
415 /** @type {Node} */
416 var child = iq_children[0];
417 if (child.nodeName == 'query') {
418 if (!this.verifyAttributes(child, 'xmlns')) {
419 return null;
420 }
421 var xmlns = child.getAttribute('xmlns');
422 if (xmlns == 'google:jingleinfo') {
423 var result = this.prettyIqHeading(action, id, 'result ' + xmlns, null);
424 result += this.prettyJingleinfo(child);
425 return result;
426 }
427 return '';
428 } else if (child.nodeName == 'rem:log-result') {
429 if (!this.verifyAttributes(child, 'xmlns:rem')) {
430 return null;
431 }
432 return this.prettyIqHeading(action, id, 'result (log-result)', null);
433 }
434 }
435 return null;
436 };
437
438 /**
439 * Print out an Iq 'get'-type node.
440 *
441 * @param {string} action String describing action (send/receive).
442 * @param {NodeList} iq_list Node containing the 'get' xml.
443 *
444 * @return {?string} Pretty version of Iq get stanza. Null if error.
445 */
446 remoting.FormatIq.prototype.prettyIqGet = function(action, iq_list) {
447 /** @type {Node} */
448 var iq = iq_list[0];
449 var id = iq.getAttribute('id');
450 var iq_children = iq.childNodes;
451
452 if (iq_children.length != 1) {
453 return null;
454 }
455
456 /** @type {Node} */
457 var query = iq_children[0];
458 if (query.nodeName != 'query') {
459 return null;
460 }
461 if (!this.verifyAttributes(query, 'xmlns')) {
462 return null;
463 }
464 var xmlns = query.getAttribute('xmlns');
465 return this.prettyIqHeading(action, id, 'get ' + xmlns, null);
466 };
467
468 /**
469 * Print out an iq 'set'-type node.
470 *
471 * @param {string} action String describing action (send/receive).
472 * @param {NodeList} iq_list Node containing the 'set' xml.
473 *
474 * @return {?string} Pretty version of Iq set stanza. Null if error.
475 */
476 remoting.FormatIq.prototype.prettyIqSet = function(action, iq_list) {
477 /** @type {Node} */
478 var iq = iq_list[0];
479 var id = iq.getAttribute('id');
480 var iq_children = iq.childNodes;
481
482 var children = iq_children.length;
483 if (children == 1) {
484 /** @type {Node} */
485 var child = iq_children[0];
486 if (child.nodeName == 'gr:log') {
487 var grlog = child;
488 if (!this.verifyAttributes(grlog, 'xmlns:gr')) {
489 return null;
490 }
491
492 if (grlog.childNodes.length != 1) {
493 return null;
494 }
495 var grentry = grlog.firstChild;
496 if (grentry.nodeName != 'gr:entry') {
497 return null;
498 }
499 if (!this.verifyAttributes(grentry, 'role,event-name,session-state,' +
500 'os-name,cpu,browser-version,' +
501 'webapp-version')) {
502 return null;
503 }
504 var role = grentry.getAttribute('role');
505 var event_name = grentry.getAttribute('event-name');
506 var session_state = grentry.getAttribute('session-state');
507 var os_name = grentry.getAttribute('os-name');
508 var cpu = grentry.getAttribute('cpu');
509 var browser_version = grentry.getAttribute('browser-version');
510 var webapp_version = grentry.getAttribute('webapp-version');
511
512 var result = this.prettyIqHeading(action, id, role + ' ' + event_name +
513 ' ' + session_state, null);
514 result += '\n ' + os_name + ' ' + cpu + " browser:" + browser_version +
515 " webapp:" + webapp_version;
516 return result;
517 }
518 if (child.nodeName == 'jingle') {
519 var jingle = child;
520 if (!this.verifyAttributes(jingle, 'xmlns,action,sid,initiator')) {
521 return null;
522 }
523
524 var jingle_action = jingle.getAttribute('action');
525 var sid = jingle.getAttribute('sid');
526
527 var result = this.prettyIqHeading(action, id, 'set ' + jingle_action,
528 sid);
529 var action_str = this.prettyJingleAction(jingle, jingle_action);
530 if (!action_str) {
531 return null;
532 }
533 return result + action_str;
534 }
535 }
536 return null;
537 };
538
539 /**
540 * Print out an iq 'error'-type node.
541 *
542 * @param {string} action String describing action (send/receive).
543 * @param {NodeList} iq_list Node containing the 'error' xml.
544 *
545 * @return {?string} Pretty version of iq error stanza. Null if error parsing
546 * this stanza.
547 */
548 remoting.FormatIq.prototype.prettyIqError = function(action, iq_list) {
549 /** @type {Node} */
550 var iq = iq_list[0];
551 var id = iq.getAttribute('id');
552 var iq_children = iq.childNodes;
553
554 var children = iq_children.length;
555 if (children != 2) {
556 return null;
557 }
558
559 /** @type {Node} */
560 var jingle = iq_children[0];
561 if (jingle.nodeName != 'jingle') {
562 return null;
563 }
564 if (!this.verifyAttributes(jingle, 'xmlns,action,sid,initiator')) {
565 return null;
566 }
567 var jingle_action = jingle.getAttribute('action');
568 var sid = jingle.getAttribute('sid');
569 var result = this.prettyIqHeading(action, id, 'error from ' + jingle_action,
570 sid);
571 var action_str = this.prettyJingleAction(jingle, jingle_action);
572 if (!action_str) {
573 return null;
574 }
575 result += action_str;
576
577 /** @type {Node} */
578 var error = iq_children[1];
579 if (error.nodeName != 'cli:error') {
580 return null;
581 }
582
583 var error_str = this.prettyError(error);
584 if (!error_str) {
585 return null;
586 }
587 result += error_str;
588 return result;
589 };
590
591 /**
592 * Try to log a pretty-print the given IQ stanza (XML).
593 * Return true if the stanza was successfully printed.
594 *
595 * @param {boolean} send True if we're sending this stanza; false for receiving.
596 * @param {string} message The XML stanza to add to the log.
597 *
598 * @return {?string} Pretty version of the Iq stanza. Null if error.
599 */
600 remoting.FormatIq.prototype.prettyIq = function(send, message) {
601 var parser = new DOMParser();
602 var xml = parser.parseFromString(message, 'text/xml');
603
604 var iq_list = xml.getElementsByTagName('iq');
605
606 if (iq_list && iq_list.length > 0) {
607 /** @type {Node} */
608 var iq = iq_list[0];
609 if (!this.verifyAttributes(iq, 'xmlns,xmlns:cli,id,to,from,type'))
610 return null;
611
612 // Verify that the to/from fields match the expected sender/receiver.
613 var to = iq.getAttribute('to');
614 var from = iq.getAttribute('from');
615 var action = '';
616 var bot = remoting.settings.DIRECTORY_BOT_JID;
617 if (send) {
618 if (to && to != this.hostJid_ && to != bot) {
619 console.warn('FormatIq: bad to: ' + to);
620 return null;
621 }
622 if (from && from != this.clientJid_) {
623 console.warn('FormatIq: bad from: ' + from);
624 return null;
625 }
626
627 action = "send";
628 if (to == bot) {
629 action = action + " (to bot)";
630 }
631 } else {
632 if (to && to != this.clientJid_) {
633 console.warn('FormatIq: bad to: ' + to);
634 return null;
635 }
636 if (from && from != this.hostJid_ && from != bot) {
637 console.warn('FormatIq: bad from: ' + from);
638 return null;
639 }
640
641 action = "receive";
642 if (from == bot) {
643 action = action + " (from bot)";
644 }
645 }
646
647 var type = iq.getAttribute('type');
648 if (type == 'result') {
649 return this.prettyIqResult(action, iq_list);
650 } else if (type == 'get') {
651 return this.prettyIqGet(action, iq_list);
652 } else if (type == 'set') {
653 return this.prettyIqSet(action, iq_list);
654 } else if (type == 'error') {
655 return this.prettyIqError(action, iq_list);
656 }
657 }
658
659 return null;
660 };
661
662 /**
663 * Return a pretty-formatted string for the IQ stanza being sent.
664 * If the stanza cannot be made pretty, then a string with a raw dump of the
665 * stanza will be returned.
666 *
667 * @param {string} message The XML stanza to make pretty.
668 *
669 * @return {string} Pretty version of XML stanza being sent. A raw dump of the
670 * stanza is returned if there was a parsing error.
671 */
672 remoting.FormatIq.prototype.prettifySendIq = function(message) {
673 var result = this.prettyIq(true, message);
674 if (!result) {
675 // Fall back to showing the raw stanza.
676 return 'Sending Iq: ' + message;
677 }
678 return result;
679 };
680
681 /**
682 * Return a pretty-formatted string for the IQ stanza that was received.
683 * If the stanza cannot be made pretty, then a string with a raw dump of the
684 * stanza will be returned.
685 *
686 * @param {string} message The XML stanza to make pretty.
687 *
688 * @return {string} Pretty version of XML stanza that was received. A raw dump
689 * of the stanza is returned if there was a parsing error.
690 */
691 remoting.FormatIq.prototype.prettifyReceiveIq = function(message) {
692 var result = this.prettyIq(false, message);
693 if (!result) {
694 // Fall back to showing the raw stanza.
695 return 'Receiving Iq: ' + message;
696 }
697 return result;
698 };
OLDNEW
« no previous file with comments | « remoting/webapp/crd/js/fallback_signal_strategy_unittest.js ('k') | remoting/webapp/crd/js/host.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698