Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / remoting / webapp / base / js / xmpp_error_cache.js
blob79a91385ad3cf90b540390ede38e9a3cc507ca9c
1 // Copyright 2015 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.
6 /** @suppress {duplicate} */
7 var remoting = remoting || {};
9 (function() {
11 'use strict';
13 /**
14 * This class monitors incoming XMPP stanza and records the first
15 * error encountered. It also strips all PII from the error stanza,
16 * so that it can be uploaded to the cloud for error analysis.
18 * @constructor
21 remoting.XmppErrorCache = function() {
22 /** @private {remoting.ChromotingEvent.XmppError} */
23 this.firstError_ = null;
26 /**
27 * @return {remoting.ChromotingEvent.XmppError} The first XMPP error that the
28 * monitor encountered. Returns null if no errors have been encountered so
29 * far.
31 remoting.XmppErrorCache.prototype.getFirstError = function() {
32 return this.firstError_;
35 /**
36 * Monitor the incoming stanza for error.
38 * @param {Element} iqNode
40 remoting.XmppErrorCache.prototype.processStanza = function(iqNode) {
41 if (this.firstError_ != null) {
42 return;
44 // The XML structure is as follows:
45 // <iq type='error'>
46 // <jingle action='session-accept'/>
47 // <error type='modify' code=''/>
48 // </iq>
49 if (iqNode.getAttribute('type') != 'error') {
50 return;
53 var strippedStanza = this.stripPII_(iqNode);
54 this.firstError_ = new remoting.ChromotingEvent.XmppError(strippedStanza);
57 /**
58 * @param {Element} iqNode
59 * @return {string} Return a string representation of |iqNode| with all PII
60 * removed.
61 * @private
63 remoting.XmppErrorCache.prototype.stripPII_ = function(iqNode) {
64 var parser = new DOMParser();
65 var outDocument = parser.parseFromString('<iq/>', 'text/xml');
66 stripPII(iqNode, outDocument.firstElementChild);
67 return new XMLSerializer().serializeToString(outDocument.firstElementChild);
70 /**
71 * @param {Element} node
72 * @param {Element} outNode
74 function stripPII(node, outNode) {
75 var attributesWhiteList = new Set([
76 'action',
77 'code',
78 'codec',
79 'creator',
80 'height',
81 'id',
82 'name',
83 'sid',
84 'supported-methods',
85 'transport',
86 'type',
87 'version',
88 'width',
89 'xmlns',
90 ]);
92 var nodesWhiteList = new Set([
93 'jingle',
94 'content',
95 'description',
96 'error',
97 'standard-ice',
98 'control',
99 'event',
100 'video',
101 'audio',
102 'initial-resolution',
103 'authentication',
104 'quic-config',
105 'service-unavailable'
108 // Strip PII from attributes.
109 var attributes = node.attributes;
110 for (var i = 0; i < attributes.length; i++) {
111 var attribute = /** @type {Attr} */ (attributes[i]);
112 var value = 'REDACTED';
113 if (attributesWhiteList.has(attribute.nodeName)) {
114 value = attribute.nodeValue;
116 outNode.setAttribute(attribute.nodeName, value);
119 // Copy the text content.
120 if (node.childNodes.length == 1 &&
121 node.firstChild.nodeType == Node.TEXT_NODE) {
122 var textValue = 'REDACTED';
123 if (nodesWhiteList.has(node.tagName)) {
124 textValue = node.firstChild.nodeValue;
126 outNode.appendChild(outNode.ownerDocument.createTextNode(textValue));
127 return;
130 // Strip PII from child nodes.
131 var children = node.children;
132 for (i = 0; i < children.length; i++) {
133 var child = /** @type{Element}*/ (children[i]);
134 var childCopy = outNode.ownerDocument.createElement(child.tagName);
135 outNode.appendChild(childCopy);
136 stripPII(child, childCopy);
140 })();