From 4a1cc2ddd035f5c269e82ab6f7686e2e60d3b3ea Mon Sep 17 00:00:00 2001 From: Josh Story Date: Mon, 3 Apr 2023 09:34:53 -0700 Subject: [PATCH] Fix logic around attribute seralization (#26526) There was a bug in the attribute seralization for stylesheet resources injected by the Fizz runtime. For boolean properties the attribute value was set to an empty string but later immediately set to a string coerced value. This PR fixes that bug and refactors the code paths to be clearer --- .../src/server/ReactDOMServerFormatConfig.js | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js b/packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js index 4168b40cb7afc..60d53197bd44a 100644 --- a/packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js +++ b/packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js @@ -3926,48 +3926,51 @@ function writeStyleResourceAttributeInJS( return; // Attribute renames - case 'className': + case 'className': { attributeName = 'class'; + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); break; - + } // Booleans - case 'hidden': + case 'hidden': { if (value === false) { return; } attributeValue = ''; break; - + } // Santized URLs case 'src': case 'href': { + value = sanitizeURL(value); if (__DEV__) { checkAttributeStringCoercion(value, attributeName); } - value = sanitizeURL(value); + attributeValue = '' + (value: any); break; } default: { + if ( + // unrecognized event handlers are not SSR'd and we (apparently) + // use on* as hueristic for these handler props + name.length > 2 && + (name[0] === 'o' || name[0] === 'O') && + (name[1] === 'n' || name[1] === 'N') + ) { + return; + } if (!isAttributeNameSafe(name)) { return; } + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); } } - - if ( - // shouldIgnoreAttribute - // We have already filtered out null/undefined and reserved words. - name.length > 2 && - (name[0] === 'o' || name[0] === 'O') && - (name[1] === 'n' || name[1] === 'N') - ) { - return; - } - - if (__DEV__) { - checkAttributeStringCoercion(value, attributeName); - } - attributeValue = '' + (value: any); writeChunk(destination, arrayInterstitial); writeChunk( destination, @@ -4119,48 +4122,53 @@ function writeStyleResourceAttributeInAttr( return; // Attribute renames - case 'className': + case 'className': { attributeName = 'class'; + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); break; + } // Booleans - case 'hidden': + case 'hidden': { if (value === false) { return; } attributeValue = ''; break; + } // Santized URLs case 'src': case 'href': { + value = sanitizeURL(value); if (__DEV__) { checkAttributeStringCoercion(value, attributeName); } - value = sanitizeURL(value); + attributeValue = '' + (value: any); break; } default: { + if ( + // unrecognized event handlers are not SSR'd and we (apparently) + // use on* as hueristic for these handler props + name.length > 2 && + (name[0] === 'o' || name[0] === 'O') && + (name[1] === 'n' || name[1] === 'N') + ) { + return; + } if (!isAttributeNameSafe(name)) { return; } + if (__DEV__) { + checkAttributeStringCoercion(value, attributeName); + } + attributeValue = '' + (value: any); } } - - if ( - // shouldIgnoreAttribute - // We have already filtered out null/undefined and reserved words. - name.length > 2 && - (name[0] === 'o' || name[0] === 'O') && - (name[1] === 'n' || name[1] === 'N') - ) { - return; - } - - if (__DEV__) { - checkAttributeStringCoercion(value, attributeName); - } - attributeValue = '' + (value: any); writeChunk(destination, arrayInterstitial); writeChunk( destination,