@@ -94,6 +94,8 @@ import getComponentNameFromType from 'shared/getComponentNameFromType';
9494
9595import { getOwnerStackByComponentInfoInDev } from 'shared/ReactComponentInfoStack' ;
9696
97+ import hasOwnProperty from 'shared/hasOwnProperty' ;
98+
9799import { injectInternals } from './ReactFlightClientDevToolsHook' ;
98100
99101import { OMITTED_PROP_ERROR } from 'shared/ReactFlightPropertyAccess' ;
@@ -159,6 +161,8 @@ const INITIALIZED = 'fulfilled';
159161const ERRORED = 'rejected' ;
160162const HALTED = 'halted' ; // DEV-only. Means it never resolves even if connection closes.
161163
164+ const __PROTO__ = '__proto__' ;
165+
162166type PendingChunk < T > = {
163167 status : 'pending' ,
164168 value : null | Array < InitializationReference | ( T => mixed ) > ,
@@ -1544,7 +1548,16 @@ function fulfillReference(
15441548 }
15451549 }
15461550 }
1547- value = value [ path [ i ] ] ;
1551+ const name = path [ i ] ;
1552+ if (
1553+ typeof value === 'object ' &&
1554+ value !== null &&
1555+ hasOwnProperty . call ( value , name )
1556+ ) {
1557+ value = value [ name ] ;
1558+ } else {
1559+ throw new Error ( 'Invalid reference.' ) ;
1560+ }
15481561 }
15491562
15501563 while (
@@ -1580,7 +1593,9 @@ function fulfillReference(
15801593 }
15811594
15821595 const mappedValue = map ( response , value , parentObject , key ) ;
1583- parentObject [ key ] = mappedValue ;
1596+ if ( key !== __PROTO__ ) {
1597+ parentObject [ key ] = mappedValue ;
1598+ }
15841599
15851600 // If this is the root object for a model reference, where `handler.value`
15861601 // is a stale `null`, the resolved value can be used directly.
@@ -1849,7 +1864,9 @@ function loadServerReference<A: Iterable<any>, T>(
18491864 response . _encodeFormAction ,
18501865 ) ;
18511866
1852- parentObject [ key ] = resolvedValue ;
1867+ if ( key !== __PROTO__ ) {
1868+ parentObject [ key ] = resolvedValue ;
1869+ }
18531870
18541871 // If this is the root object for a model reference, where `handler.value`
18551872 // is a stale `null`, the resolved value can be used directly.
@@ -2231,29 +2248,31 @@ function defineLazyGetter<T>(
22312248): any {
22322249 // We don't immediately initialize it even if it's resolved.
22332250 // Instead, we wait for the getter to get accessed.
2234- Object . defineProperty ( parentObject , key , {
2235- get : function ( ) {
2236- if ( chunk . status === RESOLVED_MODEL ) {
2237- // If it was now resolved, then we initialize it. This may then discover
2238- // a new set of lazy references that are then asked for eagerly in case
2239- // we get that deep.
2240- initializeModelChunk ( chunk ) ;
2241- }
2242- switch ( chunk . status ) {
2243- case INITIALIZED : {
2244- return chunk . value ;
2251+ if ( key !== __PROTO__ ) {
2252+ Object . defineProperty ( parentObject , key , {
2253+ get : function ( ) {
2254+ if ( chunk . status === RESOLVED_MODEL ) {
2255+ // If it was now resolved, then we initialize it. This may then discover
2256+ // a new set of lazy references that are then asked for eagerly in case
2257+ // we get that deep.
2258+ initializeModelChunk ( chunk ) ;
22452259 }
2246- case ERRORED :
2247- throw chunk . reason ;
2248- }
2249- // Otherwise, we didn't have enough time to load the object before it was
2250- // accessed or the connection closed. So we just log that it was omitted.
2251- // TODO: We should ideally throw here to indicate a difference.
2252- return OMITTED_PROP_ERROR ;
2253- } ,
2254- enumerable : true ,
2255- configurable : false ,
2256- } ) ;
2260+ switch ( chunk . status ) {
2261+ case INITIALIZED : {
2262+ return chunk . value ;
2263+ }
2264+ case ERRORED :
2265+ throw chunk . reason ;
2266+ }
2267+ // Otherwise, we didn't have enough time to load the object before it was
2268+ // accessed or the connection closed. So we just log that it was omitted.
2269+ // TODO: We should ideally throw here to indicate a difference.
2270+ return OMITTED_PROP_ERROR ;
2271+ } ,
2272+ enumerable : true ,
2273+ configurable : false ,
2274+ } ) ;
2275+ }
22572276 return null;
22582277}
22592278
@@ -2564,14 +2583,16 @@ function parseModelString(
25642583 // In DEV mode we encode omitted objects in logs as a getter that throws
25652584 // so that when you try to access it on the client, you know why that
25662585 // happened.
2567- Object . defineProperty ( parentObject , key , {
2568- get : function ( ) {
2569- // TODO: We should ideally throw here to indicate a difference.
2570- return OMITTED_PROP_ERROR ;
2571- } ,
2572- enumerable : true ,
2573- configurable : false ,
2574- } ) ;
2586+ if ( key !== __PROTO__ ) {
2587+ Object . defineProperty ( parentObject , key , {
2588+ get : function ( ) {
2589+ // TODO: We should ideally throw here to indicate a difference.
2590+ return OMITTED_PROP_ERROR ;
2591+ } ,
2592+ enumerable : true ,
2593+ configurable : false ,
2594+ } ) ;
2595+ }
25752596 return null ;
25762597 }
25772598 // Fallthrough
@@ -5183,6 +5204,9 @@ function parseModel<T>(response: Response, json: UninitializedModel): T {
51835204function createFromJSONCallback(response: Response) {
51845205 // $FlowFixMe[missing-this-annot]
51855206 return function ( key : string , value : JSONValue ) {
5207+ if ( key === __PROTO__ ) {
5208+ return undefined ;
5209+ }
51865210 if ( typeof value === 'string' ) {
51875211 // We can't use .bind here because we need the "this" value.
51885212 return parseModelString ( response , this , key , value ) ;
0 commit comments