Split escapeTextForBrowser into escapeTextContentForBrowser and quoteAttributeValueForBrowser

This commit is contained in:
Andreas Svensson
2015-02-04 13:44:38 +01:00
committed by syranide
parent 9174501771
commit 8ca058ac4e
9 changed files with 115 additions and 24 deletions
+2 -2
View File
@@ -25,7 +25,7 @@ var ReactMultiChild = require('ReactMultiChild');
var ReactPerf = require('ReactPerf');
var assign = require('Object.assign');
var escapeTextForBrowser = require('escapeTextForBrowser');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
var invariant = require('invariant');
var isEventSupported = require('isEventSupported');
var keyOf = require('keyOf');
@@ -284,7 +284,7 @@ ReactDOMComponent.Mixin = {
CONTENT_TYPES[typeof props.children] ? props.children : null;
var childrenToUse = contentToUse != null ? null : props.children;
if (contentToUse != null) {
return prefix + escapeTextForBrowser(contentToUse);
return prefix + escapeTextContentForBrowser(contentToUse);
} else if (childrenToUse != null) {
var mountImages = this.mountChildren(
childrenToUse,
+2 -2
View File
@@ -18,7 +18,7 @@ var ReactComponentBrowserEnvironment =
var ReactDOMComponent = require('ReactDOMComponent');
var assign = require('Object.assign');
var escapeTextForBrowser = require('escapeTextForBrowser');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
var invariant = require('invariant');
/**
@@ -67,7 +67,7 @@ assign(ReactDOMTextComponent.prototype, {
*/
mountComponent: function(rootID, transaction, context) {
this._rootNodeID = rootID;
var escapedText = escapeTextForBrowser(this._stringText);
var escapedText = escapeTextContentForBrowser(this._stringText);
if (transaction.renderToStaticMarkup) {
// Normally we'd wrap this in a `span` for the reasons stated above, but
@@ -431,6 +431,23 @@ describe('ReactDOMComponent', function() {
'style={{marginRight: spacing + \'em\'}} when using JSX.'
);
});
it("should properly escape text content and attributes values", function() {
expect(
React.renderToStaticMarkup(
React.DOM.div({
title: '\'"<>&',
style: {
textAlign: '\'"<>&'
}
}, '\'"<>&')
)
).toBe(
'<div title="&#x27;&quot;&lt;&gt;&amp;" style="text-align:&#x27;&quot;&lt;&gt;&amp;;">' +
'&#x27;&quot;&lt;&gt;&amp;' +
'</div>'
);
});
});
describe('unmountComponent', function() {
+7 -6
View File
@@ -14,7 +14,8 @@
var DOMProperty = require('DOMProperty');
var escapeTextForBrowser = require('escapeTextForBrowser');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
var memoizeStringOnly = require('memoizeStringOnly');
var warning = require('warning');
@@ -27,7 +28,7 @@ function shouldIgnoreValue(name, value) {
}
var processAttributeNameAndPrefix = memoizeStringOnly(function(name) {
return escapeTextForBrowser(name) + '="';
return escapeTextContentForBrowser(name) + '=';
});
if (__DEV__) {
@@ -82,7 +83,7 @@ var DOMPropertyOperations = {
*/
createMarkupForID: function(id) {
return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) +
escapeTextForBrowser(id) + '"';
quoteAttributeValueForBrowser(id);
},
/**
@@ -101,16 +102,16 @@ var DOMPropertyOperations = {
var attributeName = DOMProperty.getAttributeName[name];
if (DOMProperty.hasBooleanValue[name] ||
(DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
return escapeTextForBrowser(attributeName);
return escapeTextContentForBrowser(attributeName);
}
return processAttributeNameAndPrefix(attributeName) +
escapeTextForBrowser(value) + '"';
quoteAttributeValueForBrowser(value);
} else if (DOMProperty.isCustomAttribute(name)) {
if (value == null) {
return '';
}
return processAttributeNameAndPrefix(name) +
escapeTextForBrowser(value) + '"';
quoteAttributeValueForBrowser(value);
} else if (__DEV__) {
warnUnknownProperty(name);
}
+2 -2
View File
@@ -19,7 +19,7 @@
"use strict";
var ExecutionEnvironment = require('ExecutionEnvironment');
var escapeTextForBrowser = require('escapeTextForBrowser');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
var setInnerHTML = require('setInnerHTML');
/**
@@ -39,7 +39,7 @@ var setTextContent = function(node, text) {
if (ExecutionEnvironment.canUseDOM) {
if (!('textContent' in document.documentElement)) {
setTextContent = function(node, text) {
setInnerHTML(node, escapeTextForBrowser(text));
setInnerHTML(node, escapeTextContentForBrowser(text));
};
}
}
@@ -11,17 +11,17 @@
'use strict';
describe('escapeTextForBrowser', function() {
describe('escapeTextContentForBrowser', function() {
var escapeTextForBrowser = require('escapeTextForBrowser');
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
it('should escape boolean to string', function() {
expect(escapeTextForBrowser(true)).toBe('true');
expect(escapeTextForBrowser(false)).toBe('false');
expect(escapeTextContentForBrowser(true)).toBe('true');
expect(escapeTextContentForBrowser(false)).toBe('false');
});
it('should escape object to string', function() {
var escaped = escapeTextForBrowser({
var escaped = escapeTextContentForBrowser({
toString: function() {
return 'ponys';
}
@@ -31,17 +31,17 @@ describe('escapeTextForBrowser', function() {
});
it('should escape number to string', function() {
expect(escapeTextForBrowser(42)).toBe('42');
expect(escapeTextContentForBrowser(42)).toBe('42');
});
it('should escape string', function() {
var escaped = escapeTextForBrowser('<script type=\'\' src=""></script>');
var escaped = escapeTextContentForBrowser('<script type=\'\' src=""></script>');
expect(escaped).not.toContain('<');
expect(escaped).not.toContain('>');
expect(escaped).not.toContain('\'');
expect(escaped).not.toContain('\"');
escaped = escapeTextForBrowser('&');
escaped = escapeTextContentForBrowser('&');
expect(escaped).toBe('&amp;');
});
@@ -0,0 +1,48 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
"use strict";
describe('quoteAttributeValueForBrowser', function() {
var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
it('should escape boolean to string', function() {
expect(quoteAttributeValueForBrowser(true)).toBe('"true"');
expect(quoteAttributeValueForBrowser(false)).toBe('"false"');
});
it('should escape object to string', function() {
var escaped = quoteAttributeValueForBrowser({
toString: function() {
return 'ponys';
}
});
expect(escaped).toBe('"ponys"');
});
it('should escape number to string', function() {
expect(quoteAttributeValueForBrowser(42)).toBe('"42"');
});
it('should escape string', function() {
var escaped = quoteAttributeValueForBrowser('<script type=\'\' src=""></script>');
expect(escaped).not.toContain('<');
expect(escaped).not.toContain('>');
expect(escaped).not.toContain('\'');
expect(escaped.substr(1, -1)).not.toContain('\"');
escaped = quoteAttributeValueForBrowser('&');
expect(escaped).toBe('"&amp;"');
});
});
@@ -6,8 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule escapeTextForBrowser
* @typechecks static-only
* @providesModule escapeTextContentForBrowser
*/
'use strict';
@@ -32,8 +31,8 @@ function escaper(match) {
* @param {*} text Text value to escape.
* @return {string} An escaped string.
*/
function escapeTextForBrowser(text) {
function escapeTextContentForBrowser(text) {
return ('' + text).replace(ESCAPE_REGEX, escaper);
}
module.exports = escapeTextForBrowser;
module.exports = escapeTextContentForBrowser;
@@ -0,0 +1,26 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule quoteAttributeValueForBrowser
*/
"use strict";
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
/**
* Escapes attribute value to prevent scripting attacks.
*
* @param {*} value Value to escape.
* @return {string} An escaped string.
*/
function quoteAttributeValueForBrowser(value) {
return '"' + escapeTextContentForBrowser(value) + '"';
}
module.exports = quoteAttributeValueForBrowser;