@@ -4,7 +4,8 @@ const assert = require('assert');
4
4
const { promiseResolvedWith, promiseRejectedWith, newPromise, resolvePromise, rejectPromise, uponPromise,
5
5
setPromiseIsHandledToTrue, waitForAllPromise, transformPromiseWith, uponFulfillment, uponRejection } =
6
6
require ( '../helpers/webidl.js' ) ;
7
- const { CopyDataBlockBytes, CreateArrayFromList, TransferArrayBuffer } = require ( './ecmascript.js' ) ;
7
+ const { CanTransferArrayBuffer, CopyDataBlockBytes, CreateArrayFromList, IsDetachedBuffer, TransferArrayBuffer } =
8
+ require ( './ecmascript.js' ) ;
8
9
const { IsNonNegativeNumber } = require ( './miscellaneous.js' ) ;
9
10
const { EnqueueValueWithSize, ResetQueue } = require ( './queue-with-sizes.js' ) ;
10
11
const { AcquireWritableStreamDefaultWriter, IsWritableStreamLocked, WritableStreamAbort,
@@ -983,8 +984,8 @@ function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescripto
983
984
assert ( bytesFilled <= pullIntoDescriptor . byteLength ) ;
984
985
assert ( bytesFilled % elementSize === 0 ) ;
985
986
986
- return new pullIntoDescriptor . viewConstructor (
987
- pullIntoDescriptor . buffer , pullIntoDescriptor . byteOffset , bytesFilled / elementSize ) ;
987
+ const buffer = TransferArrayBuffer ( pullIntoDescriptor . buffer ) ;
988
+ return new pullIntoDescriptor . viewConstructor ( buffer , pullIntoDescriptor . byteOffset , bytesFilled / elementSize ) ;
988
989
}
989
990
990
991
function ReadableByteStreamControllerEnqueue ( controller , chunk ) {
@@ -997,8 +998,23 @@ function ReadableByteStreamControllerEnqueue(controller, chunk) {
997
998
const buffer = chunk . buffer ;
998
999
const byteOffset = chunk . byteOffset ;
999
1000
const byteLength = chunk . byteLength ;
1001
+ if ( IsDetachedBuffer ( buffer ) === true ) {
1002
+ throw new TypeError ( 'chunk\'s buffer is detached and so cannot be enqueued' ) ;
1003
+ }
1000
1004
const transferredBuffer = TransferArrayBuffer ( buffer ) ;
1001
1005
1006
+ if ( controller . _pendingPullIntos . length > 0 ) {
1007
+ const firstPendingPullInto = controller . _pendingPullIntos [ 0 ] ;
1008
+ if ( IsDetachedBuffer ( firstPendingPullInto . buffer ) === true ) {
1009
+ throw new TypeError (
1010
+ 'The BYOB request\'s buffer has been detached and so cannot be filled with an enqueued chunk'
1011
+ ) ;
1012
+ }
1013
+ firstPendingPullInto . buffer = TransferArrayBuffer ( firstPendingPullInto . buffer ) ;
1014
+ }
1015
+
1016
+ ReadableByteStreamControllerInvalidateBYOBRequest ( controller ) ;
1017
+
1002
1018
if ( ReadableStreamHasDefaultReader ( stream ) === true ) {
1003
1019
if ( ReadableStreamGetNumReadRequests ( stream ) === 0 ) {
1004
1020
ReadableByteStreamControllerEnqueueChunkToQueue ( controller , transferredBuffer , byteOffset , byteLength ) ;
@@ -1041,8 +1057,7 @@ function ReadableByteStreamControllerError(controller, e) {
1041
1057
1042
1058
function ReadableByteStreamControllerFillHeadPullIntoDescriptor ( controller , size , pullIntoDescriptor ) {
1043
1059
assert ( controller . _pendingPullIntos . length === 0 || controller . _pendingPullIntos [ 0 ] === pullIntoDescriptor ) ;
1044
-
1045
- ReadableByteStreamControllerInvalidateBYOBRequest ( controller ) ;
1060
+ assert ( controller . _byobRequest === null ) ;
1046
1061
pullIntoDescriptor . bytesFilled += size ;
1047
1062
}
1048
1063
@@ -1160,9 +1175,17 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest)
1160
1175
1161
1176
const ctor = view . constructor ;
1162
1177
1163
- const buffer = TransferArrayBuffer ( view . buffer ) ;
1178
+ let buffer ;
1179
+ try {
1180
+ buffer = TransferArrayBuffer ( view . buffer ) ;
1181
+ } catch ( e ) {
1182
+ readIntoRequest . errorSteps ( e ) ;
1183
+ return ;
1184
+ }
1185
+
1164
1186
const pullIntoDescriptor = {
1165
1187
buffer,
1188
+ bufferByteLength : buffer . byteLength ,
1166
1189
byteOffset : view . byteOffset ,
1167
1190
byteLength : view . byteLength ,
1168
1191
bytesFilled : 0 ,
@@ -1216,12 +1239,29 @@ function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest)
1216
1239
function ReadableByteStreamControllerRespond ( controller , bytesWritten ) {
1217
1240
assert ( controller . _pendingPullIntos . length > 0 ) ;
1218
1241
1242
+ const firstDescriptor = controller . _pendingPullIntos [ 0 ] ;
1243
+ const state = controller . _stream . _state ;
1244
+
1245
+ if ( state === 'closed' ) {
1246
+ if ( bytesWritten !== 0 ) {
1247
+ throw new TypeError ( 'bytesWritten must be 0 when calling respond() on a closed stream' ) ;
1248
+ }
1249
+ } else {
1250
+ assert ( state === 'readable' ) ;
1251
+ if ( bytesWritten === 0 ) {
1252
+ throw new TypeError ( 'bytesWritten must be greater than 0 when calling respond() on a readable stream' ) ;
1253
+ }
1254
+ if ( firstDescriptor . bytesFilled + bytesWritten > firstDescriptor . byteLength ) {
1255
+ throw new RangeError ( 'bytesWritten out of range' ) ;
1256
+ }
1257
+ }
1258
+
1259
+ firstDescriptor . buffer = TransferArrayBuffer ( firstDescriptor . buffer ) ;
1260
+
1219
1261
ReadableByteStreamControllerRespondInternal ( controller , bytesWritten ) ;
1220
1262
}
1221
1263
1222
1264
function ReadableByteStreamControllerRespondInClosedState ( controller , firstDescriptor ) {
1223
- firstDescriptor . buffer = TransferArrayBuffer ( firstDescriptor . buffer ) ;
1224
-
1225
1265
assert ( firstDescriptor . bytesFilled === 0 ) ;
1226
1266
1227
1267
const stream = controller . _stream ;
@@ -1234,14 +1274,11 @@ function ReadableByteStreamControllerRespondInClosedState(controller, firstDescr
1234
1274
}
1235
1275
1236
1276
function ReadableByteStreamControllerRespondInReadableState ( controller , bytesWritten , pullIntoDescriptor ) {
1237
- if ( pullIntoDescriptor . bytesFilled + bytesWritten > pullIntoDescriptor . byteLength ) {
1238
- throw new RangeError ( 'bytesWritten out of range' ) ;
1239
- }
1277
+ assert ( pullIntoDescriptor . bytesFilled + bytesWritten <= pullIntoDescriptor . byteLength ) ;
1240
1278
1241
1279
ReadableByteStreamControllerFillHeadPullIntoDescriptor ( controller , bytesWritten , pullIntoDescriptor ) ;
1242
1280
1243
1281
if ( pullIntoDescriptor . bytesFilled < pullIntoDescriptor . elementSize ) {
1244
- // TODO: Figure out whether we should detach the buffer or not here.
1245
1282
return ;
1246
1283
}
1247
1284
@@ -1254,7 +1291,6 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri
1254
1291
ReadableByteStreamControllerEnqueueChunkToQueue ( controller , remainder , 0 , remainder . byteLength ) ;
1255
1292
}
1256
1293
1257
- pullIntoDescriptor . buffer = TransferArrayBuffer ( pullIntoDescriptor . buffer ) ;
1258
1294
pullIntoDescriptor . bytesFilled -= remainderSize ;
1259
1295
ReadableByteStreamControllerCommitPullIntoDescriptor ( controller . _stream , pullIntoDescriptor ) ;
1260
1296
@@ -1263,18 +1299,17 @@ function ReadableByteStreamControllerRespondInReadableState(controller, bytesWri
1263
1299
1264
1300
function ReadableByteStreamControllerRespondInternal ( controller , bytesWritten ) {
1265
1301
const firstDescriptor = controller . _pendingPullIntos [ 0 ] ;
1302
+ assert ( CanTransferArrayBuffer ( firstDescriptor . buffer ) === true ) ;
1266
1303
1267
- const state = controller . _stream . _state ;
1304
+ ReadableByteStreamControllerInvalidateBYOBRequest ( controller ) ;
1268
1305
1306
+ const state = controller . _stream . _state ;
1269
1307
if ( state === 'closed' ) {
1270
- if ( bytesWritten !== 0 ) {
1271
- throw new TypeError ( 'bytesWritten must be 0 when calling respond() on a closed stream' ) ;
1272
- }
1273
-
1308
+ assert ( bytesWritten === 0 ) ;
1274
1309
ReadableByteStreamControllerRespondInClosedState ( controller , firstDescriptor ) ;
1275
1310
} else {
1276
1311
assert ( state === 'readable' ) ;
1277
-
1312
+ assert ( bytesWritten > 0 ) ;
1278
1313
ReadableByteStreamControllerRespondInReadableState ( controller , bytesWritten , firstDescriptor ) ;
1279
1314
}
1280
1315
@@ -1283,24 +1318,42 @@ function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) {
1283
1318
1284
1319
function ReadableByteStreamControllerRespondWithNewView ( controller , view ) {
1285
1320
assert ( controller . _pendingPullIntos . length > 0 ) ;
1321
+ assert ( IsDetachedBuffer ( view . buffer ) === false ) ;
1286
1322
1287
1323
const firstDescriptor = controller . _pendingPullIntos [ 0 ] ;
1324
+ const state = controller . _stream . _state ;
1325
+
1326
+ if ( state === 'closed' ) {
1327
+ if ( view . byteLength !== 0 ) {
1328
+ throw new TypeError ( 'The view\'s length must be 0 when calling respondWithNewView() on a closed stream' ) ;
1329
+ }
1330
+ } else {
1331
+ assert ( state === 'readable' ) ;
1332
+ if ( view . byteLength === 0 ) {
1333
+ throw new TypeError (
1334
+ 'The view\'s length must be greater than 0 when calling respondWithNewView() on a readable stream'
1335
+ ) ;
1336
+ }
1337
+ }
1288
1338
1289
1339
if ( firstDescriptor . byteOffset + firstDescriptor . bytesFilled !== view . byteOffset ) {
1290
1340
throw new RangeError ( 'The region specified by view does not match byobRequest' ) ;
1291
1341
}
1292
- if ( firstDescriptor . byteLength !== view . byteLength ) {
1342
+ if ( firstDescriptor . bufferByteLength !== view . buffer . byteLength ) {
1293
1343
throw new RangeError ( 'The buffer of view has different capacity than byobRequest' ) ;
1294
1344
}
1345
+ if ( firstDescriptor . bytesFilled + view . byteLength > firstDescriptor . byteLength ) {
1346
+ throw new RangeError ( 'The region specified by view is larger than byobRequest' ) ;
1347
+ }
1295
1348
1296
- firstDescriptor . buffer = view . buffer ;
1349
+ firstDescriptor . buffer = TransferArrayBuffer ( view . buffer ) ;
1297
1350
1298
1351
ReadableByteStreamControllerRespondInternal ( controller , view . byteLength ) ;
1299
1352
}
1300
1353
1301
1354
function ReadableByteStreamControllerShiftPendingPullInto ( controller ) {
1355
+ assert ( controller . _byobRequest === null ) ;
1302
1356
const descriptor = controller . _pendingPullIntos . shift ( ) ;
1303
- ReadableByteStreamControllerInvalidateBYOBRequest ( controller ) ;
1304
1357
return descriptor ;
1305
1358
}
1306
1359
0 commit comments