@samitouri / QOS-React-2 / commits / 12627f93b5

Perform hasOwnProperty check in Relay Flight (#20220)

We simulate JSON.stringify in this loop so we should do a has own check. Otherwise we'll include things like constructor properties. This will actually make things throw less even when it should.

Sebastian Markbåge committed Nov 10, 2020 at 22:59 UTC 12627f93b5357032881412abcc014da53a0b70f8
4 files changed +61 -12
packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js
+10 -6
@@ -71,6 +71,8 @@ export function processErrorChunk(
71 ];
72 }
73
74 +const hasOwnProperty = Object.prototype.hasOwnProperty;
75 +
76 function convertModelToJSON(
77 request: Request,
78 parent: {+[key: string]: ReactModel} | $ReadOnlyArray<ReactModel>,
@@ -88,12 +90,14 @@ function convertModelToJSON(
90 } else {
91 const jsonObj: {[key: string]: JSONValue} = {};
92 for (const nextKey in json) {
91 - jsonObj[nextKey] = convertModelToJSON(
92 - request,
93 - json,
94 - nextKey,
95 - json[nextKey],
96 - );
93 + if (hasOwnProperty.call(json, nextKey)) {
94 + jsonObj[nextKey] = convertModelToJSON(
95 + request,
96 + json,
97 + nextKey,
98 + json[nextKey],
99 + );
100 + }
101 }
102 return jsonObj;
103 }
packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js
+19
@@ -214,4 +214,23 @@ describe('ReactFlightDOMRelay', () => {
214 const model = readThrough(transport);
215 expect(model).toEqual(14);
216 });
217 +
218 + it('should warn in DEV if a class instance polyfill is passed to a host component', () => {
219 + function Bar() {}
220 +
221 + function Foo() {}
222 + Foo.prototype = Object.create(Bar.prototype);
223 + // This is enumerable which some polyfills do.
224 + Foo.prototype.constructor = Foo;
225 + Foo.prototype.method = function() {};
226 +
227 + expect(() => {
228 + const transport = [];
229 + ReactDOMFlightRelayServer.render(<input value={new Foo()} />, transport);
230 + readThrough(transport);
231 + }).toErrorDev(
232 + 'Only plain objects can be passed to client components from server components. ',
233 + {withoutStack: true},
234 + );
235 + });
236 });
packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js
+10 -6
@@ -71,6 +71,8 @@ export function processErrorChunk(
71 ];
72 }
73
74 +const hasOwnProperty = Object.prototype.hasOwnProperty;
75 +
76 function convertModelToJSON(
77 request: Request,
78 parent: {+[key: string]: ReactModel} | $ReadOnlyArray<ReactModel>,
@@ -88,12 +90,14 @@ function convertModelToJSON(
90 } else {
91 const jsonObj: {[key: string]: JSONValue} = {};
92 for (const nextKey in json) {
91 - jsonObj[nextKey] = convertModelToJSON(
92 - request,
93 - json,
94 - nextKey,
95 - json[nextKey],
96 - );
93 + if (hasOwnProperty.call(json, nextKey)) {
94 + jsonObj[nextKey] = convertModelToJSON(
95 + request,
96 + json,
97 + nextKey,
98 + json[nextKey],
99 + );
100 + }
101 }
102 return jsonObj;
103 }
packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js
+22
@@ -105,4 +105,26 @@ describe('ReactFlightNativeRelay', () => {
105 nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
106 ).toMatchSnapshot();
107 });
108 +
109 + it('should warn in DEV if a class instance polyfill is passed to a host component', () => {
110 + function Bar() {}
111 +
112 + function Foo() {}
113 + Foo.prototype = Object.create(Bar.prototype);
114 + // This is enumerable which some polyfills do.
115 + Foo.prototype.constructor = Foo;
116 + Foo.prototype.method = function() {};
117 +
118 + expect(() => {
119 + const transport = [];
120 + ReactNativeFlightRelayServer.render(
121 + <input value={new Foo()} />,
122 + transport,
123 + );
124 + readThrough(transport);
125 + }).toErrorDev(
126 + 'Only plain objects can be passed to client components from server components. ',
127 + {withoutStack: true},
128 + );
129 + });
130 });