@@ -32,6 +32,7 @@ const {
3232
3333const {
3434 AbortError,
35+ ErrnoException,
3536 codes : {
3637 ERR_ARG_NOT_ITERABLE ,
3738 ERR_ILLEGAL_CONSTRUCTOR ,
@@ -51,6 +52,13 @@ const {
5152 markPromiseAsHandled,
5253} = internalBinding ( 'util' ) ;
5354
55+ const {
56+ kReadBytesOrError,
57+ streamBaseState,
58+ } = internalBinding ( 'stream_wrap' ) ;
59+
60+ const { UV_EOF } = internalBinding ( 'uv' ) ;
61+
5462const {
5563 isArrayBufferView,
5664 isDataView,
@@ -123,6 +131,7 @@ const {
123131 resetQueue,
124132 resolvedRecord,
125133 setPromiseHandled,
134+ kStreamBase,
126135} = require ( 'internal/webstreams/util' ) ;
127136
128137const {
@@ -134,6 +143,7 @@ const {
134143 isWritableStreamDefaultWriter,
135144
136145 writableStreamAbort,
146+ writableStreamClose,
137147 writableStreamCloseQueuedOrInFlight,
138148 writableStreamDefaultWriterCloseWithErrorPropagation,
139149 writableStreamDefaultWriterRelease,
@@ -1462,6 +1472,83 @@ function readableStreamPipeTo(
14621472 preventCancel ,
14631473 signal ) {
14641474
1475+ const sourceStreamBase = source ?. [ kStreamBase ] ;
1476+ const destStreamBase = dest ?. [ kStreamBase ] ;
1477+
1478+ if ( sourceStreamBase !== undefined &&
1479+ destStreamBase !== undefined &&
1480+ signal === undefined &&
1481+ ! preventClose &&
1482+ ! preventAbort &&
1483+ ! preventCancel ) {
1484+ // Native C++ StreamPipe path for internal-to-internal piping.
1485+ // Ref: https://github.com/nodejs/performance/issues/134
1486+ const promise = PromiseWithResolvers ( ) ;
1487+
1488+ source [ kState ] . disturbed = true ;
1489+
1490+ let pipeError = null ;
1491+ let isComplete = false ;
1492+ const originalSourceOnread = sourceStreamBase . onread ;
1493+
1494+ sourceStreamBase . onread = ( arrayBuffer ) => {
1495+ const nread = streamBaseState [ kReadBytesOrError ] ;
1496+ if ( nread < 0 && nread !== UV_EOF ) {
1497+ pipeError = new ErrnoException ( nread , 'read' ) ;
1498+ }
1499+ if ( originalSourceOnread ) {
1500+ return originalSourceOnread ( arrayBuffer ) ;
1501+ }
1502+ } ;
1503+
1504+ function finalize ( error ) {
1505+ if ( isComplete ) return ;
1506+ isComplete = true ;
1507+ sourceStreamBase . onread = originalSourceOnread ;
1508+
1509+ if ( error ) {
1510+ if ( source [ kState ] . state === 'readable' ) {
1511+ readableStreamError ( source , error ) ;
1512+ }
1513+ if ( dest [ kState ] . state === 'writable' ) {
1514+ writableStreamAbort ( dest , error ) ;
1515+ }
1516+ promise . reject ( error ) ;
1517+ } else {
1518+ if ( source [ kState ] . state === 'readable' ) {
1519+ readableStreamClose ( source ) ;
1520+ }
1521+ if ( dest [ kState ] . state === 'writable' &&
1522+ ! writableStreamCloseQueuedOrInFlight ( dest ) ) {
1523+ PromisePrototypeThen (
1524+ writableStreamClose ( dest ) ,
1525+ ( ) => promise . resolve ( ) ,
1526+ ( err ) => promise . reject ( err ) ,
1527+ ) ;
1528+ } else {
1529+ promise . resolve ( ) ;
1530+ }
1531+ }
1532+ }
1533+
1534+ try {
1535+ const pipe = new StreamPipe ( sourceStreamBase , destStreamBase ) ;
1536+ pipe . onunpipe = ( ) => {
1537+ if ( pipeError ) {
1538+ finalize ( pipeError ) ;
1539+ }
1540+ } ;
1541+ pipe . oncomplete = ( ) => finalize ( pipeError ) ;
1542+ pipe . start ( ) ;
1543+ } catch ( error ) {
1544+ sourceStreamBase . onread = originalSourceOnread ;
1545+ promise . reject ( error ) ;
1546+ }
1547+
1548+ return promise . promise ;
1549+ }
1550+
1551+ // Use JS-based piping
14651552 let reader ;
14661553 let writer ;
14671554 let disposable ;
0 commit comments