react-native-windows 0.66.18 → 0.66.21

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.
Files changed (63) hide show
  1. package/CHANGELOG.json +58 -1
  2. package/CHANGELOG.md +31 -5
  3. package/Chakra/ChakraHelpers.cpp +0 -1
  4. package/Directory.Build.props +4 -0
  5. package/Folly/Folly.vcxproj +4 -5
  6. package/Libraries/Network/RCTNetworkingWinShared.js +7 -0
  7. package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +3 -1
  8. package/Microsoft.ReactNative/IReactContext.cpp +17 -0
  9. package/Microsoft.ReactNative/IReactContext.h +2 -0
  10. package/Microsoft.ReactNative/IReactContext.idl +27 -0
  11. package/Microsoft.ReactNative/Modules/CreateModules.cpp +3 -3
  12. package/Microsoft.ReactNative/packages.config +1 -1
  13. package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp +17 -3
  14. package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.h +48 -0
  15. package/PropertySheets/JSEngine.props +1 -1
  16. package/Scripts/OfficeReact.Win32.nuspec +1 -1
  17. package/Shared/BaseScriptStoreImpl.cpp +1 -1
  18. package/Shared/CppRuntimeOptions.h +50 -0
  19. package/Shared/CreateModules.h +17 -2
  20. package/Shared/InspectorPackagerConnection.cpp +7 -5
  21. package/Shared/InspectorPackagerConnection.h +2 -2
  22. package/Shared/JSI/ChakraApi.cpp +0 -1
  23. package/Shared/JSI/ChakraRuntime.cpp +0 -1
  24. package/Shared/JSI/NapiJsiV8RuntimeHolder.cpp +72 -2
  25. package/Shared/JSI/NapiJsiV8RuntimeHolder.h +2 -0
  26. package/Shared/Modules/BlobModule.cpp +376 -0
  27. package/Shared/Modules/BlobModule.h +153 -0
  28. package/Shared/Modules/CxxModuleUtilities.cpp +19 -0
  29. package/Shared/Modules/CxxModuleUtilities.h +23 -0
  30. package/Shared/Modules/FileReaderModule.cpp +156 -0
  31. package/Shared/Modules/FileReaderModule.h +54 -0
  32. package/Shared/Modules/HttpModule.cpp +73 -70
  33. package/Shared/Modules/HttpModule.h +10 -3
  34. package/Shared/Modules/IBlobPersistor.h +30 -0
  35. package/Shared/Modules/IHttpModuleProxy.h +30 -0
  36. package/Shared/Modules/IRequestBodyHandler.h +52 -0
  37. package/Shared/Modules/IResponseHandler.h +27 -0
  38. package/Shared/Modules/IUriHandler.h +37 -0
  39. package/Shared/Modules/IWebSocketModuleContentHandler.h +26 -0
  40. package/Shared/Modules/IWebSocketModuleProxy.h +22 -0
  41. package/Shared/Modules/NetworkingModule.cpp +1 -1
  42. package/Shared/Modules/WebSocketModule.cpp +93 -23
  43. package/Shared/Modules/WebSocketModule.h +35 -6
  44. package/Shared/Networking/IHttpResource.h +101 -0
  45. package/Shared/{IWebSocketResource.h → Networking/IWebSocketResource.h} +2 -2
  46. package/Shared/Networking/OriginPolicy.h +15 -0
  47. package/Shared/Networking/OriginPolicyHttpFilter.cpp +747 -0
  48. package/Shared/Networking/OriginPolicyHttpFilter.h +112 -0
  49. package/Shared/Networking/WinRTHttpResource.cpp +465 -0
  50. package/Shared/{WinRTHttpResource.h → Networking/WinRTHttpResource.h} +35 -20
  51. package/Shared/Networking/WinRTTypes.h +33 -0
  52. package/Shared/{WinRTWebSocketResource.cpp → Networking/WinRTWebSocketResource.cpp} +2 -2
  53. package/Shared/{WinRTWebSocketResource.h → Networking/WinRTWebSocketResource.h} +3 -3
  54. package/Shared/OInstance.cpp +26 -6
  55. package/Shared/OInstance.h +8 -4
  56. package/Shared/RuntimeOptions.cpp +96 -15
  57. package/Shared/RuntimeOptions.h +32 -8
  58. package/Shared/Shared.vcxitems +24 -6
  59. package/Shared/Shared.vcxitems.filters +78 -18
  60. package/fmt/fmt.vcxproj +4 -5
  61. package/package.json +1 -1
  62. package/Shared/IHttpResource.h +0 -53
  63. package/Shared/WinRTHttpResource.cpp +0 -317
