Skip to content

Commit 85c1c9a

Browse files
committed
Perform hasOwnProperty check in Relay Flight
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.
1 parent 16e6dad commit 85c1c9a

File tree

4 files changed

+61
-12
lines changed

4 files changed

+61
-12
lines changed

packages/react-transport-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ export function processErrorChunk(
9090
};
9191
}
9292

93+
const hasOwnProperty = Object.prototype.hasOwnProperty;
94+
9395
function convertModelToJSON(
9496
request: Request,
9597
parent: {+[key: string]: ReactModel} | $ReadOnlyArray<ReactModel>,
@@ -107,12 +109,14 @@ function convertModelToJSON(
107109
} else {
108110
const jsonObj: {[key: string]: JSONValue} = {};
109111
for (const nextKey in json) {
110-
jsonObj[nextKey] = convertModelToJSON(
111-
request,
112-
json,
113-
nextKey,
114-
json[nextKey],
115-
);
112+
if (hasOwnProperty.call(json, nextKey)) {
113+
jsonObj[nextKey] = convertModelToJSON(
114+
request,
115+
json,
116+
nextKey,
117+
json[nextKey],
118+
);
119+
}
116120
}
117121
return jsonObj;
118122
}

packages/react-transport-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,23 @@ describe('ReactFlightDOMRelay', () => {
222222
const model = readThrough(transport);
223223
expect(model).toEqual(14);
224224
});
225+
226+
it('should warn in DEV if a class instance polyfill is passed to a host component', () => {
227+
function Bar() {}
228+
229+
function Foo() {}
230+
Foo.prototype = Object.create(Bar.prototype);
231+
// This is enumerable which some polyfills do.
232+
Foo.prototype.constructor = Foo;
233+
Foo.prototype.method = function() {};
234+
235+
expect(() => {
236+
const transport = [];
237+
ReactDOMFlightRelayServer.render(<input value={new Foo()} />, transport);
238+
readThrough(transport);
239+
}).toErrorDev(
240+
'Only plain objects can be passed to client components from server components. ',
241+
{withoutStack: true},
242+
);
243+
});
225244
});

packages/react-transport-native-relay/src/ReactFlightNativeRelayServerHostConfig.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ export function processErrorChunk(
9090
};
9191
}
9292

93+
const hasOwnProperty = Object.prototype.hasOwnProperty;
94+
9395
function convertModelToJSON(
9496
request: Request,
9597
parent: {+[key: string]: ReactModel} | $ReadOnlyArray<ReactModel>,
@@ -107,12 +109,14 @@ function convertModelToJSON(
107109
} else {
108110
const jsonObj: {[key: string]: JSONValue} = {};
109111
for (const nextKey in json) {
110-
jsonObj[nextKey] = convertModelToJSON(
111-
request,
112-
json,
113-
nextKey,
114-
json[nextKey],
115-
);
112+
if (hasOwnProperty.call(json, nextKey)) {
113+
jsonObj[nextKey] = convertModelToJSON(
114+
request,
115+
json,
116+
nextKey,
117+
json[nextKey],
118+
);
119+
}
116120
}
117121
return jsonObj;
118122
}

packages/react-transport-native-relay/src/__tests__/ReactFlightNativeRelay-test.internal.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,26 @@ describe('ReactFlightNativeRelay', () => {
124124
nativeFabricUIManager.__dumpHierarchyForJestTestsOnly(),
125125
).toMatchSnapshot();
126126
});
127+
128+
it('should warn in DEV if a class instance polyfill is passed to a host component', () => {
129+
function Bar() {}
130+
131+
function Foo() {}
132+
Foo.prototype = Object.create(Bar.prototype);
133+
// This is enumerable which some polyfills do.
134+
Foo.prototype.constructor = Foo;
135+
Foo.prototype.method = function() {};
136+
137+
expect(() => {
138+
const transport = [];
139+
ReactNativeFlightRelayServer.render(
140+
<input value={new Foo()} />,
141+
transport,
142+
);
143+
readThrough(transport);
144+
}).toErrorDev(
145+
'Only plain objects can be passed to client components from server components. ',
146+
{withoutStack: true},
147+
);
148+
});
127149
});

0 commit comments

Comments
 (0)