Index: Source/devtools/front_end/network/RequestJSONView.js |
diff --git a/Source/devtools/front_end/network/RequestJSONView.js b/Source/devtools/front_end/network/RequestJSONView.js |
index 2b972271c3b03b89fdc891b4fb8e8733a5d2e767..d4f1b22580ddce2169d8386613cc5e7ba73f2882 100644 |
--- a/Source/devtools/front_end/network/RequestJSONView.js |
+++ b/Source/devtools/front_end/network/RequestJSONView.js |
@@ -41,51 +41,139 @@ WebInspector.RequestJSONView = function(request, parsedJSON) |
this.element.classList.add("json"); |
} |
+// "false", "true", "null", ",", "{", "}", "[", "]", number, double-quoted string. |
+WebInspector.RequestJSONView._jsonToken = new RegExp('(?:false|true|null|[,\\{\\}\\[\\]]|(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)|(?:\"(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))*\"))', 'g'); |
+ |
+// Escaped unicode char. |
+WebInspector.RequestJSONView._escapedUnicode = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g'); |
+ |
+// Map from escaped char to its literal value. |
+WebInspector.RequestJSONView._standardEscapes = {'"': '"', '/': '/', '\\': '\\', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t'}; |
+ |
/** |
- * @param {string} text |
- * @return {?WebInspector.ParsedJSON} |
+ * @param {string} full |
+ * @param {string} standard |
+ * @param {string} unicode |
+ * @return {string} |
*/ |
-WebInspector.RequestJSONView.parseJSON = function(text) |
+WebInspector.RequestJSONView._unescape = function(full, standard, unicode) |
{ |
- var prefix = ""; |
+ return standard ? WebInspector.RequestJSONView._standardEscapes[standard] : String.fromCharCode(parseInt(unicode, 16)); |
+} |
- // Trim while(1), for(;;), weird numbers, etc. We need JSON start. |
- var start = /[{[]/.exec(text); |
- if (start && start.index) { |
- prefix = text.substring(0, start.index); |
- text = text.substring(start.index); |
- } |
+/** |
+ * @param {string} text |
+ * @return {string} |
+ */ |
+WebInspector.RequestJSONView._unescapeString = function(text) |
+{ |
+ return text.indexOf("\\") === -1 ? text : text.replace(WebInspector.RequestJSONView._escapedUnicode, WebInspector.RequestJSONView._unescape); |
+} |
- try { |
- return new WebInspector.ParsedJSON(JSON.parse(text), prefix, ""); |
- } catch (e) { |
- return null; |
+/** |
+ * @return {*} |
+ */ |
+WebInspector.RequestJSONView._buildObjectFromJSON = function(text) |
+{ |
+ var regExp = WebInspector.RequestJSONView._jsonToken; |
+ regExp.lastIndex = 0; |
+ var result = []; |
+ var tip = result; |
+ var stack = []; |
+ var key = undefined; |
+ var token = undefined; |
+ var lastToken = undefined; |
+ while (true) { |
+ var match = regExp.exec(text); |
+ if (match === null) |
+ break; |
+ lastToken = token; |
+ token = match[0]; |
+ var code = token.charCodeAt(0); |
+ if ((code === 0x5b) || (code === 0x7b)) { // [ or { |
+ var newTip = (code === 0x5b) ? [] : {}; |
+ tip[key || tip.length] = newTip; |
+ stack.push(tip); |
+ tip = newTip; |
+ } else if ((code === 0x5d) || (code === 0x7d)) { // ] or } |
+ tip = stack.pop(); |
+ if (!tip) |
+ break; |
+ } else if (code === 0x2C) { // , |
+ if ((tip instanceof Array) && (lastToken === undefined || lastToken === "[" || lastToken === ",")) |
+ tip[tip.length] = undefined; |
+ } else if (code === 0x22) { // " |
+ token = WebInspector.RequestJSONView._unescapeString(token.substring(1, token.length - 1)); |
+ if (!key) { |
+ if (tip instanceof Array) { |
+ key = tip.length; |
+ } else { |
+ key = token || ""; |
+ continue; |
+ } |
+ } |
+ tip[key] = token; |
+ } else if (code === 0x66) { // f |
+ tip[key || tip.length] = false; |
+ } else if (code === 0x6e) { // n |
+ tip[key || tip.length] = null; |
+ } else if (code === 0x74) { // t |
+ tip[key || tip.length] = true; |
+ } else { // sign or digit |
+ tip[key || tip.length] = +(token); |
+ } |
+ key = undefined; |
} |
+ return (result.length > 1) ? result : result[0]; |
} |
/** |
* @param {string} text |
* @return {?WebInspector.ParsedJSON} |
*/ |
-WebInspector.RequestJSONView.parseJSONP = function(text) |
+WebInspector.RequestJSONView.parseJSON = function(text) |
{ |
- // Taking everything between first and last parentheses |
- var start = text.indexOf("("); |
- var end = text.lastIndexOf(")"); |
- if (start == -1 || end == -1 || end < start) |
+ // Trim stubs like "while(1)", "for(;;)", weird numbers, etc. We need JSON start. |
+ var inner = WebInspector.RequestJSONView._findBrackets(text, "{", "}"); |
+ var inner2 = WebInspector.RequestJSONView._findBrackets(text, "[", "]"); |
+ inner = inner2.length > inner.length ? inner2 : inner; |
+ var inner3 = WebInspector.RequestJSONView._findBrackets(text, "(", ")"); |
+ if (inner3.length - 2 > inner.length) { |
+ inner = inner3; |
+ ++inner.start; |
+ --inner.end; |
+ } |
+ if (inner.length === -1) |
return null; |
- var prefix = text.substring(0, start + 1); |
- var suffix = text.substring(end); |
- text = text.substring(start + 1, end); |
+ |
+ var prefix = text.substring(0, inner.start); |
+ var suffix = text.substring(inner.end + 1); |
+ text = text.substring(inner.start, inner.end + 1); |
try { |
- return new WebInspector.ParsedJSON(JSON.parse(text), prefix, suffix); |
+ return new WebInspector.ParsedJSON(WebInspector.RequestJSONView._buildObjectFromJSON(text), prefix, suffix); |
} catch (e) { |
return null; |
} |
} |
+/** |
+ * @param {string} text |
+ * @param {string} open |
+ * @param {string} close |
+ * @return {{start: number, end: number, length: number}} |
+ */ |
+WebInspector.RequestJSONView._findBrackets = function(text, open, close) |
+{ |
+ var start = text.indexOf(open); |
+ var end = text.lastIndexOf(close); |
+ var length = end - start - 1; |
+ if (start == -1 || end == -1 || end < start) |
+ length = -1; |
+ return {start: start, end: end, length: length}; |
+} |
+ |
WebInspector.RequestJSONView.prototype = { |
wasShown: function() |
{ |