Skip to content

Commit 5debe80

Browse files
Jake ChampionJakeChampion
authored andcommitted
fix: Request.prototype.clone - Do not create a body on the new request if the request instance being cloned does not contain a body
1 parent 6a0307b commit 5debe80

File tree

1 file changed

+71
-64
lines changed

1 file changed

+71
-64
lines changed

runtime/js-compute-runtime/builtins/request-response.cpp

Lines changed: 71 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,88 +1269,95 @@ bool Request::setCacheKey(JSContext *cx, unsigned argc, JS::Value *vp) {
12691269
JSString *GET_atom;
12701270

12711271
bool Request::clone(JSContext *cx, unsigned argc, JS::Value *vp) {
1272-
METHOD_HEADER(0)
1273-
1274-
if (RequestOrResponse::body_used(self)) {
1275-
JS_ReportErrorLatin1(cx, "Request.prototype.clone: the request's body isn't usable.");
1276-
return false;
1277-
}
1278-
1279-
// Here we get the current requests body stream and call ReadableStream.prototype.tee to return
1280-
// two versions of the stream. Once we get the two streams, we create a new request handle and
1281-
// attach one of the streams to the new handle and the other stream is attached to the request
1282-
// handle that `clone()` was called upon.
1283-
JS::RootedObject body_stream(cx, RequestOrResponse::body_stream(self));
1284-
if (!body_stream) {
1285-
body_stream = RequestOrResponse::create_body_stream(cx, self);
1286-
if (!body_stream) {
1287-
return false;
1288-
}
1289-
}
1290-
JS::RootedValue tee_val(cx);
1291-
if (!JS_GetProperty(cx, body_stream, "tee", &tee_val)) {
1292-
return false;
1293-
}
1294-
JS::Rooted<JSFunction *> tee(cx, JS_GetObjectFunction(&tee_val.toObject()));
1295-
if (!tee) {
1296-
return false;
1297-
}
1298-
JS::RootedVector<JS::Value> argv(cx);
1299-
JS::RootedValue rval(cx);
1300-
if (!JS::Call(cx, body_stream, tee, argv, &rval)) {
1301-
return false;
1302-
}
1303-
JS::RootedObject rval_array(cx, &rval.toObject());
1304-
JS::RootedValue body1_val(cx);
1305-
if (!JS_GetProperty(cx, rval_array, "0", &body1_val)) {
1306-
return false;
1307-
}
1308-
JS::RootedValue body2_val(cx);
1309-
if (!JS_GetProperty(cx, rval_array, "1", &body2_val)) {
1310-
return false;
1311-
}
1272+
METHOD_HEADER(0);
13121273

13131274
auto request_handle_res = HttpReq::make();
13141275
if (auto *err = request_handle_res.to_err()) {
13151276
HANDLE_ERROR(cx, *err);
13161277
return false;
13171278
}
13181279

1319-
auto res = HttpBody::make();
1320-
if (auto *err = res.to_err()) {
1321-
HANDLE_ERROR(cx, *err);
1322-
return false;
1323-
}
1324-
13251280
auto request_handle = request_handle_res.unwrap();
1326-
auto body_handle = res.unwrap();
1327-
if (!JS::IsReadableStream(&body1_val.toObject())) {
1328-
return false;
1329-
}
1330-
body_stream.set(&body1_val.toObject());
1331-
if (RequestOrResponse::body_unusable(cx, body_stream)) {
1332-
JS_ReportErrorLatin1(cx, "Can't use a ReadableStream that's locked or has ever been "
1333-
"read from or canceled as a Request body.");
1334-
return false;
1335-
}
13361281

13371282
JS::RootedObject requestInstance(cx, Request::create_instance(cx));
13381283
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::Request),
13391284
JS::Int32Value(request_handle.handle));
1340-
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::Body),
1341-
JS::Int32Value(body_handle.handle));
1342-
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::BodyStream), body1_val);
13431285
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::BodyUsed), JS::FalseValue());
1344-
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::HasBody),
1345-
JS::BooleanValue(true));
13461286
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::URL),
13471287
JS::GetReservedSlot(self, static_cast<uint32_t>(Slots::URL)));
13481288
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::IsDownstream),
13491289
JS::GetReservedSlot(self, static_cast<uint32_t>(Slots::IsDownstream)));
13501290

