@@ -1044,7 +1044,11 @@ catch (...)
1044
1044
}
1045
1045
1046
1046
1047
- winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob (
1047
+ IAsyncAction setTimeout (std::chrono::seconds time) {
1048
+ co_await time;
1049
+ }
1050
+
1051
+ winrt::fire_and_forget RNFetchBlob::fetchBlob (
1048
1052
winrt::Microsoft::ReactNative::JSValueObject options,
1049
1053
std::string taskId,
1050
1054
std::string method,
@@ -1060,6 +1064,7 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob(
1060
1064
{
1061
1065
filter.IgnorableServerCertificateErrors ().Append (Cryptography::Certificates::ChainValidationResult::Untrusted);
1062
1066
}
1067
+ RNFetchBlobState eventState;
1063
1068
1064
1069
winrt::Windows::Web::Http::HttpClient httpClient{ filter };
1065
1070
@@ -1185,12 +1190,39 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob(
1185
1190
}
1186
1191
}
1187
1192
}
1193
+
1194
+ std::string error;
1195
+ auto cancellationTimer{ setTimeout (config.timeout ) };
1196
+ cancellationTimer.Completed ([weak_this = weak_from_this (), taskId, error](IAsyncAction const & action, AsyncStatus status) {
1197
+ if (status == AsyncStatus::Completed) {
1198
+ auto strong_this{ weak_this.lock () };
1199
+ if (strong_this) {
1200
+ strong_this->m_tasks .Cancel (taskId);
1201
+ {
1202
+ std::scoped_lock lock{ strong_this->m_mutex };
1203
+ strong_this->uploadProgressMap .extract (taskId);
1204
+ strong_this->downloadProgressMap .extract (taskId);
1205
+ }
1206
+ }
1207
+ }
1208
+ });
1209
+ try {
1210
+ co_await m_tasks.Add (taskId, ProcessRequestAsync (taskId, filter, requestMessage, config, callback, error));
1211
+ }
1212
+ catch (...) {
1213
+
1214
+ }
1215
+ if (!error.empty ()) {
1216
+ if (cancellationTimer.Status () != AsyncStatus::Completed) {
1217
+ callback (error, " error" , " " );
1218
+ }
1219
+ else {
1220
+ callback (" RNFetchBlob request timed out" , " error" , " " );
1221
+ }
1222
+ }
1188
1223
1189
- ReactNativeBlobUtilState eventState;
1190
-
1191
- co_await m_tasks.Add (taskId, ProcessRequestAsync (taskId, filter, requestMessage, config, callback, eventState));
1192
-
1193
- m_tasks.Cancel (taskId);
1224
+ cancellationTimer.Cancel ();
1225
+ m_tasks.Cancel (taskId);
1194
1226
{
1195
1227
std::scoped_lock lock{ m_mutex };
1196
1228
uploadProgressMap.extract (taskId);
@@ -1212,14 +1244,7 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlobForm(
1212
1244
1213
1245
ReactNativeBlobUtilConfig config{ options };
1214
1246
1215
- if (config.followRedirect == true )
1216
- {
1217
- filter.AllowAutoRedirect (true );
1218
- }
1219
- else
1220
- {
1221
- filter.AllowAutoRedirect (false );
1222
- }
1247
+ filter.AllowAutoRedirect (false );
1223
1248
1224
1249
if (config.trusty )
1225
1250
{
@@ -1375,25 +1400,38 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlobForm(
1375
1400
}
1376
1401
}
1377
1402
}
1378
-
1379
- // TODO, set a timeout for cancellation
1380
-
1381
- // Create EVENT_STATE_CHANGE
1382
- /*
1383
- taskId, // DO NOT STORE
1384
- @"state": @"2", // store
1385
- @"headers": headers, // store
1386
- @"redirects": redirects, //check how to track
1387
- @"respType" : respType, // store
1388
- @"timeout" : @NO, // do not store
1389
- @"status": [NSNumber numberWithInteger:statusCode] // store
1390
- */
1391
1403
1392
- ReactNativeBlobUtilState eventState;
1393
-
1394
- co_await m_tasks.Add (taskId, ProcessRequestAsync (taskId, filter, requestMessage, config, callback, eventState));
1404
+ std::string error;
1405
+ auto cancellationTimer{ setTimeout (config.timeout ) };
1406
+ cancellationTimer.Completed ([weak_this = weak_from_this (), taskId, error](IAsyncAction const & action, AsyncStatus status) {
1407
+ if (status == AsyncStatus::Completed) {
1408
+ auto strong_this{ weak_this.lock () };
1409
+ if (strong_this) {
1410
+ strong_this->m_tasks .Cancel (taskId);
1411
+ {
1412
+ std::scoped_lock lock{ strong_this->m_mutex };
1413
+ strong_this->uploadProgressMap .extract (taskId);
1414
+ strong_this->downloadProgressMap .extract (taskId);
1415
+ }
1416
+ }
1417
+ }
1418
+ });
1419
+ try {
1420
+ co_await m_tasks.Add (taskId, ProcessRequestAsync (taskId, filter, requestMessage, config, callback, error));
1421
+ }
1422
+ catch (...) {
1395
1423
1424
+ }
1425
+ if (!error.empty ()) {
1426
+ if (cancellationTimer.Status () != AsyncStatus::Completed) {
1427
+ callback (error, " error" , " " );
1428
+ }
1429
+ else {
1430
+ callback (" ReactNativeBlobUtil request timed out" , " error" , " " );
1431
+ }
1432
+ }
1396
1433
1434
+ cancellationTimer.Cancel ();
1397
1435
m_tasks.Cancel (taskId);
1398
1436
{
1399
1437
std::scoped_lock lock{ m_mutex };
@@ -1494,24 +1532,49 @@ winrt::Windows::Foundation::IAsyncAction ReactNativeBlobUtil::ProcessRequestAsyn
1494
1532
winrt::Windows::Web::Http::HttpRequestMessage& httpRequestMessage,
1495
1533
ReactNativeBlobUtilConfig& config,
1496
1534
std::function<void (std::string, std::string, std::string)> callback,
1497
- ReactNativeBlobUtilState& eventState ) noexcept
1535
+ std::string& error ) noexcept
1498
1536
try
1499
1537
{
1500
1538
winrt::Windows::Web::Http::HttpClient httpClient{filter};
1501
-
1539
+
1502
1540
winrt::Windows::Web::Http::HttpResponseMessage response{ co_await httpClient.SendRequestAsync (httpRequestMessage, winrt::Windows::Web::Http::HttpCompletionOption::ResponseHeadersRead) };
1503
1541
1542
+ RNFetchBlobState eventState;
1543
+
1504
1544
auto status{ static_cast <int >(response.StatusCode ()) };
1505
1545
if (config.followRedirect ) {
1506
1546
while (status >= 300 && status < 400 ) {
1507
1547
auto redirect{ response.Headers ().Location ().ToString () };
1508
- eventState.redirects .push_back (winrt::to_string (redirect));
1548
+ eventState.redirects .push_back (Microsoft::ReactNative::JSValue ( winrt::to_string (redirect) ));
1509
1549
httpRequestMessage.RequestUri (Uri{ redirect });
1510
1550
response = co_await httpClient.SendRequestAsync (httpRequestMessage, winrt::Windows::Web::Http::HttpCompletionOption::ResponseHeadersRead);
1511
1551
status = static_cast <int >(response.StatusCode ());
1512
1552
}
1513
1553
}
1514
1554
1555
+ eventState.status = static_cast <int >(response.StatusCode ());
1556
+
1557
+ for (const auto header : response.Content ().Headers ().GetView ()) {
1558
+ eventState.headers [winrt::to_string (header.Key ())] = winrt::to_string (header.Value ());
1559
+ }
1560
+
1561
+ if (response.Content ().Headers ().ContentType () != nullptr ) {
1562
+ eventState.respType = winrt::to_string (response.Content ().Headers ().ContentType ().ToString ());
1563
+ }
1564
+
1565
+ eventState.state = winrt::to_string (response.ReasonPhrase ());
1566
+
1567
+ m_reactContext.CallJSFunction (L" RCTDeviceEventEmitter" , L" emit" , L" RNFetchBlobState" ,
1568
+ Microsoft::ReactNative::JSValueObject{
1569
+ { " taskId" , taskId },
1570
+ { " state" , eventState.state },
1571
+ { " headers" , std::move (eventState.headers ) },
1572
+ { " redirects" , std::move (eventState.redirects ) },
1573
+ { " respType" , eventState.respType },
1574
+ { " status" , eventState.status },
1575
+ { " timeout" , false },
1576
+ });
1577
+
1515
1578
IReference<uint64_t > contentLength{ response.Content ().Headers ().ContentLength () };
1516
1579
1517
1580
IOutputStream outputStream;
@@ -1604,30 +1667,18 @@ try
1604
1667
}
1605
1668
}
1606
1669
}
1607
-
1608
- eventState.status = static_cast <int >(response.StatusCode ());
1609
-
1610
- for (const auto header : response.Content ().Headers ().GetView ()) {
1611
- eventState.headers [winrt::to_string (header.Key ())] = winrt::to_string (header.Value ());
1612
- }
1613
-
1614
- if (response.Content ().Headers ().ContentType () != nullptr ) {
1615
- eventState.respType = winrt::to_string (response.Content ().Headers ().ContentType ().ToString ());
1616
- }
1617
-
1618
- eventState.state = winrt::to_string (response.ReasonPhrase ());
1619
1670
1620
1671
if (writeToFile) {
1621
1672
callback (" " , " path" , config.path );
1622
1673
}
1623
1674
else {
1624
1675
callback (" " , " result" , resultOutput.str ());
1625
1676
}
1626
- // callback("ReactNativeBlobUtil request timed out", "error", "");
1627
1677
}
1628
1678
catch (const hresult_error& ex)
1629
1679
{
1630
- callback (winrt::to_string (ex.message ().c_str ()), " error" , " " );
1680
+ error = winrt::to_string (ex.message ().c_str ());
1681
+ // callback(winrt::to_string(ex.message().c_str()), "error", "");
1631
1682
}
1632
1683
catch (...) {
1633
1684
co_return ;
0 commit comments