@@ -1411,13 +1411,9 @@ function serializeTemporaryReference(
1411
1411
}
1412
1412
1413
1413
function serializeLargeTextString ( request : Request , text : string ) : string {
1414
- request . pendingChunks += 2 ;
1414
+ request . pendingChunks ++ ;
1415
1415
const textId = request . nextChunkId ++ ;
1416
- const textChunk = stringToChunk ( text ) ;
1417
- const binaryLength = byteLengthOfChunk ( textChunk ) ;
1418
- const row = textId . toString ( 16 ) + ':T' + binaryLength . toString ( 16 ) + ',' ;
1419
- const headerChunk = stringToChunk ( row ) ;
1420
- request . completedRegularChunks . push ( headerChunk , textChunk ) ;
1416
+ emitTextChunk ( request , textId , text ) ;
1421
1417
return serializeByValueID ( textId ) ;
1422
1418
}
1423
1419
@@ -1467,27 +1463,9 @@ function serializeTypedArray(
1467
1463
tag : string ,
1468
1464
typedArray : $ArrayBufferView ,
1469
1465
) : string {
1470
- if ( enableTaint ) {
1471
- if ( TaintRegistryByteLengths . has ( typedArray . byteLength ) ) {
1472
- // If we have had any tainted values of this length, we check
1473
- // to see if these bytes matches any entries in the registry.
1474
- const tainted = TaintRegistryValues . get (
1475
- binaryToComparableString ( typedArray ) ,
1476
- ) ;
1477
- if ( tainted !== undefined ) {
1478
- throwTaintViolation ( tainted . message ) ;
1479
- }
1480
- }
1481
- }
1482
- request . pendingChunks += 2 ;
1466
+ request . pendingChunks ++ ;
1483
1467
const bufferId = request . nextChunkId ++ ;
1484
- // TODO: Convert to little endian if that's not the server default.
1485
- const binaryChunk = typedArrayToBinaryChunk ( typedArray ) ;
1486
- const binaryLength = byteLengthOfBinaryChunk ( binaryChunk ) ;
1487
- const row =
1488
- bufferId . toString ( 16 ) + ':' + tag + binaryLength . toString ( 16 ) + ',' ;
1489
- const headerChunk = stringToChunk ( row ) ;
1490
- request . completedRegularChunks . push ( headerChunk , binaryChunk ) ;
1468
+ emitTypedArrayChunk ( request , bufferId , tag , typedArray ) ;
1491
1469
return serializeByValueID ( bufferId ) ;
1492
1470
}
1493
1471
@@ -2321,6 +2299,42 @@ function emitDebugChunk(
2321
2299
request.completedRegularChunks.push(processedChunk);
2322
2300
}
2323
2301
2302
+ function emitTypedArrayChunk (
2303
+ request : Request ,
2304
+ id : number ,
2305
+ tag : string ,
2306
+ typedArray : $ArrayBufferView ,
2307
+ ) : void {
2308
+ if ( enableTaint ) {
2309
+ if ( TaintRegistryByteLengths . has ( typedArray . byteLength ) ) {
2310
+ // If we have had any tainted values of this length, we check
2311
+ // to see if these bytes matches any entries in the registry.
2312
+ const tainted = TaintRegistryValues . get (
2313
+ binaryToComparableString ( typedArray ) ,
2314
+ ) ;
2315
+ if ( tainted !== undefined ) {
2316
+ throwTaintViolation ( tainted . message ) ;
2317
+ }
2318
+ }
2319
+ }
2320
+ request . pendingChunks ++ ; // Extra chunk for the header.
2321
+ // TODO: Convert to little endian if that's not the server default.
2322
+ const binaryChunk = typedArrayToBinaryChunk ( typedArray ) ;
2323
+ const binaryLength = byteLengthOfBinaryChunk ( binaryChunk ) ;
2324
+ const row = id . toString ( 16 ) + ':' + tag + binaryLength . toString ( 16 ) + ', ';
2325
+ const headerChunk = stringToChunk ( row ) ;
2326
+ request . completedRegularChunks . push ( headerChunk , binaryChunk ) ;
2327
+ }
2328
+
2329
+ function emitTextChunk ( request : Request , id : number , text : string ) : void {
2330
+ request . pendingChunks ++ ; // Extra chunk for the header.
2331
+ const textChunk = stringToChunk ( text ) ;
2332
+ const binaryLength = byteLengthOfChunk ( textChunk ) ;
2333
+ const row = id . toString ( 16 ) + ':T' + binaryLength . toString ( 16 ) + ',' ;
2334
+ const headerChunk = stringToChunk ( row ) ;
2335
+ request . completedRegularChunks . push ( headerChunk , textChunk ) ;
2336
+ }
2337
+
2324
2338
function serializeEval(source: string): string {
2325
2339
if ( ! __DEV__ ) {
2326
2340
// These errors should never make it into a build so we don't need to encode them in codes.json
@@ -2681,6 +2695,96 @@ function forwardDebugInfo(
2681
2695
}
2682
2696
}
2683
2697
2698
+ function emitChunk (
2699
+ request : Request ,
2700
+ task : Task ,
2701
+ value : ReactClientValue ,
2702
+ ) : void {
2703
+ const id = task . id ;
2704
+ // For certain types we have special types, we typically outlined them but
2705
+ // we can emit them directly for this row instead of through an indirection.
2706
+ if ( typeof value === 'string' ) {
2707
+ if ( enableTaint ) {
2708
+ const tainted = TaintRegistryValues . get ( value ) ;
2709
+ if ( tainted !== undefined ) {
2710
+ throwTaintViolation ( tainted . message ) ;
2711
+ }
2712
+ }
2713
+ emitTextChunk(request, id, value);
2714
+ return;
2715
+ }
2716
+ if ( enableBinaryFlight ) {
2717
+ if ( value instanceof ArrayBuffer ) {
2718
+ emitTypedArrayChunk ( request , id , 'A' , new Uint8Array ( value ) ) ;
2719
+ return ;
2720
+ }
2721
+ if (value instanceof Int8Array) {
2722
+ // char
2723
+ emitTypedArrayChunk ( request , id , 'O' , value ) ;
2724
+ return ;
2725
+ }
2726
+ if (value instanceof Uint8Array) {
2727
+ // unsigned char
2728
+ emitTypedArrayChunk ( request , id , 'o' , value ) ;
2729
+ return ;
2730
+ }
2731
+ if (value instanceof Uint8ClampedArray) {
2732
+ // unsigned clamped char
2733
+ emitTypedArrayChunk ( request , id , 'U' , value ) ;
2734
+ return ;
2735
+ }
2736
+ if (value instanceof Int16Array) {
2737
+ // sort
2738
+ emitTypedArrayChunk ( request , id , 'S' , value ) ;
2739
+ return ;
2740
+ }
2741
+ if (value instanceof Uint16Array) {
2742
+ // unsigned short
2743
+ emitTypedArrayChunk ( request , id , 's' , value ) ;
2744
+ return ;
2745
+ }
2746
+ if (value instanceof Int32Array) {
2747
+ // long
2748
+ emitTypedArrayChunk ( request , id , 'L' , value ) ;
2749
+ return ;
2750
+ }
2751
+ if (value instanceof Uint32Array) {
2752
+ // unsigned long
2753
+ emitTypedArrayChunk ( request , id , 'l' , value ) ;
2754
+ return ;
2755
+ }
2756
+ if (value instanceof Float32Array) {
2757
+ // float
2758
+ emitTypedArrayChunk ( request , id , 'G' , value ) ;
2759
+ return ;
2760
+ }
2761
+ if (value instanceof Float64Array) {
2762
+ // double
2763
+ emitTypedArrayChunk ( request , id , 'g' , value ) ;
2764
+ return ;
2765
+ }
2766
+ if (value instanceof BigInt64Array) {
2767
+ // number
2768
+ emitTypedArrayChunk ( request , id , 'M' , value ) ;
2769
+ return ;
2770
+ }
2771
+ if (value instanceof BigUint64Array) {
2772
+ // unsigned number
2773
+ // We use "m" instead of "n" since JSON can start with "null"
2774
+ emitTypedArrayChunk ( request , id , 'm' , value ) ;
2775
+ return ;
2776
+ }
2777
+ if (value instanceof DataView) {
2778
+ emitTypedArrayChunk ( request , id , 'V' , value ) ;
2779
+ return ;
2780
+ }
2781
+ }
2782
+ // For anything else we need to try to serialize it using JSON.
2783
+ // $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2784
+ const json : string = stringify ( value , task . toJSON ) ;
2785
+ emitModelChunk ( request , task . id , json ) ;
2786
+ }
2787
+
2684
2788
const emptyRoot = { } ;
2685
2789
2686
2790
function retryTask(request: Request, task: Task): void {
@@ -2725,19 +2829,17 @@ function retryTask(request: Request, task: Task): void {
2725
2829
task.keyPath = null;
2726
2830
task.implicitSlot = false;
2727
2831
2728
- let json: string;
2729
2832
if (typeof resolvedModel === 'object' && resolvedModel !== null ) {
2730
2833
// Object might contain unresolved values like additional elements.
2731
2834
// This is simulating what the JSON loop would do if this was part of it.
2732
- // $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2733
- json = stringify ( resolvedModel , task . toJSON ) ;
2835
+ emitChunk ( request , task , resolvedModel ) ;
2734
2836
} else {
2735
2837
// If the value is a string, it means it's a terminal value and we already escaped it
2736
2838
// We don't need to escape it again so it's not passed the toJSON replacer.
2737
2839
// $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2738
- json = stringify ( resolvedModel ) ;
2840
+ const json : string = stringify ( resolvedModel ) ;
2841
+ emitModelChunk ( request , task . id , json ) ;
2739
2842
}
2740
- emitModelChunk(request, task.id, json);
2741
2843
2742
2844
request.abortableTasks.delete(task);
2743
2845
task.status = COMPLETED;
@@ -2789,9 +2891,7 @@ function tryStreamTask(request: Request, task: Task): void {
2789
2891
debugID = null ;
2790
2892
}
2791
2893
try {
2792
- // $FlowFixMe[incompatible-type] stringify can return null for undefined but we never do
2793
- const json : string = stringify ( task . model , task . toJSON ) ;
2794
- emitModelChunk ( request , task . id , json ) ;
2894
+ emitChunk ( request , task , task . model ) ;
2795
2895
} finally {
2796
2896
if ( __DEV__ ) {
2797
2897
debugID = prevDebugID ;
0 commit comments