1351-
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::BodyStream), body2_val);
1352-
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::BodyUsed), JS::FalseValue());
1353-
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::HasBody), JS::BooleanValue(true));
1291+
auto hasBody = RequestOrResponse::has_body(self);
1292+
1293+
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::HasBody),
1294+
JS::BooleanValue(hasBody));
1295+
1296+
if (hasBody) {
1297+
if (RequestOrResponse::body_used(self)) {
1298+
JS_ReportErrorLatin1(cx, "Request.prototype.clone: the request's body isn't usable.");
1299+
return false;
1300+
}
1301+
1302+
// Here we get the current requests body stream and call ReadableStream.prototype.tee to return
1303+
// two versions of the stream. Once we get the two streams, we create a new request handle and
1304+
// attach one of the streams to the new handle and the other stream is attached to the request
1305+
// handle that `clone()` was called upon.
1306+
JS::RootedObject body_stream(cx, RequestOrResponse::body_stream(self));
1307+
if (!body_stream) {
1308+
body_stream = RequestOrResponse::create_body_stream(cx, self);
1309+
if (!body_stream) {
1310+
return false;
1311+
}
1312+
}
1313+
JS::RootedValue tee_val(cx);
1314+
if (!JS_GetProperty(cx, body_stream, "tee", &tee_val)) {
1315+
return false;
1316+
}
1317+
JS::Rooted<JSFunction *> tee(cx, JS_GetObjectFunction(&tee_val.toObject()));
1318+
if (!tee) {
1319+
return false;
1320+
}
1321+
JS::RootedVector<JS::Value> argv(cx);
1322+
JS::RootedValue rval(cx);
1323+
if (!JS::Call(cx, body_stream, tee, argv, &rval)) {
1324+
return false;
1325+
}
1326+
JS::RootedObject rval_array(cx, &rval.toObject());
1327+
JS::RootedValue body1_val(cx);
1328+
if (!JS_GetProperty(cx, rval_array, "0", &body1_val)) {
1329+
return false;
1330+
}
1331+
JS::RootedValue body2_val(cx);
1332+
if (!JS_GetProperty(cx, rval_array, "1", &body2_val)) {
1333+
return false;
1334+
}
1335+
1336+
auto res = HttpBody::make();
1337+
if (auto *err = res.to_err()) {
1338+
HANDLE_ERROR(cx, *err);
1339+
return false;
1340+
}
1341+
1342+
auto body_handle = res.unwrap();
1343+
if (!JS::IsReadableStream(&body1_val.toObject())) {
1344+
return false;
1345+
}
1346+
body_stream.set(&body1_val.toObject());
1347+
if (RequestOrResponse::body_unusable(cx, body_stream)) {
1348+
JS_ReportErrorLatin1(cx, "Can't use a ReadableStream that's locked or has ever been "
1349+
"read from or canceled as a Request body.");
1350+
return false;
1351+
}
1352+
1353+
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::Body),
1354+
JS::Int32Value(body_handle.handle));
1355+
JS::SetReservedSlot(requestInstance, static_cast<uint32_t>(Slots::BodyStream), body1_val);
1356+
1357+
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::BodyStream), body2_val);
1358+
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::BodyUsed), JS::FalseValue());
1359+
JS::SetReservedSlot(self, static_cast<uint32_t>(Slots::HasBody), JS::BooleanValue(true));
1360+
}
13541361

13551362
JS::RootedObject headers(cx);
13561363
JS::RootedObject headers_obj(

0 commit comments

Comments
 (0)