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
Josh Story committed
Apr 3, 2023 at 09:34 UTC
4a1cc2ddd035f5c269e82ab6f7686e2e60d3b3ea
1 file changed
+46
-38
packages/react-dom-bindings/src/server/ReactDOMServerFormatConfig.js
+46
-38
@@ -3926,48 +3926,51 @@ function writeStyleResourceAttributeInJS(
3926
return;
3927
3928
// Attribute renames
3929
- case 'className':
3929
+ case 'className': {
3930
attributeName = 'class';
3931
+ if (__DEV__) {
3932
+ checkAttributeStringCoercion(value, attributeName);
3933
+ }
3934
+ attributeValue = '' + (value: any);
3935
break;
3932
-
3936
+ }
3937
// Booleans
3934
- case 'hidden':
3938
+ case 'hidden': {
3939
if (value === false) {
3940
return;
3941
}
3942
attributeValue = '';
3943
break;
3940
-
3944
+ }
3945
// Santized URLs
3946
case 'src':
3947
case 'href': {
3948
+ value = sanitizeURL(value);
3949
if (__DEV__) {
3950
checkAttributeStringCoercion(value, attributeName);
3951
}
3947
- value = sanitizeURL(value);
3952
+ attributeValue = '' + (value: any);
3953
break;
3954
}
3955
default: {
3956
+ if (
3957
+ // unrecognized event handlers are not SSR'd and we (apparently)
3958
+ // use on* as hueristic for these handler props
3959
+ name.length > 2 &&
3960
+ (name[0] === 'o' || name[0] === 'O') &&
3961
+ (name[1] === 'n' || name[1] === 'N')
3962
+ ) {
3963
+ return;
3964
+ }
3965
if (!isAttributeNameSafe(name)) {
3966
return;
3967
}
3968
+ if (__DEV__) {
3969
+ checkAttributeStringCoercion(value, attributeName);
3970
+ }
3971
+ attributeValue = '' + (value: any);
3972
}
3973
}
3956
-
3957
- if (
3958
- // shouldIgnoreAttribute
3959
- // We have already filtered out null/undefined and reserved words.
3960
- name.length > 2 &&
3961
- (name[0] === 'o' || name[0] === 'O') &&
3962
- (name[1] === 'n' || name[1] === 'N')
3963
- ) {
3964
- return;
3965
- }
3966
-
3967
- if (__DEV__) {
3968
- checkAttributeStringCoercion(value, attributeName);
3969
- }
3970
- attributeValue = '' + (value: any);
3974
writeChunk(destination, arrayInterstitial);
3975
writeChunk(
3976
destination,
@@ -4119,48 +4122,53 @@ function writeStyleResourceAttributeInAttr(
4122
return;
4123
4124
// Attribute renames
4122
- case 'className':
4125
+ case 'className': {
4126
attributeName = 'class';
4127
+ if (__DEV__) {
4128
+ checkAttributeStringCoercion(value, attributeName);
4129
+ }
4130
+ attributeValue = '' + (value: any);
4131
break;
4132
+ }
4133
4134
// Booleans
4127
- case 'hidden':
4135
+ case 'hidden': {
4136
if (value === false) {
4137
return;
4138
}
4139
attributeValue = '';
4140
break;
4141
+ }
4142
4143
// Santized URLs
4144
case 'src':
4145
case 'href': {
4146
+ value = sanitizeURL(value);
4147
if (__DEV__) {
4148
checkAttributeStringCoercion(value, attributeName);
4149
}
4140
- value = sanitizeURL(value);
4150
+ attributeValue = '' + (value: any);
4151
break;
4152
}
4153
default: {
4154
+ if (
4155
+ // unrecognized event handlers are not SSR'd and we (apparently)
4156
+ // use on* as hueristic for these handler props
4157
+ name.length > 2 &&
4158
+ (name[0] === 'o' || name[0] === 'O') &&
4159
+ (name[1] === 'n' || name[1] === 'N')
4160
+ ) {
4161
+ return;
4162
+ }
4163
if (!isAttributeNameSafe(name)) {
4164
return;
4165
}
4166
+ if (__DEV__) {
4167
+ checkAttributeStringCoercion(value, attributeName);
4168
+ }
4169
+ attributeValue = '' + (value: any);
4170
}
4171
}
4149
-
4150
- if (
4151
- // shouldIgnoreAttribute
4152
- // We have already filtered out null/undefined and reserved words.
4153
- name.length > 2 &&
4154
- (name[0] === 'o' || name[0] === 'O') &&
4155
- (name[1] === 'n' || name[1] === 'N')
4156
- ) {
4157
- return;
4158
- }
4159
-
4160
- if (__DEV__) {
4161
- checkAttributeStringCoercion(value, attributeName);
4162
- }
4163
- attributeValue = '' + (value: any);
4172
writeChunk(destination, arrayInterstitial);
4173
writeChunk(
4174
destination,