@@ -1044,7 +1044,11 @@ catch (...)
10441044}
10451045
10461046
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 (
10481052 winrt::Microsoft::ReactNative::JSValueObject options,
10491053 std::string taskId,
10501054 std::string method,
@@ -1060,6 +1064,7 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob(
10601064 {
10611065 filter.IgnorableServerCertificateErrors ().Append (Cryptography::Certificates::ChainValidationResult::Untrusted);
10621066 }
1067+ RNFetchBlobState eventState;
10631068
10641069 winrt::Windows::Web::Http::HttpClient httpClient{ filter };
10651070
@@ -1185,12 +1190,39 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob(
11851190 }
11861191 }
11871192 }
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+ }
11881223
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);
11941226 {
11951227 std::scoped_lock lock{ m_mutex };
11961228 uploadProgressMap.extract (taskId);
@@ -1212,14 +1244,7 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlobForm(
12121244
12131245 ReactNativeBlobUtilConfig config{ options };
12141246
1215- if (config.followRedirect == true )
1216- {
1217- filter.AllowAutoRedirect (true );
1218- }
1219- else
1220- {
1221- filter.AllowAutoRedirect (false );
1222- }
1247+ filter.AllowAutoRedirect (false );
12231248
12241249 if (config.trusty )
12251250 {
@@ -1375,25 +1400,38 @@ winrt::fire_and_forget ReactNativeBlobUtil::fetchBlobForm(
13751400 }
13761401 }
13771402 }
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- */
13911403
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 (...) {
13951423
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+ }
13961433
1434+ cancellationTimer.Cancel ();
13971435 m_tasks.Cancel (taskId);
13981436 {
13991437 std::scoped_lock lock{ m_mutex };
@@ -1494,24 +1532,49 @@ winrt::Windows::Foundation::IAsyncAction ReactNativeBlobUtil::ProcessRequestAsyn
14941532 winrt::Windows::Web::Http::HttpRequestMessage& httpRequestMessage,
14951533 ReactNativeBlobUtilConfig& config,
14961534 std::function<void (std::string, std::string, std::string)> callback,
1497- ReactNativeBlobUtilState& eventState ) noexcept
1535+ std::string& error ) noexcept
14981536try
14991537{
15001538 winrt::Windows::Web::Http::HttpClient httpClient{filter};
1501-
1539+
15021540 winrt::Windows::Web::Http::HttpResponseMessage response{ co_await httpClient.SendRequestAsync (httpRequestMessage, winrt::Windows::Web::Http::HttpCompletionOption::ResponseHeadersRead) };
15031541
1542+ RNFetchBlobState eventState;
1543+
15041544 auto status{ static_cast <int >(response.StatusCode ()) };
15051545 if (config.followRedirect ) {
15061546 while (status >= 300 && status < 400 ) {
15071547 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) ));
15091549 httpRequestMessage.RequestUri (Uri{ redirect });
15101550 response = co_await httpClient.SendRequestAsync (httpRequestMessage, winrt::Windows::Web::Http::HttpCompletionOption::ResponseHeadersRead);
15111551 status = static_cast <int >(response.StatusCode ());
15121552 }
15131553 }
15141554
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+
15151578 IReference<uint64_t > contentLength{ response.Content ().Headers ().ContentLength () };
15161579
15171580 IOutputStream outputStream;
@@ -1604,30 +1667,18 @@ try
16041667 }
16051668 }
16061669 }
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 ());
16191670
16201671 if (writeToFile) {
16211672 callback (" " , " path" , config.path );
16221673 }
16231674 else {
16241675 callback (" " , " result" , resultOutput.str ());
16251676 }
1626- // callback("ReactNativeBlobUtil request timed out", "error", "");
16271677}
16281678catch (const hresult_error& ex)
16291679{
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", "");
16311682}
16321683catch (...) {
16331684 co_return ;
0 commit comments