react-native-windows 0.70.6 → 0.70.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,21 +20,6 @@
20
20
 
21
21
  namespace Microsoft::ReactNative {
22
22
 
23
- using winrt::Microsoft::ReactNative::ReactPropertyBag;
24
-
25
- namespace {
26
-
27
- using winrt::Microsoft::ReactNative::ReactPropertyId;
28
-
29
- ReactPropertyId<bool> HttpUseMonolithicModuleProperty() noexcept {
30
- static ReactPropertyId<bool> propId{
31
- L"ReactNative.Http"
32
- L"UseMonolithicModule"};
33
- return propId;
34
- }
35
-
36
- } // namespace
37
-
38
23
  std::vector<facebook::react::NativeModuleDescription> GetCoreModules(
39
24
  const std::shared_ptr<facebook::react::MessageQueueThread> &batchingUIMessageQueue,
40
25
  const std::shared_ptr<facebook::react::MessageQueueThread>
@@ -48,17 +33,15 @@ std::vector<facebook::react::NativeModuleDescription> GetCoreModules(
48
33
  [props = context->Properties()]() { return Microsoft::React::CreateHttpModule(props); },
49
34
  jsMessageQueue);
50
35
 
51
- if (!ReactPropertyBag(context->Properties()).Get(HttpUseMonolithicModuleProperty())) {
52
- modules.emplace_back(
53
- Microsoft::React::GetBlobModuleName(),
54
- [props = context->Properties()]() { return Microsoft::React::CreateBlobModule(props); },
55
- batchingUIMessageQueue);
36
+ modules.emplace_back(
37
+ Microsoft::React::GetBlobModuleName(),
38
+ [props = context->Properties()]() { return Microsoft::React::CreateBlobModule(props); },
39
+ batchingUIMessageQueue);
56
40
 
57
- modules.emplace_back(
58
- Microsoft::React::GetFileReaderModuleName(),
59
- [props = context->Properties()]() { return Microsoft::React::CreateFileReaderModule(props); },
60
- batchingUIMessageQueue);
61
- }
41
+ modules.emplace_back(
42
+ Microsoft::React::GetFileReaderModuleName(),
43
+ [props = context->Properties()]() { return Microsoft::React::CreateFileReaderModule(props); },
44
+ batchingUIMessageQueue);
62
45
 
63
46
  modules.emplace_back(
64
47
  "Timing",
@@ -10,10 +10,10 @@
10
10
  -->
11
11
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
12
12
  <PropertyGroup>
13
- <ReactNativeWindowsVersion>0.70.6</ReactNativeWindowsVersion>
13
+ <ReactNativeWindowsVersion>0.70.8</ReactNativeWindowsVersion>
14
14
  <ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
15
15
  <ReactNativeWindowsMinor>70</ReactNativeWindowsMinor>
16
- <ReactNativeWindowsPatch>6</ReactNativeWindowsPatch>
16
+ <ReactNativeWindowsPatch>8</ReactNativeWindowsPatch>
17
17
  <ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
18
18
  </PropertyGroup>
19
19
  </Project>
@@ -33,8 +33,10 @@ constexpr char moduleName[] = "Networking";
33
33
  // React event names
34
34
  constexpr char completedResponse[] = "didCompleteNetworkResponse";
35
35
  constexpr char receivedResponse[] = "didReceiveNetworkResponse";
36
- constexpr char receivedData[] = "didReceiveNetworkData";
36
+ constexpr char sentData[] = "didSendNetworkData";
37
+ constexpr char receivedIncrementalData[] = "didReceiveNetworkIncrementalData";
37
38
  constexpr char receivedDataProgress[] = "didReceiveNetworkDataProgress";
39
+ constexpr char receivedData[] = "didReceiveNetworkData";
38
40
 
39
41
  static void SetUpHttpResource(
40
42
  shared_ptr<IHttpResource> resource,
@@ -60,9 +62,6 @@ static void SetUpHttpResource(
60
62
 
61
63
  resource->SetOnData([weakReactInstance](int64_t requestId, string &&responseData) {
62
64
  SendEvent(weakReactInstance, receivedData, dynamic::array(requestId, std::move(responseData)));
63
-
64
- // TODO: Move into separate method IF not executed right after onData()
65
- SendEvent(weakReactInstance, completedResponse, dynamic::array(requestId));
66
65
  });
67
66
 
68
67
  // Explicitly declaring function type to avoid type inference ambiguity.
@@ -72,6 +71,22 @@ static void SetUpHttpResource(
72
71
  };
73
72
  resource->SetOnData(std::move(onDataDynamic));
74
73
 
74
+ resource->SetOnIncrementalData(
75
+ [weakReactInstance](int64_t requestId, string &&responseData, int64_t progress, int64_t total) {
76
+ SendEvent(
77
+ weakReactInstance,
78
+ receivedIncrementalData,
79
+ dynamic::array(requestId, std::move(responseData), progress, total));
80
+ });
81
+
82
+ resource->SetOnDataProgress([weakReactInstance](int64_t requestId, int64_t progress, int64_t total) {
83
+ SendEvent(weakReactInstance, receivedDataProgress, dynamic::array(requestId, progress, total));
84
+ });
85
+
86
+ resource->SetOnResponseComplete([weakReactInstance](int64_t requestId) {
87
+ SendEvent(weakReactInstance, completedResponse, dynamic::array(requestId));
88
+ });
89
+
75
90
  resource->SetOnError([weakReactInstance](int64_t requestId, string &&message, bool isTimeout) {
76
91
  dynamic args = dynamic::array(requestId, std::move(message));
77
92
  if (isTimeout) {
@@ -91,10 +91,136 @@ struct IHttpResource {
91
91
 
92
92
  virtual void ClearCookies() noexcept = 0;
93
93
 
94
+ /// <summary>
95
+ /// Sets a function to be invoked when a request has been successfully responded.
96
+ /// </summary>
97
+ /// <param name="handler">
98
+ ///
99
+ /// Parameters:
100
+ /// <param name="requestId">
101
+ /// Unique number identifying the HTTP request
102
+ /// </param>
103
+ /// </param>
94
104
  virtual void SetOnRequestSuccess(std::function<void(int64_t requestId)> &&handler) noexcept = 0;
105
+
106
+ /// <summary>
107
+ /// Sets a function to be invoked when a response arrives and its headers are received.
108
+ /// </summary>
109
+ /// <param name="handler">
110
+ ///
111
+ /// Parameters:
112
+ /// <param name="requestId">
113
+ /// Unique number identifying the HTTP request
114
+ /// </param>
115
+ /// <param name="response">
116
+ /// Object containing basic response data
117
+ /// </param>
118
+ /// </param>
95
119
  virtual void SetOnResponse(std::function<void(int64_t requestId, Response &&response)> &&handler) noexcept = 0;
120
+
121
+ /// <summary>
122
+ /// Sets a function to be invoked when response content data has been received.
123
+ /// </summary>
124
+ /// <param name="handler">
125
+ ///
126
+ /// Parameters:
127
+ /// <param name="requestId">
128
+ /// Unique number identifying the HTTP request
129
+ /// </param>
130
+ /// <param name="responseData">
131
+ /// Response content payload (plain text or Base64-encoded)
132
+ /// </param>
133
+ /// </param>
96
134
  virtual void SetOnData(std::function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept = 0;
135
+
136
+ /// <summary>
137
+ /// Sets a function to be invoked when response content data has been received.
138
+ /// </summary>
139
+ /// <param name="handler">
140
+ ///
141
+ /// Parameters:
142
+ /// <param name="requestId">
143
+ /// Unique number identifying the HTTP request
144
+ /// </param>
145
+ /// <param name="responseData">
146
+ /// Structured response content payload (i.e. Blob data)
147
+ /// </param>
148
+ /// </param>
97
149
  virtual void SetOnData(std::function<void(int64_t requestId, folly::dynamic &&responseData)> &&handler) noexcept = 0;
150
+
151
+ /// <summary>
152
+ /// Sets a function to be invoked when a response content increment has been received.
153
+ /// </summary>
154
+ /// <remarks>
155
+ /// The handler set by this method will only be called if the request sets the incremental updates flag.
156
+ /// The handler is also mutually exclusive with those set by `SetOnData`, which are used for one pass, non-incremental
157
+ /// updates.
158
+ /// </remarks>
159
+ /// <param name="handler">
160
+ ///
161
+ /// Parameters:
162
+ /// <param name="requestId">
163
+ /// Unique number identifying the HTTP request
164
+ /// </param>
165
+ /// <param name="responseData">
166
+ /// Partial response content data increment (non-accumulative)
167
+ /// </param>
168
+ /// <param name="progress">
169
+ /// Number of bytes received so far
170
+ /// </param>
171
+ /// <param name="total">
172
+ /// Number of total bytes to receive
173
+ /// </param>
174
+ /// </param>
175
+ virtual void SetOnIncrementalData(
176
+ std::function<void(int64_t requestId, std::string &&responseData, int64_t progress, int64_t total)>
177
+ &&handler) noexcept = 0;
178
+
179
+ /// <summary>
180
+ /// Sets a function to be invoked when response content download progress is reported.
181
+ /// </summary>
182
+ /// <param name="handler">
183
+ ///
184
+ /// Parameters:
185
+ /// <param name="requestId">
186
+ /// Unique number identifying the HTTP request
187
+ /// </param>
188
+ /// <param name="progress">
189
+ /// Number of bytes received so far
190
+ /// </param>
191
+ /// <param name="total">
192
+ /// Number of total bytes to receive
193
+ /// </param>
194
+ /// </param>
195
+ virtual void SetOnDataProgress(
196
+ std::function<void(int64_t requestId, int64_t progress, int64_t total)> &&handler) noexcept = 0;
197
+
198
+ /// <summary>
199
+ /// Sets a function to be invoked when a response has been fully handled (either succeeded or failed).
200
+ /// </summary>
201
+ /// <param name="handler">
202
+ ///
203
+ /// Parameters:
204
+ /// <param name="requestId">
205
+ /// Unique number identifying the HTTP request
206
+ /// </param>
207
+ /// </param>
208
+ virtual void SetOnResponseComplete(std::function<void(int64_t requestId)> &&handler) noexcept = 0;
209
+
210
+ /// <summary>
211
+ /// Sets a function to be invoked when an error condition is found.
212
+ /// </summary>
213
+ /// <remarks>
214
+ /// The handler's purpose is not to report any given HTTP error status (i.e. 403, 501).
215
+ /// It is meant to report application errors when executing HTTP requests.
216
+ /// </remarks>
217
+ /// <param name="handler">
218
+ ///
219
+ /// Parameters:
220
+ /// <param name="requestId">
221
+ /// Unique number identifying the HTTP request
222
+ /// </param>
223
+ /// </param>
98
224
  virtual void SetOnError(
99
225
  std::function<void(int64_t requestId, std::string &&errorMessage, bool isTimeout)> &&handler) noexcept = 0;
100
226
  };
@@ -51,8 +51,51 @@ using winrt::Windows::Web::Http::IHttpClient;
51
51
  using winrt::Windows::Web::Http::IHttpContent;
52
52
  using winrt::Windows::Web::Http::Headers::HttpMediaTypeHeaderValue;
53
53
 
54
+ namespace {
55
+
56
+ constexpr uint32_t operator""_KiB(unsigned long long int x) {
57
+ return static_cast<uint32_t>(1024 * x);
58
+ }
59
+
60
+ constexpr uint32_t operator""_MiB(unsigned long long int x) {
61
+ return static_cast<uint32_t>(1024_KiB * x);
62
+ }
63
+
64
+ constexpr char responseTypeText[] = "text";
65
+ constexpr char responseTypeBase64[] = "base64";
66
+ constexpr char responseTypeBlob[] = "blob";
67
+
68
+ } // namespace
54
69
  namespace Microsoft::React::Networking {
55
70
 
71
+ // May throw winrt::hresult_error
72
+ void AttachMultipartHeaders(IHttpContent content, const dynamic &headers) {
73
+ HttpMediaTypeHeaderValue contentType{nullptr};
74
+
75
+ // Headers are generally case-insensitive
76
+ // https://www.ietf.org/rfc/rfc2616.txt section 4.2
77
+ // TODO: Consolidate with PerformRequest's header parsing.
78
+ for (auto &header : headers.items()) {
79
+ auto &name = header.first.getString();
80
+ auto &value = header.second.getString();
81
+
82
+ if (boost::iequals(name.c_str(), "Content-Type")) {
83
+ contentType = HttpMediaTypeHeaderValue::Parse(to_hstring(value));
84
+ } else if (boost::iequals(name.c_str(), "Authorization")) {
85
+ bool success = content.Headers().TryAppendWithoutValidation(to_hstring(name), to_hstring(value));
86
+ if (!success) {
87
+ throw hresult_error{E_INVALIDARG, L"Failed to append Authorization"};
88
+ }
89
+ } else {
90
+ content.Headers().Append(to_hstring(name), to_hstring(value));
91
+ }
92
+ }
93
+
94
+ if (contentType) {
95
+ content.Headers().ContentType(contentType);
96
+ }
97
+ }
98
+
56
99
  #pragma region WinRTHttpResource
57
100
 
58
101
  WinRTHttpResource::WinRTHttpResource(IHttpClient &&client) noexcept : m_client{std::move(client)} {}
@@ -81,20 +124,23 @@ IAsyncOperation<HttpRequestMessage> WinRTHttpResource::CreateRequest(
81
124
  // Headers are generally case-insensitive
82
125
  // https://www.ietf.org/rfc/rfc2616.txt section 4.2
83
126
  for (auto &header : reqArgs->Headers) {
84
- if (boost::iequals(header.first.c_str(), "Content-Type")) {
85
- bool success = HttpMediaTypeHeaderValue::TryParse(to_hstring(header.second), contentType);
127
+ auto &name = header.first;
128
+ auto &value = header.second;
129
+
130
+ if (boost::iequals(name.c_str(), "Content-Type")) {
131
+ bool success = HttpMediaTypeHeaderValue::TryParse(to_hstring(value), contentType);
86
132
  if (!success) {
87
133
  if (self->m_onError) {
88
134
  self->m_onError(reqArgs->RequestId, "Failed to parse Content-Type", false);
89
135
  }
90
136
  co_return nullptr;
91
137
  }
92
- } else if (boost::iequals(header.first.c_str(), "Content-Encoding")) {
93
- contentEncoding = header.second;
94
- } else if (boost::iequals(header.first.c_str(), "Content-Length")) {
95
- contentLength = header.second;
96
- } else if (boost::iequals(header.first.c_str(), "Authorization")) {
97
- bool success = request.Headers().TryAppendWithoutValidation(to_hstring(header.first), to_hstring(header.second));
138
+ } else if (boost::iequals(name.c_str(), "Content-Encoding")) {
139
+ contentEncoding = value;
140
+ } else if (boost::iequals(name.c_str(), "Content-Length")) {
141
+ contentLength = value;
142
+ } else if (boost::iequals(name.c_str(), "Authorization")) {
143
+ bool success = request.Headers().TryAppendWithoutValidation(to_hstring(name), to_hstring(value));
98
144
  if (!success) {
99
145
  if (self->m_onError) {
100
146
  self->m_onError(reqArgs->RequestId, "Failed to append Authorization", false);
@@ -103,7 +149,7 @@ IAsyncOperation<HttpRequestMessage> WinRTHttpResource::CreateRequest(
103
149
  }
104
150
  } else {
105
151
  try {
106
- request.Headers().Append(to_hstring(header.first), to_hstring(header.second));
152
+ request.Headers().Append(to_hstring(name), to_hstring(value));
107
153
  } catch (hresult_error const &e) {
108
154
  if (self->m_onError) {
109
155
  self->m_onError(reqArgs->RequestId, Utilities::HResultToString(e), false);
@@ -146,9 +192,31 @@ IAsyncOperation<HttpRequestMessage> WinRTHttpResource::CreateRequest(
146
192
  auto file = co_await StorageFile::GetFileFromApplicationUriAsync(Uri{to_hstring(data["uri"].asString())});
147
193
  auto stream = co_await file.OpenReadAsync();
148
194
  content = HttpStreamContent{std::move(stream)};
149
- } else if (!data["form"].empty()) {
150
- // #9535 - HTTP form data support
151
- // winrt::Windows::Web::Http::HttpMultipartFormDataContent()
195
+ } else if (!data["formData"].empty()) {
196
+ winrt::Windows::Web::Http::HttpMultipartFormDataContent multiPartContent;
197
+ auto formData = data["formData"];
198
+
199
+ // #6046 - Overwriting WinRT's HttpMultipartFormDataContent implicit Content-Type clears the generated boundary
200
+ contentType = nullptr;
201
+
202
+ for (auto &formDataPart : formData) {
203
+ IHttpContent formContent{nullptr};
204
+ if (!formDataPart["string"].isNull()) {
205
+ formContent = HttpStringContent{to_hstring(formDataPart["string"].asString())};
206
+ } else if (!formDataPart["uri"].empty()) {
207
+ auto filePath = to_hstring(formDataPart["uri"].asString());
208
+ auto file = co_await StorageFile::GetFileFromPathAsync(filePath);
209
+ auto stream = co_await file.OpenReadAsync();
210
+ formContent = HttpStreamContent{stream};
211
+ }
212
+
213
+ if (formContent) {
214
+ AttachMultipartHeaders(formContent, formDataPart["headers"]);
215
+ multiPartContent.Add(formContent, to_hstring(formDataPart["fieldName"].asString()));
216
+ }
217
+ } // foreach form data part
218
+
219
+ content = multiPartContent;
152
220
  }
153
221
  }
154
222
 
@@ -205,7 +273,7 @@ void WinRTHttpResource::SendRequest(
205
273
  bool withCredentials,
206
274
  std::function<void(int64_t)> &&callback) noexcept /*override*/ {
207
275
  // Enforce supported args
208
- assert(responseType == "text" || responseType == "base64" || responseType == "blob");
276
+ assert(responseType == responseTypeText || responseType == responseTypeBase64 || responseType == responseTypeBlob);
209
277
 
210
278
  if (callback) {
211
279
  callback(requestId);
@@ -283,6 +351,22 @@ void WinRTHttpResource::SetOnData(function<void(int64_t requestId, dynamic &&res
283
351
  m_onDataDynamic = std::move(handler);
284
352
  }
285
353
 
354
+ void WinRTHttpResource::SetOnIncrementalData(
355
+ function<void(int64_t requestId, string &&responseData, int64_t progress, int64_t total)> &&handler) noexcept
356
+ /*override*/ {
357
+ m_onIncrementalData = std::move(handler);
358
+ }
359
+
360
+ void WinRTHttpResource::SetOnDataProgress(
361
+ function<void(int64_t requestId, int64_t progress, int64_t total)> &&handler) noexcept
362
+ /*override*/ {
363
+ m_onDataProgress = std::move(handler);
364
+ }
365
+
366
+ void WinRTHttpResource::SetOnResponseComplete(function<void(int64_t requestId)> &&handler) noexcept /*override*/ {
367
+ m_onComplete = std::move(handler);
368
+ }
369
+
286
370
  void WinRTHttpResource::SetOnError(
287
371
  function<void(int64_t requestId, string &&errorMessage, bool isTimeout)> &&handler) noexcept
288
372
  /*override*/ {
@@ -316,11 +400,18 @@ WinRTHttpResource::PerformSendRequest(HttpMethod &&method, Uri &&rtUri, IInspect
316
400
  auto props = winrt::multi_threaded_map<winrt::hstring, IInspectable>();
317
401
  props.Insert(L"RequestArgs", coArgs);
318
402
 
319
- auto coRequest = co_await CreateRequest(std::move(coMethod), std::move(coUri), props);
320
- if (!coRequest) {
321
- co_return;
403
+ auto coRequestOp = CreateRequest(std::move(coMethod), std::move(coUri), props);
404
+ co_await lessthrow_await_adapter<IAsyncOperation<HttpRequestMessage>>{coRequestOp};
405
+ auto coRequestOpHR = coRequestOp.ErrorCode();
406
+ if (coRequestOpHR < 0) {
407
+ if (self->m_onError) {
408
+ self->m_onError(reqArgs->RequestId, Utilities::HResultToString(std::move(coRequestOpHR)), false);
409
+ }
410
+ co_return self->UntrackResponse(reqArgs->RequestId);
322
411
  }
323
412
 
413
+ auto coRequest = coRequestOp.GetResults();
414
+
324
415
  // If URI handler is available, it takes over request processing.
325
416
  if (auto uriHandler = self->m_uriHandler.lock()) {
326
417
  auto uri = winrt::to_string(coRequest.RequestUri().ToString());
@@ -332,6 +423,10 @@ WinRTHttpResource::PerformSendRequest(HttpMethod &&method, Uri &&rtUri, IInspect
332
423
  self->m_onRequestSuccess(reqArgs->RequestId);
333
424
  }
334
425
 
426
+ if (self->m_onComplete) {
427
+ self->m_onComplete(reqArgs->RequestId);
428
+ }
429
+
335
430
  co_return;
336
431
  }
337
432
  } catch (const hresult_error &e) {
@@ -345,6 +440,9 @@ WinRTHttpResource::PerformSendRequest(HttpMethod &&method, Uri &&rtUri, IInspect
345
440
 
346
441
  try {
347
442
  auto sendRequestOp = self->m_client.SendRequestAsync(coRequest);
443
+
444
+ auto isText = reqArgs->ResponseType == responseTypeText;
445
+
348
446
  self->TrackResponse(reqArgs->RequestId, sendRequestOp);
349
447
 
350
448
  if (reqArgs->Timeout > 0) {
@@ -411,55 +509,86 @@ WinRTHttpResource::PerformSendRequest(HttpMethod &&method, Uri &&rtUri, IInspect
411
509
  auto inputStream = co_await response.Content().ReadAsInputStreamAsync();
412
510
  auto reader = DataReader{inputStream};
413
511
 
414
- // #9510 - 10mb limit on fetch
415
- co_await reader.LoadAsync(10 * 1024 * 1024);
512
+ // Accumulate all incoming request data in 8MB chunks
513
+ // Note, the minimum apparent valid chunk size is 128 KB
514
+ // Apple's implementation appears to grab 5-8 KB chunks
515
+ const uint32_t segmentSize = reqArgs->IncrementalUpdates ? 128_KiB : 8_MiB;
416
516
 
417
517
  // Let response handler take over, if set
418
518
  if (auto responseHandler = self->m_responseHandler.lock()) {
419
519
  if (responseHandler->Supports(reqArgs->ResponseType)) {
420
- auto bytes = vector<uint8_t>(reader.UnconsumedBufferLength());
421
- reader.ReadBytes(bytes);
422
- auto blob = responseHandler->ToResponseData(std::move(bytes));
520
+ vector<uint8_t> responseData{};
521
+ while (auto loaded = co_await reader.LoadAsync(segmentSize)) {
522
+ auto length = reader.UnconsumedBufferLength();
523
+ auto data = vector<uint8_t>(length);
524
+ reader.ReadBytes(data);
525
+
526
+ responseData.insert(responseData.cend(), data.cbegin(), data.cend());
527
+ }
528
+
529
+ auto blob = responseHandler->ToResponseData(std::move(responseData));
423
530
 
424
531
  if (self->m_onDataDynamic && self->m_onRequestSuccess) {
425
532
  self->m_onDataDynamic(reqArgs->RequestId, std::move(blob));
426
533
  self->m_onRequestSuccess(reqArgs->RequestId);
427
534
  }
428
535
 
536
+ if (self->m_onComplete) {
537
+ self->m_onComplete(reqArgs->RequestId);
538
+ }
429
539
  co_return;
430
540
  }
431
541
  }
432
542
 
433
- auto isText = reqArgs->ResponseType == "text";
434
543
  if (isText) {
435
544
  reader.UnicodeEncoding(UnicodeEncoding::Utf8);
436
545
  }
437
546
 
438
- // #9510 - We currently accumulate all incoming request data in 10MB chunks.
439
- uint32_t segmentSize = 10 * 1024 * 1024;
547
+ int64_t receivedBytes = 0;
440
548
  string responseData;
441
549
  winrt::Windows::Storage::Streams::IBuffer buffer;
442
- uint32_t length;
443
- do {
444
- co_await reader.LoadAsync(segmentSize);
445
- length = reader.UnconsumedBufferLength();
550
+ while (auto loaded = co_await reader.LoadAsync(segmentSize)) {
551
+ auto length = reader.UnconsumedBufferLength();
552
+ receivedBytes += length;
446
553
 
447
554
  if (isText) {
448
- auto data = std::vector<uint8_t>(length);
555
+ auto data = vector<uint8_t>(length);
449
556
  reader.ReadBytes(data);
450
557
 
451
- responseData += string(Common::Utilities::CheckedReinterpretCast<char *>(data.data()), data.size());
558
+ auto incrementData = string(Common::Utilities::CheckedReinterpretCast<char *>(data.data()), data.size());
559
+ // #9534 - Send incremental updates.
560
+ // See https://github.com/facebook/react-native/blob/v0.70.6/Libraries/Network/RCTNetworking.mm#L561
561
+ if (reqArgs->IncrementalUpdates) {
562
+ responseData = std::move(incrementData);
563
+
564
+ if (self->m_onIncrementalData) {
565
+ // For total, see #10849
566
+ self->m_onIncrementalData(reqArgs->RequestId, std::move(responseData), receivedBytes, 0 /*total*/);
567
+ }
568
+ } else {
569
+ responseData += std::move(incrementData);
570
+ }
452
571
  } else {
453
572
  buffer = reader.ReadBuffer(length);
454
573
  auto data = CryptographicBuffer::EncodeToBase64String(buffer);
455
574
 
456
575
  responseData += winrt::to_string(std::wstring_view(data));
576
+
577
+ if (self->m_onDataProgress) {
578
+ // For total, see #10849
579
+ self->m_onDataProgress(reqArgs->RequestId, receivedBytes, 0 /*total*/);
580
+ }
457
581
  }
458
- } while (length > 0);
582
+ }
459
583
 
460
- if (self->m_onData) {
584
+ // If dealing with text-incremental response data, use m_onIncrementalData instead
585
+ if (self->m_onData && !(reqArgs->IncrementalUpdates && isText)) {
461
586
  self->m_onData(reqArgs->RequestId, std::move(responseData));
462
587
  }
588
+
589
+ if (self->m_onComplete) {
590
+ self->m_onComplete(reqArgs->RequestId);
591
+ }
463
592
  } else {
464
593
  if (self->m_onError) {
465
594
  self->m_onError(reqArgs->RequestId, response == nullptr ? "request failed" : "No response content", false);
@@ -30,6 +30,10 @@ class WinRTHttpResource : public IHttpResource,
30
30
  std::function<void(int64_t requestId, std::string &&responseData)> m_onData;
31
31
  std::function<void(int64_t requestId, folly::dynamic &&responseData)> m_onDataDynamic;
32
32
  std::function<void(int64_t requestId, std::string &&errorMessage, bool isTimeout)> m_onError;
33
+ std::function<void(int64_t requestId, std::string &&responseData, int64_t progress, int64_t total)>
34
+ m_onIncrementalData;
35
+ std::function<void(int64_t requestId, int64_t progress, int64_t total)> m_onDataProgress;
36
+ std::function<void(int64_t requestId)> m_onComplete;
33
37
 
34
38
  // Used for IHttpModuleProxy
35
39
  std::weak_ptr<IUriHandler> m_uriHandler;
@@ -80,6 +84,12 @@ class WinRTHttpResource : public IHttpResource,
80
84
  void SetOnResponse(std::function<void(int64_t requestId, Response &&response)> &&handler) noexcept override;
81
85
  void SetOnData(std::function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept override;
82
86
  void SetOnData(std::function<void(int64_t requestId, folly::dynamic &&responseData)> &&handler) noexcept override;
87
+ void SetOnIncrementalData(
88
+ std::function<void(int64_t requestId, std::string &&responseData, int64_t progress, int64_t total)>
89
+ &&handler) noexcept override;
90
+ void SetOnDataProgress(
91
+ std::function<void(int64_t requestId, int64_t progress, int64_t total)> &&handler) noexcept override;
92
+ void SetOnResponseComplete(std::function<void(int64_t requestId)> &&handler) noexcept override;
83
93
  void SetOnError(
84
94
  std::function<void(int64_t requestId, std::string &&errorMessage, bool isTimeout)> &&handler) noexcept override;
85
95
 
@@ -27,7 +27,6 @@
27
27
 
28
28
  #include <Modules/ExceptionsManagerModule.h>
29
29
  #include <Modules/HttpModule.h>
30
- #include <Modules/NetworkingModule.h>
31
30
  #include <Modules/PlatformConstantsModule.h>
32
31
  #include <Modules/SourceCodeModule.h>
33
32
  #include <Modules/StatusBarManagerModule.h>
@@ -73,11 +72,7 @@ namespace Microsoft::React {
73
72
 
74
73
  /*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateHttpModule(
75
74
  winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept {
76
- if (GetRuntimeOptionBool("Http.UseMonolithicModule")) {
77
- return std::make_unique<NetworkingModule>();
78
- } else {
79
- return std::make_unique<HttpModule>(inspectableProperties);
80
- }
75
+ return std::make_unique<HttpModule>(inspectableProperties);
81
76
  }
82
77
 
83
78
  } // namespace Microsoft::React
@@ -641,8 +636,7 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
641
636
  // If this code is enabled, we will have unused module instances.
642
637
  // Also, MSRN has a different property bag mechanism incompatible with this method's transitionalProps variable.
643
638
  #if (defined(_MSC_VER) && !defined(WINRT))
644
- if (Microsoft::React::GetRuntimeOptionBool("Blob.EnableModule") &&
645
- !Microsoft::React::GetRuntimeOptionBool("Http.UseMonolithicModule")) {
639
+ if (Microsoft::React::GetRuntimeOptionBool("Blob.EnableModule")) {
646
640
  modules.push_back(std::make_unique<CxxNativeModule>(
647
641
  m_innerInstance,
648
642
  Microsoft::React::GetBlobModuleName(),
@@ -50,7 +50,9 @@
50
50
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\FileReaderModule.cpp" />
51
51
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\HttpModule.cpp" />
52
52
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\I18nModule.cpp" />
53
- <ClCompile Include="$(MSBuildThisFileDirectory)Modules\NetworkingModule.cpp" />
53
+ <ClCompile Include="$(MSBuildThisFileDirectory)Modules\NetworkingModule.cpp">
54
+ <ExcludedFromBuild>true</ExcludedFromBuild>
55
+ </ClCompile>
54
56
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\PlatformConstantsModule.cpp" />
55
57
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\SourceCodeModule.cpp" />
56
58
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\StatusBarManagerModule.cpp" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-windows",
3
- "version": "0.70.6",
3
+ "version": "0.70.8",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "@react-native-community/cli": "^9.0.0",
27
27
  "@react-native-community/cli-platform-android": "^9.0.0",
28
28
  "@react-native-community/cli-platform-ios": "^9.0.0",
29
- "@react-native-windows/cli": "0.70.1",
29
+ "@react-native-windows/cli": "0.70.2",
30
30
  "@react-native-windows/virtualized-list": "0.70.0",
31
31
  "@react-native/assets": "1.0.0",
32
32
  "@react-native/normalize-color": "2.0.0",