Repository: facebook/react
File: packages/react-dom-bindings/src/client/ReactDOMComponent.js (JavaScript)

Code before:
          warnForPropDifference(propKey, serverValue, value, serverDifferences);
          continue;
        }
      // fallthrough
      case 'src':
      case 'href':
        if (enableFilterEmptyStringAttributesDOM) {
          if (
            value === '' &&
            // <a href=""> is fine for "reload" links.
            !(tag === 'a' && propKey === 'href') &&
            !(tag === 'object' && propKey === 'data')
          ) {
            if (__DEV__) {
              if (propKey === 'src') {
                console.error(
                  'An empty string ("") was passed to the %s attribute. ' +
                    'This may cause the browser to download the whole page again over the network. ' +
                    'To fix this, either do not render the element at all ' +
                    'or pass null to %s instead of an empty string.',
                  propKey,
                  propKey,
                );
              } else {
                console.error(
                  'An empty string ("") was passed to the %s attribute. ' +
                    'To fix this, either do not render the element at all ' +
                    'or pass null to %s instead of an empty string.',
                  propKey,
                  propKey,
                );
              }
            }
            hydrateSanitizedAttribute(
              domElement,
              propKey,
              propKey,
              null,
              extraAttributes,
              serverDifferences,
            );
            continue;
          }
        }
        hydrateSanitizedAttribute(
          domElement,
          propKey,
          propKey,
          value,
          extraAttributes,
          serverDifferences,

Review comment (security):
I think we should probably skip `hydrateSanitizedAttribute` below if we already warned above.

I.e. call `continue` in the branch above.

Otherwise we end up both logging the error and with a hydration error, because the server will have omitted this attribute.

The hydration error is also not correct because it's not what the client would've done.

Code after:
      case 'href':
        if (
          value === '' &&
          // <a href=""> is fine for "reload" links.
          !(tag === 'a' && propKey === 'href') &&
          !(tag === 'object' && propKey === 'data')
        ) {
          if (__DEV__) {
            if (propKey === 'src') {
              console.error(
                'An empty string ("") was passed to the %s attribute. ' +
                  'This may cause the browser to download the whole page again over the network. ' +
                  'To fix this, either do not render the element at all ' +
                  'or pass null to %s instead of an empty string.',
                propKey,
                propKey,
              );
            } else {
              console.error(
                'An empty string ("") was passed to the %s attribute. ' +
                  'To fix this, either do not render the element at all ' +
                  'or pass null to %s instead of an empty string.',
                propKey,
                propKey,
              );
            }
          }
          hydrateSanitizedAttribute(
            domElement,
            propKey,
            propKey,
            null,
            extraAttributes,
            serverDifferences,
          );
          continue;
        } else {
          hydrateSanitizedAttribute(
            domElement,
            propKey,
            propKey,
            value,
            extraAttributes,
            serverDifferences,
          );
          continue;
        }
      case 'action':
      case 'formAction': {
        const serverValue = domElement.getAttribute(propKey);
        if (typeof value === 'function') {