@@ -0,0 +1,112 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include "OriginPolicy.h"
7
+
8
+ // Windows API
9
+ #include <winrt/Windows.Foundation.h>
10
+ #include <winrt/Windows.Web.Http.Filters.h>
11
+ #include <winrt/Windows.Web.Http.h>
12
+
13
+ // Standard Library
14
+ #include <set>
15
+
16
+ namespace Microsoft::React::Networking {
17
+
18
+ class OriginPolicyHttpFilter
19
+ : public winrt::implements<OriginPolicyHttpFilter, winrt::Windows::Web::Http::Filters::IHttpFilter> {
20
+ public:
21
+ struct ConstWcharComparer {
22
+ bool operator()(const wchar_t *, const wchar_t *) const;
23
+ };
24
+
25
+ private:
26
+ static std::set<const wchar_t *, ConstWcharComparer> s_forbiddenMethods;
27
+ static std::set<const wchar_t *, ConstWcharComparer> s_simpleCorsMethods;
28
+ static std::set<const wchar_t *, ConstWcharComparer> s_simpleCorsRequestHeaderNames;
29
+ static std::set<const wchar_t *, ConstWcharComparer> s_simpleCorsResponseHeaderNames;
30
+ static std::set<const wchar_t *, ConstWcharComparer> s_simpleCorsContentTypeValues;
31
+ static std::set<const wchar_t *, ConstWcharComparer> s_corsForbiddenRequestHeaderNames;
32
+ static std::set<const wchar_t *, ConstWcharComparer> s_corsForbiddenRequestHeaderNamePrefixes;
33
+ static std::set<const wchar_t *, ConstWcharComparer> s_cookieSettingResponseHeaders;
34
+
35
+ // NOTE: Assumes static origin through owning client/resource/module/(React) instance's lifetime.
36
+ static winrt::Windows::Foundation::Uri s_origin;
37
+
38
+ struct AccessControlValues {
39
+ winrt::hstring AllowedOrigin;
40
+ winrt::hstring AllowedCredentials;
41
+ std::set<std::wstring> AllowedHeaders;
42
+ std::set<std::wstring> AllowedMethods;
43
+ std::set<std::wstring> ExposedHeaders;
44
+ size_t MaxAge;
45
+ };
46
+
47
+ winrt::Windows::Web::Http::Filters::IHttpFilter m_innerFilter;
48
+
49
+ public:
50
+ static void SetStaticOrigin(std::string &&url);
51
+
52
+ static bool IsSameOrigin(
53
+ winrt::Windows::Foundation::Uri const &u1,
54
+ winrt::Windows::Foundation::Uri const &u2) noexcept;
55
+
56
+ static winrt::Windows::Foundation::Uri GetOrigin(winrt::Windows::Foundation::Uri const &uri) noexcept;
57
+
58
+ static bool IsSimpleCorsRequest(winrt::Windows::Web::Http::HttpRequestMessage const &request) noexcept;
59
+
60
+ static bool AreSafeRequestHeaders(
61
+ winrt::Windows::Web::Http::Headers::HttpRequestHeaderCollection const &headers) noexcept;
62
+
63
+ static std::set<const wchar_t *> CorsUnsafeNotForbiddenRequestHeaderNames(
64
+ winrt::Windows::Web::Http::Headers::HttpRequestHeaderCollection const &headers) noexcept;
65
+
66
+ static AccessControlValues ExtractAccessControlValues(
67
+ winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> const &headers);
68
+
69
+ static bool IsCorsSafelistedRequestHeader(winrt::hstring const &name, winrt::hstring const &value) noexcept;
70
+
71
+ static bool IsCorsUnsafeRequestHeaderByte(wchar_t c) noexcept;
72
+
73
+ // Filter out Http-Only cookies from response headers to prevent malicious code from being sent to a malicious server
74
+ static void RemoveHttpOnlyCookiesFromResponseHeaders(
75
+ winrt::Windows::Web::Http::HttpResponseMessage const &response,
76
+ bool removeAll);
77
+
78
+ OriginPolicyHttpFilter(winrt::Windows::Web::Http::Filters::IHttpFilter &&innerFilter);
79
+
80
+ OriginPolicyHttpFilter();
81
+
82
+ OriginPolicy ValidateRequest(winrt::Windows::Web::Http::HttpRequestMessage const &request);
83
+
84
+ void ValidatePreflightResponse(
85
+ winrt::Windows::Web::Http::HttpRequestMessage const &request,
86
+ winrt::Windows::Web::Http::HttpResponseMessage const &response) const;
87
+
88
+ void ValidateResponse(
89
+ winrt::Windows::Web::Http::HttpResponseMessage const &response,
90
+ const OriginPolicy effectivePolicy) const;
91
+
92
+ void ValidateAllowOrigin(
93
+ winrt::hstring const &allowedOrigin,
94
+ winrt::hstring const &allowCredentials,
95
+ winrt::Windows::Foundation::IInspectable const &iArgs) const;
96
+
97
+ winrt::Windows::Foundation::IAsyncOperationWithProgress<
98
+ winrt::Windows::Web::Http::HttpResponseMessage,
99
+ winrt::Windows::Web::Http::HttpProgress>
100
+ SendPreflightAsync(winrt::Windows::Web::Http::HttpRequestMessage const &request) const;
101
+
102
+ #pragma region IHttpFilter
103
+
104
+ winrt::Windows::Foundation::IAsyncOperationWithProgress<
105
+ winrt::Windows::Web::Http::HttpResponseMessage,
106
+ winrt::Windows::Web::Http::HttpProgress>
107
+ SendRequestAsync(winrt::Windows::Web::Http::HttpRequestMessage const &request);
108
+
109
+ #pragma endregion IHttpFilter
110
+ };
111
+
112
+ } // namespace Microsoft::React::Networking
@@ -0,0 +1,465 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "WinRTHttpResource.h"
5
+
6
+ #include <CppRuntimeOptions.h>
7
+ #include <ReactPropertyBag.h>
8
+ #include <Utils/CppWinrtLessExceptions.h>
9
+ #include <Utils/WinRTConversions.h>
10
+ #include <utilities.h>
11
+ #include "OriginPolicyHttpFilter.h"
12
+
13
+ // Boost Libraries
14
+ #include <boost/algorithm/string.hpp>
15
+
16
+ // Windows API
17
+ #include <winrt/Windows.Security.Cryptography.h>
18
+ #include <winrt/Windows.Storage.Streams.h>
19
+ #include <winrt/Windows.Web.Http.Headers.h>
20
+
21
+ using folly::dynamic;
22
+
23
+ using std::function;
24
+ using std::scoped_lock;
25
+ using std::shared_ptr;
26
+ using std::string;
27
+ using std::vector;
28
+ using std::weak_ptr;
29
+
30
+ using winrt::fire_and_forget;
31
+ using winrt::hresult_error;
32
+ using winrt::to_hstring;
33
+ using winrt::to_string;
34
+ using winrt::Windows::Foundation::IInspectable;
35
+ using winrt::Windows::Foundation::Uri;
36
+ using winrt::Windows::Security::Cryptography::CryptographicBuffer;
37
+ using winrt::Windows::Storage::StorageFile;
38
+ using winrt::Windows::Storage::Streams::DataReader;
39
+ using winrt::Windows::Storage::Streams::UnicodeEncoding;
40
+ using winrt::Windows::Web::Http::HttpBufferContent;
41
+ using winrt::Windows::Web::Http::HttpMethod;
42
+ using winrt::Windows::Web::Http::HttpRequestMessage;
43
+ using winrt::Windows::Web::Http::HttpStreamContent;
44
+ using winrt::Windows::Web::Http::HttpStringContent;
45
+ using winrt::Windows::Web::Http::IHttpClient;
46
+ using winrt::Windows::Web::Http::IHttpContent;
47
+ using winrt::Windows::Web::Http::Headers::HttpMediaTypeHeaderValue;
48
+
49
+ namespace Microsoft::React::Networking {
50
+
51
+ #pragma region WinRTHttpResource
52
+
53
+ WinRTHttpResource::WinRTHttpResource(IHttpClient &&client) noexcept : m_client{std::move(client)} {}
54
+
55
+ WinRTHttpResource::WinRTHttpResource() noexcept : WinRTHttpResource(winrt::Windows::Web::Http::HttpClient{}) {}
56
+
57
+ #pragma region IHttpResource
58
+
59
+ void WinRTHttpResource::SendRequest(
60
+ string &&method,
61
+ string &&url,
62
+ int64_t requestId,
63
+ Headers &&headers,
64
+ dynamic &&data,
65
+ string &&responseType,
66
+ bool useIncrementalUpdates,
67
+ int64_t timeout,
68
+ bool withCredentials,
69
+ std::function<void(int64_t)> &&callback) noexcept /*override*/ {
70
+ // Enforce supported args
71
+ assert(responseType == "text" || responseType == "base64" | responseType == "blob");
72
+
73
+ if (callback) {
74
+ callback(requestId);
75
+ }
76
+
77
+ try {
78
+ HttpMethod httpMethod{to_hstring(std::move(method))};
79
+ Uri uri{to_hstring(std::move(url))};
80
+ HttpRequestMessage request{httpMethod, uri};
81
+
82
+ auto args = winrt::make<RequestArgs>();
83
+ auto concreteArgs = args.as<RequestArgs>();
84
+ concreteArgs->RequestId = requestId;
85
+ concreteArgs->Headers = std::move(headers);
86
+ concreteArgs->Data = std::move(data);
87
+ concreteArgs->IncrementalUpdates = useIncrementalUpdates;
88
+ concreteArgs->WithCredentials = withCredentials;
89
+ concreteArgs->ResponseType = std::move(responseType);
90
+ concreteArgs->Timeout = timeout;
91
+
92
+ PerformSendRequest(std::move(request), args);
93
+ } catch (std::exception const &e) {
94
+ if (m_onError) {
95
+ m_onError(requestId, e.what());
96
+ }
97
+ } catch (hresult_error const &e) {
98
+ if (m_onError) {
99
+ m_onError(requestId, Utilities::HResultToString(e));
100
+ }
101
+ } catch (...) {
102
+ m_onError(requestId, "Unidentified error sending HTTP request");
103
+ }
104
+ }
105
+
106
+ void WinRTHttpResource::AbortRequest(int64_t requestId) noexcept /*override*/ {
107
+ ResponseOperation request{nullptr};
108
+
109
+ {
110
+ scoped_lock lock{m_mutex};
111
+ auto iter = m_responses.find(requestId);
112
+ if (iter == std::end(m_responses)) {
113
+ return;
114
+ }
115
+ request = iter->second;
116
+ }
117
+
118
+ try {
119
+ request.Cancel();
120
+ } catch (hresult_error const &e) {
121
+ m_onError(requestId, Utilities::HResultToString(e));
122
+ }
123
+ }
124
+
125
+ void WinRTHttpResource::ClearCookies() noexcept /*override*/ {
126
+ assert(false);
127
+ // NOT IMPLEMENTED
128
+ }
129
+
130
+ void WinRTHttpResource::SetOnRequestSuccess(function<void(int64_t requestId)> &&handler) noexcept /*override*/ {
131
+ m_onRequestSuccess = std::move(handler);
132
+ }
133
+
134
+ void WinRTHttpResource::SetOnResponse(function<void(int64_t requestId, Response &&response)> &&handler) noexcept
135
+ /*override*/ {
136
+ m_onResponse = std::move(handler);
137
+ }
138
+
139
+ void WinRTHttpResource::SetOnData(function<void(int64_t requestId, string &&responseData)> &&handler) noexcept
140
+ /*override*/ {
141
+ m_onData = std::move(handler);
142
+ }
143
+
144
+ void WinRTHttpResource::SetOnData(function<void(int64_t requestId, dynamic &&responseData)> &&handler) noexcept
145
+ /*override*/
146
+ {
147
+ m_onDataDynamic = std::move(handler);
148
+ }
149
+
150
+ void WinRTHttpResource::SetOnError(function<void(int64_t requestId, string &&errorMessage)> &&handler) noexcept
151
+ /*override*/ {
152
+ m_onError = std::move(handler);
153
+ }
154
+
155
+ #pragma endregion IHttpResource
156
+
157
+ void WinRTHttpResource::TrackResponse(int64_t requestId, ResponseOperation response) noexcept {
158
+ scoped_lock lock{m_mutex};
159
+ m_responses[requestId] = response;
160
+ }
161
+
162
+ void WinRTHttpResource::UntrackResponse(int64_t requestId) noexcept {
163
+ scoped_lock lock{m_mutex};
164
+ m_responses.erase(requestId);
165
+ }
166
+
167
+ fire_and_forget WinRTHttpResource::PerformSendRequest(HttpRequestMessage &&request, IInspectable const &args) noexcept {
168
+ // Keep references after coroutine suspension.
169
+ auto self = shared_from_this();
170
+ auto coRequest = std::move(request);
171
+ auto coArgs = args;
172
+ auto coReqArgs = coArgs.as<RequestArgs>();
173
+
174
+ // Ensure background thread
175
+ co_await winrt::resume_background();
176
+
177
+ // If URI handler is available, it takes over request processing.
178
+ if (auto uriHandler = self->m_uriHandler.lock()) {
179
+ auto uri = winrt::to_string(coRequest.RequestUri().ToString());
180
+ try {
181
+ if (uriHandler->Supports(uri, coReqArgs->ResponseType)) {
182
+ auto blob = uriHandler->Fetch(uri);
183
+ if (self->m_onDataDynamic && self->m_onRequestSuccess) {
184
+ self->m_onDataDynamic(coReqArgs->RequestId, std::move(blob));
185
+ self->m_onRequestSuccess(coReqArgs->RequestId);
186
+ }
187
+
188
+ co_return;
189
+ }
190
+ } catch (const hresult_error &e) {
191
+ if (self->m_onError)
192
+ co_return self->m_onError(coReqArgs->RequestId, Utilities::HResultToString(e));
193
+ } catch (const std::exception &e) {
194
+ if (self->m_onError)
195
+ co_return self->m_onError(coReqArgs->RequestId, e.what());
196
+ }
197
+ }
198
+
199
+ HttpMediaTypeHeaderValue contentType{nullptr};
200
+ string contentEncoding;
201
+ string contentLength;
202
+
203
+ // Headers are generally case-insensitive
204
+ // https://www.ietf.org/rfc/rfc2616.txt section 4.2
205
+ for (auto &header : coReqArgs->Headers) {
206
+ if (boost::iequals(header.first.c_str(), "Content-Type")) {
207
+ bool success = HttpMediaTypeHeaderValue::TryParse(to_hstring(header.second), contentType);
208
+ if (!success && m_onError) {
209
+ co_return m_onError(coReqArgs->RequestId, "Failed to parse Content-Type");
210
+ }
211
+ } else if (boost::iequals(header.first.c_str(), "Content-Encoding")) {
212
+ contentEncoding = header.second;
213
+ } else if (boost::iequals(header.first.c_str(), "Content-Length")) {
214
+ contentLength = header.second;
215
+ } else if (boost::iequals(header.first.c_str(), "Authorization")) {
216
+ bool success =
217
+ coRequest.Headers().TryAppendWithoutValidation(to_hstring(header.first), to_hstring(header.second));
218
+ if (!success && m_onError) {
219
+ co_return m_onError(coReqArgs->RequestId, "Failed to append Authorization");
220
+ }
221
+ } else {
222
+ try {
223
+ coRequest.Headers().Append(to_hstring(header.first), to_hstring(header.second));
224
+ } catch (hresult_error const &e) {
225
+ if (self->m_onError) {
226
+ co_return self->m_onError(coReqArgs->RequestId, Utilities::HResultToString(e));
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ IHttpContent content{nullptr};
233
+ auto &data = coReqArgs->Data;
234
+ if (!data.isNull()) {
235
+ auto bodyHandler = self->m_requestBodyHandler.lock();
236
+ if (bodyHandler && bodyHandler->Supports(data)) {
237
+ auto contentTypeString = contentType ? winrt::to_string(contentType.ToString()) : "";
238
+ dynamic blob;
239
+ try {
240
+ blob = bodyHandler->ToRequestBody(data, contentTypeString);
241
+ } catch (const std::invalid_argument &e) {
242
+ if (self->m_onError) {
243
+ self->m_onError(coReqArgs->RequestId, e.what());
244
+ }
245
+ co_return;
246
+ }
247
+ auto bytes = blob["bytes"];
248
+ auto byteVector = vector<uint8_t>(bytes.size());
249
+ for (auto &byte : bytes) {
250
+ byteVector.push_back(static_cast<uint8_t>(byte.asInt()));
251
+ }
252
+ auto view = winrt::array_view<uint8_t>{byteVector};
253
+ auto buffer = CryptographicBuffer::CreateFromByteArray(view);
254
+ content = HttpBufferContent{std::move(buffer)};
255
+ } else if (!data["string"].empty()) {
256
+ content = HttpStringContent{to_hstring(data["string"].asString())};
257
+ } else if (!data["base64"].empty()) {
258
+ auto buffer = CryptographicBuffer::DecodeFromBase64String(to_hstring(data["base64"].asString()));
259
+ content = HttpBufferContent{std::move(buffer)};
260
+ } else if (!data["uri"].empty()) {
261
+ auto file = co_await StorageFile::GetFileFromApplicationUriAsync(Uri{to_hstring(data["uri"].asString())});
262
+ auto stream = co_await file.OpenReadAsync();
263
+ content = HttpStreamContent{std::move(stream)};
264
+ } else if (!data["form"].empty()) {
265
+ // #9535 - HTTP form data support
266
+ // winrt::Windows::Web::Http::HttpMultipartFormDataContent()
267
+ } else {
268
+ // Assume empty request body.
269
+ // content = HttpStringContent{L""};
270
+ }
271
+ }
272
+
273
+ if (content != nullptr) {
274
+ // Attach content headers
275
+ if (contentType) {
276
+ content.Headers().ContentType(contentType);
277
+ }
278
+ if (!contentEncoding.empty()) {
279
+ if (!content.Headers().ContentEncoding().TryParseAdd(to_hstring(contentEncoding))) {
280
+ if (self->m_onError)
281
+ self->m_onError(coReqArgs->RequestId, "Failed to parse Content-Encoding");
282
+
283
+ co_return;
284
+ }
285
+ }
286
+
287
+ if (!contentLength.empty()) {
288
+ const auto contentLengthHeader = _atoi64(contentLength.c_str());
289
+ content.Headers().ContentLength(contentLengthHeader);
290
+ }
291
+
292
+ coRequest.Content(content);
293
+ }
294
+
295
+ try {
296
+ coRequest.Properties().Insert(L"RequestArgs", coArgs);
297
+ auto sendRequestOp = self->m_client.SendRequestAsync(coRequest);
298
+ self->TrackResponse(coReqArgs->RequestId, sendRequestOp);
299
+
300
+ co_await lessthrow_await_adapter<ResponseOperation>{sendRequestOp};
301
+ auto result = sendRequestOp.ErrorCode();
302
+ if (result < 0) {
303
+ if (self->m_onError) {
304
+ self->m_onError(coReqArgs->RequestId, Utilities::HResultToString(std::move(result)));
305
+ }
306
+ co_return self->UntrackResponse(coReqArgs->RequestId);
307
+ }
308
+
309
+ auto response = sendRequestOp.GetResults();
310
+ if (response) {
311
+ if (self->m_onResponse) {
312
+ auto url = to_string(response.RequestMessage().RequestUri().AbsoluteUri());
313
+
314
+ // Gather headers for both the response content and the response itself
315
+ // See Invoke-WebRequest PowerShell cmdlet or Chromium response handling
316
+ Headers responseHeaders;
317
+ for (auto header : response.Headers()) {
318
+ responseHeaders.emplace(to_string(header.Key()), to_string(header.Value()));
319
+ }
320
+ for (auto header : response.Content().Headers()) {
321
+ responseHeaders.emplace(to_string(header.Key()), to_string(header.Value()));
322
+ }
323
+
324
+ self->m_onResponse(
325
+ coReqArgs->RequestId,
326
+ {static_cast<int32_t>(response.StatusCode()), std::move(url), std::move(responseHeaders)});
327
+ }
328
+ }
329
+
330
+ // #9534 - Support HTTP incremental updates
331
+ if (response && response.Content()) {
332
+ auto inputStream = co_await response.Content().ReadAsInputStreamAsync();
333
+ auto reader = DataReader{inputStream};
334
+
335
+ // #9510 - 10mb limit on fetch
336
+ co_await reader.LoadAsync(10 * 1024 * 1024);
337
+
338
+ // Let response handler take over, if set
339
+ if (auto responseHandler = self->m_responseHandler.lock()) {
340
+ if (responseHandler->Supports(coReqArgs->ResponseType)) {
341
+ auto bytes = vector<uint8_t>(reader.UnconsumedBufferLength());
342
+ reader.ReadBytes(bytes);
343
+ auto blob = responseHandler->ToResponseData(std::move(bytes));
344
+
345
+ if (self->m_onDataDynamic && self->m_onRequestSuccess) {
346
+ self->m_onDataDynamic(coReqArgs->RequestId, std::move(blob));
347
+ self->m_onRequestSuccess(coReqArgs->RequestId);
348
+ }
349
+
350
+ co_return;
351
+ }
352
+ }
353
+
354
+ auto isText = coReqArgs->ResponseType == "text";
355
+ if (isText) {
356
+ reader.UnicodeEncoding(UnicodeEncoding::Utf8);
357
+ }
358
+
359
+ // #9510 - We currently accumulate all incoming request data in 10MB chunks.
360
+ uint32_t segmentSize = 10 * 1024 * 1024;
361
+ string responseData;
362
+ winrt::Windows::Storage::Streams::IBuffer buffer;
363
+ uint32_t length;
364
+ do {
365
+ co_await reader.LoadAsync(segmentSize);
366
+ length = reader.UnconsumedBufferLength();
367
+
368
+ if (isText) {
369
+ auto data = std::vector<uint8_t>(length);
370
+ reader.ReadBytes(data);
371
+
372
+ responseData += string(Common::Utilities::CheckedReinterpretCast<char *>(data.data()), data.size());
373
+ } else {
374
+ buffer = reader.ReadBuffer(length);
375
+ auto data = CryptographicBuffer::EncodeToBase64String(buffer);
376
+
377
+ responseData += to_string(std::wstring_view(data));
378
+ }
379
+ } while (length > 0);
380
+
381
+ if (self->m_onData) {
382
+ self->m_onData(coReqArgs->RequestId, std::move(responseData));
383
+ }
384
+ } else {
385
+ if (self->m_onError) {
386
+ self->m_onError(coReqArgs->RequestId, response == nullptr ? "request failed" : "No response content");
387
+ }
388
+ }
389
+ } catch (std::exception const &e) {
390
+ if (self->m_onError) {
391
+ self->m_onError(coReqArgs->RequestId, e.what());
392
+ }
393
+ } catch (hresult_error const &e) {
394
+ if (self->m_onError) {
395
+ self->m_onError(coReqArgs->RequestId, Utilities::HResultToString(e));
396
+ }
397
+ } catch (...) {
398
+ if (self->m_onError) {
399
+ self->m_onError(coReqArgs->RequestId, "Unhandled exception during request");
400
+ }
401
+ }
402
+
403
+ self->UntrackResponse(coReqArgs->RequestId);
404
+ } // PerformSendRequest
405
+
406
+ #pragma region IHttpModuleProxy
407
+
408
+ void WinRTHttpResource::AddUriHandler(shared_ptr<IUriHandler> /*uriHandler*/) noexcept /*override*/
409
+ {
410
+ // TODO: Implement custom URI handling.
411
+ }
412
+
413
+ void WinRTHttpResource::AddRequestBodyHandler(shared_ptr<IRequestBodyHandler> requestBodyHandler) noexcept /*override*/
414
+ {
415
+ m_requestBodyHandler = weak_ptr<IRequestBodyHandler>(requestBodyHandler);
416
+ }
417
+
418
+ void WinRTHttpResource::AddResponseHandler(shared_ptr<IResponseHandler> responseHandler) noexcept /*override*/
419
+ {
420
+ m_responseHandler = weak_ptr<IResponseHandler>(responseHandler);
421
+ }
422
+
423
+ #pragma endregion IHttpModuleProxy
424
+
425
+ #pragma endregion WinRTHttpResource
426
+
427
+ #pragma region IHttpResource
428
+
429
+ /*static*/ shared_ptr<IHttpResource> IHttpResource::Make(
430
+ winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept {
431
+ using namespace winrt::Microsoft::ReactNative;
432
+ using winrt::Windows::Web::Http::HttpClient;
433
+
434
+ shared_ptr<WinRTHttpResource> result;
435
+
436
+ if (static_cast<OriginPolicy>(GetRuntimeOptionInt("Http.OriginPolicy")) == OriginPolicy::None) {
437
+ result = std::make_shared<WinRTHttpResource>();
438
+ } else {
439
+ auto globalOrigin = GetRuntimeOptionString("Http.GlobalOrigin");
440
+ OriginPolicyHttpFilter::SetStaticOrigin(std::move(globalOrigin));
441
+ auto opFilter = winrt::make<OriginPolicyHttpFilter>();
442
+ auto client = HttpClient{opFilter};
443
+
444
+ result = std::make_shared<WinRTHttpResource>(std::move(client));
445
+ }
446
+
447
+ // Register resource as HTTP module proxy.
448
+ if (inspectableProperties) {
449
+ auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IHttpModuleProxy>>>{L"HttpModule.Proxy"};
450
+ auto propBag = ReactPropertyBag{inspectableProperties.try_as<IReactPropertyBag>()};
451
+ auto moduleProxy = weak_ptr<IHttpModuleProxy>{result};
452
+ propBag.Set(propId, std::move(moduleProxy));
453
+ }
454
+
455
+ return result;
456
+ }
457
+
458
+ /*static*/ shared_ptr<IHttpResource> IHttpResource::Make() noexcept {
459
+ auto inspectableProperties = IInspectable{nullptr};
460
+ return Make(inspectableProperties);
461
+ }
462
+
463
+ #pragma endregion IHttpResource
464
+
465
+ } // namespace Microsoft::React::Networking
@@ -3,7 +3,10 @@
3
3
 
4
4
  #pragma once
5
5
 
6
- #include <IHttpResource.h>
6
+ #include "IHttpResource.h"
7
+
8
+ #include <Modules/IHttpModuleProxy.h>
9
+ #include "WinRTTypes.h"
7
10
 
8
11
  // Windows API
9
12
  #include <winrt/Windows.Web.Http.h>
@@ -11,33 +14,33 @@
11
14
  // Standard Library
12
15
  #include <mutex>
13
16
 
14
- namespace Microsoft::React {
15
-
16
- class WinRTHttpResource : public IHttpResource, public std::enable_shared_from_this<WinRTHttpResource> {
17
- typedef winrt::Windows::Foundation::IAsyncOperationWithProgress<
18
- winrt::Windows::Web::Http::HttpResponseMessage,
19
- winrt::Windows::Web::Http::HttpProgress>
20
- ResponseType;
21
-
22
- static int64_t s_lastRequestId;
17
+ namespace Microsoft::React::Networking {
23
18
 
19
+ class WinRTHttpResource : public IHttpResource,
20
+ public IHttpModuleProxy,
21
+ public std::enable_shared_from_this<WinRTHttpResource> {
24
22
  winrt::Windows::Web::Http::IHttpClient m_client;
25
23
  std::mutex m_mutex;
26
- std::unordered_map<int64_t, ResponseType> m_responses;
24
+ std::unordered_map<int64_t, ResponseOperation> m_responses;
27
25
 
28
- std::function<void(int64_t requestId)> m_onRequest;
26
+ std::function<void(int64_t requestId)> m_onRequestSuccess;
29
27
  std::function<void(int64_t requestId, Response &&response)> m_onResponse;
30
28
  std::function<void(int64_t requestId, std::string &&responseData)> m_onData;
29
+ std::function<void(int64_t requestId, folly::dynamic &&responseData)> m_onDataDynamic;
31
30
  std::function<void(int64_t requestId, std::string &&errorMessage /*, bool isTimeout*/)> m_onError;
32
31
 
33
- void TrackResponse(int64_t requestId, ResponseType response) noexcept;
32
+ // Used for IHttpModuleProxy
33
+ std::weak_ptr<IUriHandler> m_uriHandler;
34
+ std::weak_ptr<IRequestBodyHandler> m_requestBodyHandler;
35
+ std::weak_ptr<IResponseHandler> m_responseHandler;
36
+
37
+ void TrackResponse(int64_t requestId, ResponseOperation response) noexcept;
34
38
 
35
39
  void UntrackResponse(int64_t requestId) noexcept;
36
40
 
37
41
  winrt::fire_and_forget PerformSendRequest(
38
- int64_t requestId,
39
42
  winrt::Windows::Web::Http::HttpRequestMessage &&request,
40
- bool textResponse) noexcept;
43
+ winrt::Windows::Foundation::IInspectable const &args) noexcept;
41
44
 
42
45
  public:
43
46
  WinRTHttpResource() noexcept;
@@ -49,8 +52,9 @@ class WinRTHttpResource : public IHttpResource, public std::enable_shared_from_t
49
52
  void SendRequest(
50
53
  std::string &&method,
51
54
  std::string &&url,
55
+ int64_t requestId,
52
56
  Headers &&headers,
53
- BodyData &&bodyData,
57
+ folly::dynamic &&data,
54
58
  std::string &&responseType,
55
59
  bool useIncrementalUpdates,
56
60
  int64_t timeout,
@@ -59,13 +63,24 @@ class WinRTHttpResource : public IHttpResource, public std::enable_shared_from_t
59
63
  void AbortRequest(int64_t requestId) noexcept override;
60
64
  void ClearCookies() noexcept override;
61
65
 
62
- #pragma endregion IHttpResource
63
-
64
- void SetOnRequest(std::function<void(int64_t requestId)> &&handler) noexcept override;
66
+ void SetOnRequestSuccess(std::function<void(int64_t requestId)> &&handler) noexcept override;
65
67
  void SetOnResponse(std::function<void(int64_t requestId, Response &&response)> &&handler) noexcept override;
66
68
  void SetOnData(std::function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept override;
69
+ void SetOnData(std::function<void(int64_t requestId, folly::dynamic &&responseData)> &&handler) noexcept override;
67
70
  void SetOnError(std::function<void(int64_t requestId, std::string &&errorMessage /*, bool isTimeout*/)>
68
71
  &&handler) noexcept override;
72
+
73
+ #pragma endregion IHttpResource
74
+
75
+ #pragma region IHttpModuleProxy
76
+
77
+ void AddUriHandler(std::shared_ptr<IUriHandler> uriHandler) noexcept override;
78
+
79
+ void AddRequestBodyHandler(std::shared_ptr<IRequestBodyHandler> requestBodyHandler) noexcept override;
80
+
81
+ void AddResponseHandler(std::shared_ptr<IResponseHandler> responseHandler) noexcept override;
82
+
83
+ #pragma endregion IHttpModuleProxy
69
84
  };
70
85
 
71
- } // namespace Microsoft::React
86
+ } // namespace Microsoft::React::Networking