@@ -595,7 +595,7 @@ test('Should handle 206 partial content', async t => {
595595 onBodySent ( ) {
596596 t . ok ( true , 'pass' )
597597 } ,
598- onHeaders ( status , _rawHeaders , resume , _statusMessage ) {
598+ onHeaders ( status , _rawHeaders , _resume , _statusMessage ) {
599599 t . strictEqual ( status , 200 )
600600 return true
601601 } ,
@@ -636,7 +636,7 @@ test('Should handle 206 partial content', async t => {
636636} )
637637
638638test ( 'Should handle 206 partial content - bad-etag' , async t => {
639- t = tspl ( t , { plan : 6 } )
639+ t = tspl ( t , { plan : 8 } )
640640
641641 const chunks = [ ]
642642
@@ -683,7 +683,7 @@ test('Should handle 206 partial content - bad-etag', async t => {
683683 onBodySent ( ) {
684684 t . ok ( true , 'pass' )
685685 } ,
686- onHeaders ( status , _rawHeaders , resume , _statusMessage ) {
686+ onHeaders ( _status , _rawHeaders , _resume , _statusMessage ) {
687687 t . ok ( true , 'pass' )
688688 return true
689689 } ,
@@ -697,6 +697,8 @@ test('Should handle 206 partial content - bad-etag', async t => {
697697 onError ( err ) {
698698 t . strictEqual ( Buffer . concat ( chunks ) . toString ( 'utf-8' ) , 'abc' )
699699 t . strictEqual ( err . code , 'UND_ERR_REQ_RETRY' )
700+ t . strictEqual ( err . message , 'ETag mismatch' )
701+ t . deepEqual ( err . data , { count : 2 } )
700702 }
701703 }
702704 }
@@ -1083,6 +1085,7 @@ test('Should be able to properly pass the minTimeout to the RetryContext when co
10831085
10841086 await t . completed
10851087} )
1088+
10861089test ( 'Issue#2986 - Handle custom 206' , async t => {
10871090 t = tspl ( t , { plan : 8 } )
10881091
@@ -1504,3 +1507,105 @@ test('Weak etags are ignored on range-requests', async t => {
15041507
15051508 await t . completed
15061509} )
1510+
1511+ test ( 'Should throw RequestRetryError when Content-Range mismatch' , async t => {
1512+ t = tspl ( t , { plan : 10 } )
1513+
1514+ const chunks = [ ]
1515+
1516+ // Took from: https://github.com/nxtedition/nxt-lib/blob/4b001ebc2f22cf735a398f35ff800dd553fe5933/test/undici/retry.js#L47
1517+ let x = 0
1518+ const server = createServer ( ( req , res ) => {
1519+ if ( x === 0 ) {
1520+ t . ok ( true , 'pass' )
1521+ res . setHeader ( 'etag' , 'asd' )
1522+ res . write ( 'abc' )
1523+ setTimeout ( ( ) => {
1524+ res . destroy ( )
1525+ } , 1e2 )
1526+ } else if ( x === 1 ) {
1527+ t . deepStrictEqual ( req . headers . range , 'bytes=3-' )
1528+ res . setHeader ( 'content-range' , 'bytes bad' ) // intentionally bad to trigger error
1529+ res . setHeader ( 'etag' , 'asd' )
1530+ res . statusCode = 206
1531+ res . end ( 'def' )
1532+ }
1533+ x ++
1534+ } )
1535+
1536+ const dispatchOptions = {
1537+ retryOptions : {
1538+ retry : function ( err , _ , done ) {
1539+ if ( err . code && err . code === 'UND_ERR_DESTROYED' ) {
1540+ return done ( false )
1541+ }
1542+
1543+ if ( err . statusCode === 206 ) return done ( err )
1544+
1545+ setTimeout ( done , 800 )
1546+ }
1547+ } ,
1548+ method : 'GET' ,
1549+ path : '/' ,
1550+ headers : {
1551+ 'content-type' : 'application/json'
1552+ }
1553+ }
1554+
1555+ server . listen ( 0 , ( ) => {
1556+ const client = new Client ( `http://localhost:${ server . address ( ) . port } ` )
1557+ const handler = new RetryHandler ( dispatchOptions , {
1558+ dispatch : ( ...args ) => {
1559+ return client . dispatch ( ...args )
1560+ } ,
1561+ handler : {
1562+ onRequestSent ( ) {
1563+ t . ok ( true , 'pass' )
1564+ } ,
1565+ onConnect ( ) {
1566+ t . ok ( true , 'pass' )
1567+ } ,
1568+ onBodySent ( ) {
1569+ t . ok ( true , 'pass' )
1570+ } ,
1571+ onHeaders ( status , _rawHeaders , _resume , _statusMessage ) {
1572+ t . strictEqual ( status , 200 )
1573+ return true
1574+ } ,
1575+ onData ( chunk ) {
1576+ chunks . push ( chunk )
1577+ return true
1578+ } ,
1579+ onComplete ( ) {
1580+ t . ifError ( 'should not complete' )
1581+ } ,
1582+ onError ( err ) {
1583+ t . strictEqual ( Buffer . concat ( chunks ) . toString ( 'utf-8' ) , 'abc' )
1584+ t . strictEqual ( err . code , 'UND_ERR_REQ_RETRY' )
1585+ t . strictEqual ( err . message , 'Content-Range mismatch' )
1586+ t . deepEqual ( err . data , { count : 2 } )
1587+ }
1588+ }
1589+ } )
1590+
1591+ client . dispatch (
1592+ {
1593+ method : 'GET' ,
1594+ path : '/' ,
1595+ headers : {
1596+ 'content-type' : 'application/json'
1597+ }
1598+ } ,
1599+ handler
1600+ )
1601+
1602+ after ( async ( ) => {
1603+ await client . close ( )
1604+
1605+ server . close ( )
1606+ await once ( server , 'close' )
1607+ } )
1608+ } )
1609+
1610+ await t . completed
1611+ } )
0 commit comments