react-native-windows 0.69.7 → 0.69.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.
- package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +25 -0
- package/Microsoft.ReactNative/Pch/pch.h +0 -1
- package/Microsoft.ReactNative.Managed/packages.lock.json +27 -2
- package/PropertySheets/Generated/PackageVersion.g.props +2 -2
- package/Shared/Modules/BlobModule.cpp +4 -4
- package/Shared/Modules/BlobModule.h +1 -1
- package/Shared/Modules/FileReaderModule.cpp +2 -2
- package/Shared/Modules/HttpModule.cpp +4 -2
- package/Shared/Modules/IBlobPersistor.h +1 -1
- package/Shared/Networking/IHttpResource.h +2 -1
- package/Shared/Networking/IRedirectEventSource.h +18 -0
- package/Shared/Networking/IWinRTHttpRequestFactory.h +22 -0
- package/Shared/Networking/OriginPolicyHttpFilter.cpp +47 -15
- package/Shared/Networking/OriginPolicyHttpFilter.h +16 -3
- package/Shared/Networking/RedirectHttpFilter.cpp +283 -0
- package/Shared/Networking/RedirectHttpFilter.h +97 -0
- package/Shared/Networking/WinRTHttpResource.cpp +225 -140
- package/Shared/Networking/WinRTHttpResource.h +17 -4
- package/Shared/OInstance.cpp +10 -2
- package/Shared/Shared.vcxitems +4 -0
- package/Shared/Shared.vcxitems.filters +12 -0
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
+
#undef WINRT_LEAN_AND_MEAN
|
|
5
|
+
|
|
4
6
|
#include "WinRTHttpResource.h"
|
|
5
7
|
|
|
6
8
|
#include <CppRuntimeOptions.h>
|
|
@@ -8,12 +10,15 @@
|
|
|
8
10
|
#include <Utils/CppWinrtLessExceptions.h>
|
|
9
11
|
#include <Utils/WinRTConversions.h>
|
|
10
12
|
#include <utilities.h>
|
|
13
|
+
#include "IRedirectEventSource.h"
|
|
11
14
|
#include "OriginPolicyHttpFilter.h"
|
|
15
|
+
#include "RedirectHttpFilter.h"
|
|
12
16
|
|
|
13
17
|
// Boost Libraries
|
|
14
18
|
#include <boost/algorithm/string.hpp>
|
|
15
19
|
|
|
16
20
|
// Windows API
|
|
21
|
+
#include <winrt/Windows.Foundation.Collections.h>
|
|
17
22
|
#include <winrt/Windows.Security.Cryptography.h>
|
|
18
23
|
#include <winrt/Windows.Storage.Streams.h>
|
|
19
24
|
#include <winrt/Windows.Web.Http.Headers.h>
|
|
@@ -30,7 +35,7 @@ using std::weak_ptr;
|
|
|
30
35
|
using winrt::fire_and_forget;
|
|
31
36
|
using winrt::hresult_error;
|
|
32
37
|
using winrt::to_hstring;
|
|
33
|
-
using winrt::
|
|
38
|
+
using winrt::Windows::Foundation::IAsyncOperation;
|
|
34
39
|
using winrt::Windows::Foundation::IInspectable;
|
|
35
40
|
using winrt::Windows::Foundation::Uri;
|
|
36
41
|
using winrt::Windows::Security::Cryptography::CryptographicBuffer;
|
|
@@ -54,6 +59,138 @@ WinRTHttpResource::WinRTHttpResource(IHttpClient &&client) noexcept : m_client{s
|
|
|
54
59
|
|
|
55
60
|
WinRTHttpResource::WinRTHttpResource() noexcept : WinRTHttpResource(winrt::Windows::Web::Http::HttpClient{}) {}
|
|
56
61
|
|
|
62
|
+
#pragma region IWinRTHttpRequestFactory
|
|
63
|
+
|
|
64
|
+
IAsyncOperation<HttpRequestMessage> WinRTHttpResource::CreateRequest(
|
|
65
|
+
HttpMethod &&method,
|
|
66
|
+
Uri &&uri,
|
|
67
|
+
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, IInspectable> props) noexcept /*override*/ {
|
|
68
|
+
auto request = HttpRequestMessage{std::move(method), std::move(uri)};
|
|
69
|
+
for (auto prop : props) {
|
|
70
|
+
request.Properties().Insert(prop.Key(), prop.Value());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
auto iReqArgs = request.Properties().Lookup(L"RequestArgs");
|
|
74
|
+
auto reqArgs = iReqArgs.as<RequestArgs>();
|
|
75
|
+
auto self = shared_from_this();
|
|
76
|
+
|
|
77
|
+
HttpMediaTypeHeaderValue contentType{nullptr};
|
|
78
|
+
string contentEncoding;
|
|
79
|
+
string contentLength;
|
|
80
|
+
|
|
81
|
+
// Headers are generally case-insensitive
|
|
82
|
+
// https://www.ietf.org/rfc/rfc2616.txt section 4.2
|
|
83
|
+
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);
|
|
86
|
+
if (!success) {
|
|
87
|
+
if (self->m_onError) {
|
|
88
|
+
self->m_onError(reqArgs->RequestId, "Failed to parse Content-Type", false);
|
|
89
|
+
}
|
|
90
|
+
co_return nullptr;
|
|
91
|
+
}
|
|
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));
|
|
98
|
+
if (!success) {
|
|
99
|
+
if (self->m_onError) {
|
|
100
|
+
self->m_onError(reqArgs->RequestId, "Failed to append Authorization", false);
|
|
101
|
+
}
|
|
102
|
+
co_return nullptr;
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
try {
|
|
106
|
+
request.Headers().Append(to_hstring(header.first), to_hstring(header.second));
|
|
107
|
+
} catch (hresult_error const &e) {
|
|
108
|
+
if (self->m_onError) {
|
|
109
|
+
self->m_onError(reqArgs->RequestId, Utilities::HResultToString(e), false);
|
|
110
|
+
}
|
|
111
|
+
co_return nullptr;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Initialize content
|
|
117
|
+
IHttpContent content{nullptr};
|
|
118
|
+
auto &data = reqArgs->Data;
|
|
119
|
+
if (!data.isNull()) {
|
|
120
|
+
auto bodyHandler = self->m_requestBodyHandler.lock();
|
|
121
|
+
if (bodyHandler && bodyHandler->Supports(data)) {
|
|
122
|
+
auto contentTypeString = contentType ? winrt::to_string(contentType.ToString()) : "";
|
|
123
|
+
dynamic blob;
|
|
124
|
+
try {
|
|
125
|
+
blob = bodyHandler->ToRequestBody(data, contentTypeString);
|
|
126
|
+
} catch (const std::invalid_argument &e) {
|
|
127
|
+
if (self->m_onError) {
|
|
128
|
+
self->m_onError(reqArgs->RequestId, e.what(), false);
|
|
129
|
+
}
|
|
130
|
+
co_return nullptr;
|
|
131
|
+
}
|
|
132
|
+
auto bytes = blob["bytes"];
|
|
133
|
+
auto byteVector = vector<uint8_t>(bytes.size());
|
|
134
|
+
for (auto &byte : bytes) {
|
|
135
|
+
byteVector.push_back(static_cast<uint8_t>(byte.asInt()));
|
|
136
|
+
}
|
|
137
|
+
auto view = winrt::array_view<uint8_t const>{byteVector};
|
|
138
|
+
auto buffer = CryptographicBuffer::CreateFromByteArray(view);
|
|
139
|
+
content = HttpBufferContent{std::move(buffer)};
|
|
140
|
+
} else if (!data["string"].isNull()) {
|
|
141
|
+
content = HttpStringContent{to_hstring(data["string"].asString())};
|
|
142
|
+
} else if (!data["base64"].empty()) {
|
|
143
|
+
auto buffer = CryptographicBuffer::DecodeFromBase64String(to_hstring(data["base64"].asString()));
|
|
144
|
+
content = HttpBufferContent{std::move(buffer)};
|
|
145
|
+
} else if (!data["uri"].empty()) {
|
|
146
|
+
auto file = co_await StorageFile::GetFileFromApplicationUriAsync(Uri{to_hstring(data["uri"].asString())});
|
|
147
|
+
auto stream = co_await file.OpenReadAsync();
|
|
148
|
+
content = HttpStreamContent{std::move(stream)};
|
|
149
|
+
} else if (!data["form"].empty()) {
|
|
150
|
+
// #9535 - HTTP form data support
|
|
151
|
+
// winrt::Windows::Web::Http::HttpMultipartFormDataContent()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Attach content headers
|
|
156
|
+
if (content != nullptr) {
|
|
157
|
+
if (contentType) {
|
|
158
|
+
content.Headers().ContentType(contentType);
|
|
159
|
+
}
|
|
160
|
+
if (!contentEncoding.empty()) {
|
|
161
|
+
if (!content.Headers().ContentEncoding().TryParseAdd(to_hstring(contentEncoding))) {
|
|
162
|
+
if (self->m_onError)
|
|
163
|
+
self->m_onError(reqArgs->RequestId, "Failed to parse Content-Encoding", false);
|
|
164
|
+
|
|
165
|
+
co_return nullptr;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!contentLength.empty()) {
|
|
170
|
+
try {
|
|
171
|
+
const auto contentLengthHeader = std::stol(contentLength);
|
|
172
|
+
content.Headers().ContentLength(contentLengthHeader);
|
|
173
|
+
} catch (const std::invalid_argument &e) {
|
|
174
|
+
if (self->m_onError)
|
|
175
|
+
self->m_onError(reqArgs->RequestId, e.what() + string{" ["} + contentLength + "]", false);
|
|
176
|
+
|
|
177
|
+
co_return nullptr;
|
|
178
|
+
} catch (const std::out_of_range &e) {
|
|
179
|
+
if (self->m_onError)
|
|
180
|
+
self->m_onError(reqArgs->RequestId, e.what() + string{" ["} + contentLength + "]", false);
|
|
181
|
+
|
|
182
|
+
co_return nullptr;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
request.Content(content);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
co_return request;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
#pragma endregion IWinRTHttpRequestFactory
|
|
193
|
+
|
|
57
194
|
#pragma region IHttpResource
|
|
58
195
|
|
|
59
196
|
void WinRTHttpResource::SendRequest(
|
|
@@ -77,29 +214,28 @@ void WinRTHttpResource::SendRequest(
|
|
|
77
214
|
try {
|
|
78
215
|
HttpMethod httpMethod{to_hstring(std::move(method))};
|
|
79
216
|
Uri uri{to_hstring(std::move(url))};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
auto
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
PerformSendRequest(std::move(request), args);
|
|
217
|
+
|
|
218
|
+
auto iReqArgs = winrt::make<RequestArgs>();
|
|
219
|
+
auto reqArgs = iReqArgs.as<RequestArgs>();
|
|
220
|
+
reqArgs->RequestId = requestId;
|
|
221
|
+
reqArgs->Headers = std::move(headers);
|
|
222
|
+
reqArgs->Data = std::move(data);
|
|
223
|
+
reqArgs->IncrementalUpdates = useIncrementalUpdates;
|
|
224
|
+
reqArgs->WithCredentials = withCredentials;
|
|
225
|
+
reqArgs->ResponseType = std::move(responseType);
|
|
226
|
+
reqArgs->Timeout = timeout;
|
|
227
|
+
|
|
228
|
+
PerformSendRequest(std::move(httpMethod), std::move(uri), iReqArgs);
|
|
93
229
|
} catch (std::exception const &e) {
|
|
94
230
|
if (m_onError) {
|
|
95
|
-
m_onError(requestId, e.what());
|
|
231
|
+
m_onError(requestId, e.what(), false);
|
|
96
232
|
}
|
|
97
233
|
} catch (hresult_error const &e) {
|
|
98
234
|
if (m_onError) {
|
|
99
|
-
m_onError(requestId, Utilities::HResultToString(e));
|
|
235
|
+
m_onError(requestId, Utilities::HResultToString(e), false);
|
|
100
236
|
}
|
|
101
237
|
} catch (...) {
|
|
102
|
-
m_onError(requestId, "Unidentified error sending HTTP request");
|
|
238
|
+
m_onError(requestId, "Unidentified error sending HTTP request", false);
|
|
103
239
|
}
|
|
104
240
|
}
|
|
105
241
|
|
|
@@ -118,7 +254,7 @@ void WinRTHttpResource::AbortRequest(int64_t requestId) noexcept /*override*/ {
|
|
|
118
254
|
try {
|
|
119
255
|
request.Cancel();
|
|
120
256
|
} catch (hresult_error const &e) {
|
|
121
|
-
m_onError(requestId, Utilities::HResultToString(e));
|
|
257
|
+
m_onError(requestId, Utilities::HResultToString(e), false);
|
|
122
258
|
}
|
|
123
259
|
}
|
|
124
260
|
|
|
@@ -147,7 +283,8 @@ void WinRTHttpResource::SetOnData(function<void(int64_t requestId, dynamic &&res
|
|
|
147
283
|
m_onDataDynamic = std::move(handler);
|
|
148
284
|
}
|
|
149
285
|
|
|
150
|
-
void WinRTHttpResource::SetOnError(
|
|
286
|
+
void WinRTHttpResource::SetOnError(
|
|
287
|
+
function<void(int64_t requestId, string &&errorMessage, bool isTimeout)> &&handler) noexcept
|
|
151
288
|
/*override*/ {
|
|
152
289
|
m_onError = std::move(handler);
|
|
153
290
|
}
|
|
@@ -164,146 +301,88 @@ void WinRTHttpResource::UntrackResponse(int64_t requestId) noexcept {
|
|
|
164
301
|
m_responses.erase(requestId);
|
|
165
302
|
}
|
|
166
303
|
|
|
167
|
-
fire_and_forget
|
|
304
|
+
fire_and_forget
|
|
305
|
+
WinRTHttpResource::PerformSendRequest(HttpMethod &&method, Uri &&rtUri, IInspectable const &args) noexcept {
|
|
168
306
|
// Keep references after coroutine suspension.
|
|
169
307
|
auto self = shared_from_this();
|
|
170
|
-
auto coRequest = std::move(request);
|
|
171
308
|
auto coArgs = args;
|
|
172
|
-
auto
|
|
309
|
+
auto reqArgs = coArgs.as<RequestArgs>();
|
|
310
|
+
auto coMethod = std::move(method);
|
|
311
|
+
auto coUri = std::move(rtUri);
|
|
173
312
|
|
|
174
313
|
// Ensure background thread
|
|
175
314
|
co_await winrt::resume_background();
|
|
176
315
|
|
|
316
|
+
auto props = winrt::multi_threaded_map<winrt::hstring, IInspectable>();
|
|
317
|
+
props.Insert(L"RequestArgs", coArgs);
|
|
318
|
+
|
|
319
|
+
auto coRequest = co_await CreateRequest(std::move(coMethod), std::move(coUri), props);
|
|
320
|
+
if (!coRequest) {
|
|
321
|
+
co_return;
|
|
322
|
+
}
|
|
323
|
+
|
|
177
324
|
// If URI handler is available, it takes over request processing.
|
|
178
325
|
if (auto uriHandler = self->m_uriHandler.lock()) {
|
|
179
326
|
auto uri = winrt::to_string(coRequest.RequestUri().ToString());
|
|
180
327
|
try {
|
|
181
|
-
if (uriHandler->Supports(uri,
|
|
328
|
+
if (uriHandler->Supports(uri, reqArgs->ResponseType)) {
|
|
182
329
|
auto blob = uriHandler->Fetch(uri);
|
|
183
330
|
if (self->m_onDataDynamic && self->m_onRequestSuccess) {
|
|
184
|
-
self->m_onDataDynamic(
|
|
185
|
-
self->m_onRequestSuccess(
|
|
331
|
+
self->m_onDataDynamic(reqArgs->RequestId, std::move(blob));
|
|
332
|
+
self->m_onRequestSuccess(reqArgs->RequestId);
|
|
186
333
|
}
|
|
187
334
|
|
|
188
335
|
co_return;
|
|
189
336
|
}
|
|
190
337
|
} catch (const hresult_error &e) {
|
|
191
338
|
if (self->m_onError)
|
|
192
|
-
co_return self->m_onError(
|
|
339
|
+
co_return self->m_onError(reqArgs->RequestId, Utilities::HResultToString(e), false);
|
|
193
340
|
} catch (const std::exception &e) {
|
|
194
341
|
if (self->m_onError)
|
|
195
|
-
co_return self->m_onError(
|
|
342
|
+
co_return self->m_onError(reqArgs->RequestId, e.what(), false);
|
|
196
343
|
}
|
|
197
344
|
}
|
|
198
345
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
346
|
+
try {
|
|
347
|
+
auto sendRequestOp = self->m_client.SendRequestAsync(coRequest);
|
|
348
|
+
self->TrackResponse(reqArgs->RequestId, sendRequestOp);
|
|
202
349
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
}
|
|
350
|
+
if (reqArgs->Timeout > 0) {
|
|
351
|
+
// See https://devblogs.microsoft.com/oldnewthing/20220415-00/?p=106486
|
|
352
|
+
auto timedOut = std::make_shared<bool>(false);
|
|
353
|
+
auto sendRequestTimeout = [](auto timedOut, auto milliseconds) -> ResponseOperation {
|
|
354
|
+
// Convert milliseconds to "ticks" (10^-7 seconds)
|
|
355
|
+
co_await winrt::resume_after(winrt::Windows::Foundation::TimeSpan{milliseconds * 10000});
|
|
356
|
+
*timedOut = true;
|
|
357
|
+
co_return nullptr;
|
|
358
|
+
}(timedOut, reqArgs->Timeout);
|
|
231
359
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
blob = bodyHandler->ToRequestBody(data, contentTypeString);
|
|
241
|
-
} catch (const std::invalid_argument &e) {
|
|
360
|
+
co_await lessthrow_await_adapter<ResponseOperation>{winrt::when_any(sendRequestOp, sendRequestTimeout)};
|
|
361
|
+
|
|
362
|
+
// Cancel either still unfinished coroutine.
|
|
363
|
+
sendRequestTimeout.Cancel();
|
|
364
|
+
sendRequestOp.Cancel();
|
|
365
|
+
|
|
366
|
+
if (*timedOut) {
|
|
242
367
|
if (self->m_onError) {
|
|
243
|
-
|
|
368
|
+
// TODO: Try to replace with either:
|
|
369
|
+
// WININET_E_TIMEOUT
|
|
370
|
+
// ERROR_INTERNET_TIMEOUT
|
|
371
|
+
// INET_E_CONNECTION_TIMEOUT
|
|
372
|
+
self->m_onError(reqArgs->RequestId, Utilities::HResultToString(HRESULT_FROM_WIN32(ERROR_TIMEOUT)), true);
|
|
244
373
|
}
|
|
245
|
-
co_return;
|
|
374
|
+
co_return self->UntrackResponse(reqArgs->RequestId);
|
|
246
375
|
}
|
|
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
376
|
} else {
|
|
268
|
-
|
|
269
|
-
// content = HttpStringContent{L""};
|
|
377
|
+
co_await lessthrow_await_adapter<ResponseOperation>{sendRequestOp};
|
|
270
378
|
}
|
|
271
|
-
}
|
|
272
379
|
|
|
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
380
|
auto result = sendRequestOp.ErrorCode();
|
|
302
381
|
if (result < 0) {
|
|
303
382
|
if (self->m_onError) {
|
|
304
|
-
self->m_onError(
|
|
383
|
+
self->m_onError(reqArgs->RequestId, Utilities::HResultToString(std::move(result)), false);
|
|
305
384
|
}
|
|
306
|
-
co_return self->UntrackResponse(
|
|
385
|
+
co_return self->UntrackResponse(reqArgs->RequestId);
|
|
307
386
|
}
|
|
308
387
|
|
|
309
388
|
auto response = sendRequestOp.GetResults();
|
|
@@ -322,7 +401,7 @@ fire_and_forget WinRTHttpResource::PerformSendRequest(HttpRequestMessage &&reque
|
|
|
322
401
|
}
|
|
323
402
|
|
|
324
403
|
self->m_onResponse(
|
|
325
|
-
|
|
404
|
+
reqArgs->RequestId,
|
|
326
405
|
{static_cast<int32_t>(response.StatusCode()), std::move(url), std::move(responseHeaders)});
|
|
327
406
|
}
|
|
328
407
|
}
|
|
@@ -337,21 +416,21 @@ fire_and_forget WinRTHttpResource::PerformSendRequest(HttpRequestMessage &&reque
|
|
|
337
416
|
|
|
338
417
|
// Let response handler take over, if set
|
|
339
418
|
if (auto responseHandler = self->m_responseHandler.lock()) {
|
|
340
|
-
if (responseHandler->Supports(
|
|
419
|
+
if (responseHandler->Supports(reqArgs->ResponseType)) {
|
|
341
420
|
auto bytes = vector<uint8_t>(reader.UnconsumedBufferLength());
|
|
342
421
|
reader.ReadBytes(bytes);
|
|
343
422
|
auto blob = responseHandler->ToResponseData(std::move(bytes));
|
|
344
423
|
|
|
345
424
|
if (self->m_onDataDynamic && self->m_onRequestSuccess) {
|
|
346
|
-
self->m_onDataDynamic(
|
|
347
|
-
self->m_onRequestSuccess(
|
|
425
|
+
self->m_onDataDynamic(reqArgs->RequestId, std::move(blob));
|
|
426
|
+
self->m_onRequestSuccess(reqArgs->RequestId);
|
|
348
427
|
}
|
|
349
428
|
|
|
350
429
|
co_return;
|
|
351
430
|
}
|
|
352
431
|
}
|
|
353
432
|
|
|
354
|
-
auto isText =
|
|
433
|
+
auto isText = reqArgs->ResponseType == "text";
|
|
355
434
|
if (isText) {
|
|
356
435
|
reader.UnicodeEncoding(UnicodeEncoding::Utf8);
|
|
357
436
|
}
|
|
@@ -374,33 +453,33 @@ fire_and_forget WinRTHttpResource::PerformSendRequest(HttpRequestMessage &&reque
|
|
|
374
453
|
buffer = reader.ReadBuffer(length);
|
|
375
454
|
auto data = CryptographicBuffer::EncodeToBase64String(buffer);
|
|
376
455
|
|
|
377
|
-
responseData += to_string(std::wstring_view(data));
|
|
456
|
+
responseData += winrt::to_string(std::wstring_view(data));
|
|
378
457
|
}
|
|
379
458
|
} while (length > 0);
|
|
380
459
|
|
|
381
460
|
if (self->m_onData) {
|
|
382
|
-
self->m_onData(
|
|
461
|
+
self->m_onData(reqArgs->RequestId, std::move(responseData));
|
|
383
462
|
}
|
|
384
463
|
} else {
|
|
385
464
|
if (self->m_onError) {
|
|
386
|
-
self->m_onError(
|
|
465
|
+
self->m_onError(reqArgs->RequestId, response == nullptr ? "request failed" : "No response content", false);
|
|
387
466
|
}
|
|
388
467
|
}
|
|
389
468
|
} catch (std::exception const &e) {
|
|
390
469
|
if (self->m_onError) {
|
|
391
|
-
self->m_onError(
|
|
470
|
+
self->m_onError(reqArgs->RequestId, e.what(), false);
|
|
392
471
|
}
|
|
393
472
|
} catch (hresult_error const &e) {
|
|
394
473
|
if (self->m_onError) {
|
|
395
|
-
self->m_onError(
|
|
474
|
+
self->m_onError(reqArgs->RequestId, Utilities::HResultToString(e), false);
|
|
396
475
|
}
|
|
397
476
|
} catch (...) {
|
|
398
477
|
if (self->m_onError) {
|
|
399
|
-
self->m_onError(
|
|
478
|
+
self->m_onError(reqArgs->RequestId, "Unhandled exception during request", false);
|
|
400
479
|
}
|
|
401
480
|
}
|
|
402
481
|
|
|
403
|
-
self->UntrackResponse(
|
|
482
|
+
self->UntrackResponse(reqArgs->RequestId);
|
|
404
483
|
} // PerformSendRequest
|
|
405
484
|
|
|
406
485
|
#pragma region IHttpModuleProxy
|
|
@@ -431,19 +510,25 @@ void WinRTHttpResource::AddResponseHandler(shared_ptr<IResponseHandler> response
|
|
|
431
510
|
using namespace winrt::Microsoft::ReactNative;
|
|
432
511
|
using winrt::Windows::Web::Http::HttpClient;
|
|
433
512
|
|
|
434
|
-
|
|
513
|
+
auto redirFilter = winrt::make<RedirectHttpFilter>();
|
|
514
|
+
HttpClient client;
|
|
435
515
|
|
|
436
516
|
if (static_cast<OriginPolicy>(GetRuntimeOptionInt("Http.OriginPolicy")) == OriginPolicy::None) {
|
|
437
|
-
|
|
517
|
+
client = HttpClient{redirFilter};
|
|
438
518
|
} else {
|
|
439
519
|
auto globalOrigin = GetRuntimeOptionString("Http.GlobalOrigin");
|
|
440
520
|
OriginPolicyHttpFilter::SetStaticOrigin(std::move(globalOrigin));
|
|
441
|
-
auto opFilter = winrt::make<OriginPolicyHttpFilter>();
|
|
442
|
-
|
|
521
|
+
auto opFilter = winrt::make<OriginPolicyHttpFilter>(redirFilter);
|
|
522
|
+
redirFilter.as<RedirectHttpFilter>()->SetRedirectSource(opFilter.as<IRedirectEventSource>());
|
|
443
523
|
|
|
444
|
-
|
|
524
|
+
client = HttpClient{opFilter};
|
|
445
525
|
}
|
|
446
526
|
|
|
527
|
+
auto result = std::make_shared<WinRTHttpResource>(std::move(client));
|
|
528
|
+
|
|
529
|
+
// Allow redirect filter to create requests based on the resource's state
|
|
530
|
+
redirFilter.as<RedirectHttpFilter>()->SetRequestFactory(weak_ptr<IWinRTHttpRequestFactory>{result});
|
|
531
|
+
|
|
447
532
|
// Register resource as HTTP module proxy.
|
|
448
533
|
if (inspectableProperties) {
|
|
449
534
|
auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IHttpModuleProxy>>>{L"HttpModule.Proxy"};
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#include "IHttpResource.h"
|
|
7
7
|
|
|
8
8
|
#include <Modules/IHttpModuleProxy.h>
|
|
9
|
+
#include "IWinRTHttpRequestFactory.h"
|
|
9
10
|
#include "WinRTTypes.h"
|
|
10
11
|
|
|
11
12
|
// Windows API
|
|
@@ -18,6 +19,7 @@ namespace Microsoft::React::Networking {
|
|
|
18
19
|
|
|
19
20
|
class WinRTHttpResource : public IHttpResource,
|
|
20
21
|
public IHttpModuleProxy,
|
|
22
|
+
public IWinRTHttpRequestFactory,
|
|
21
23
|
public std::enable_shared_from_this<WinRTHttpResource> {
|
|
22
24
|
winrt::Windows::Web::Http::IHttpClient m_client;
|
|
23
25
|
std::mutex m_mutex;
|
|
@@ -27,7 +29,7 @@ class WinRTHttpResource : public IHttpResource,
|
|
|
27
29
|
std::function<void(int64_t requestId, Response &&response)> m_onResponse;
|
|
28
30
|
std::function<void(int64_t requestId, std::string &&responseData)> m_onData;
|
|
29
31
|
std::function<void(int64_t requestId, folly::dynamic &&responseData)> m_onDataDynamic;
|
|
30
|
-
std::function<void(int64_t requestId, std::string &&errorMessage
|
|
32
|
+
std::function<void(int64_t requestId, std::string &&errorMessage, bool isTimeout)> m_onError;
|
|
31
33
|
|
|
32
34
|
// Used for IHttpModuleProxy
|
|
33
35
|
std::weak_ptr<IUriHandler> m_uriHandler;
|
|
@@ -39,7 +41,8 @@ class WinRTHttpResource : public IHttpResource,
|
|
|
39
41
|
void UntrackResponse(int64_t requestId) noexcept;
|
|
40
42
|
|
|
41
43
|
winrt::fire_and_forget PerformSendRequest(
|
|
42
|
-
winrt::Windows::Web::Http::
|
|
44
|
+
winrt::Windows::Web::Http::HttpMethod &&method,
|
|
45
|
+
winrt::Windows::Foundation::Uri &&uri,
|
|
43
46
|
winrt::Windows::Foundation::IInspectable const &args) noexcept;
|
|
44
47
|
|
|
45
48
|
public:
|
|
@@ -47,6 +50,16 @@ class WinRTHttpResource : public IHttpResource,
|
|
|
47
50
|
|
|
48
51
|
WinRTHttpResource(winrt::Windows::Web::Http::IHttpClient &&client) noexcept;
|
|
49
52
|
|
|
53
|
+
#pragma region IWinRTHttpRequestFactory
|
|
54
|
+
|
|
55
|
+
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Web::Http::HttpRequestMessage> CreateRequest(
|
|
56
|
+
winrt::Windows::Web::Http::HttpMethod &&method,
|
|
57
|
+
winrt::Windows::Foundation::Uri &&uri,
|
|
58
|
+
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Windows::Foundation::IInspectable>
|
|
59
|
+
props) noexcept override;
|
|
60
|
+
|
|
61
|
+
#pragma endregion IWinRTHttpRequestFactory
|
|
62
|
+
|
|
50
63
|
#pragma region IHttpResource
|
|
51
64
|
|
|
52
65
|
void SendRequest(
|
|
@@ -67,8 +80,8 @@ class WinRTHttpResource : public IHttpResource,
|
|
|
67
80
|
void SetOnResponse(std::function<void(int64_t requestId, Response &&response)> &&handler) noexcept override;
|
|
68
81
|
void SetOnData(std::function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept override;
|
|
69
82
|
void SetOnData(std::function<void(int64_t requestId, folly::dynamic &&responseData)> &&handler) noexcept override;
|
|
70
|
-
void SetOnError(
|
|
71
|
-
|
|
83
|
+
void SetOnError(
|
|
84
|
+
std::function<void(int64_t requestId, std::string &&errorMessage, bool isTimeout)> &&handler) noexcept override;
|
|
72
85
|
|
|
73
86
|
#pragma endregion IHttpResource
|
|
74
87
|
|
package/Shared/OInstance.cpp
CHANGED
|
@@ -557,6 +557,7 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
|
|
|
557
557
|
std::vector<std::unique_ptr<NativeModule>> modules;
|
|
558
558
|
auto transitionalProps{ReactPropertyBagHelper::CreatePropertyBag()};
|
|
559
559
|
|
|
560
|
+
#if (defined(_MSC_VER) && !defined(WINRT))
|
|
560
561
|
modules.push_back(std::make_unique<CxxNativeModule>(
|
|
561
562
|
m_innerInstance,
|
|
562
563
|
Microsoft::React::GetHttpModuleName(),
|
|
@@ -564,6 +565,7 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
|
|
|
564
565
|
return Microsoft::React::CreateHttpModule(transitionalProps);
|
|
565
566
|
},
|
|
566
567
|
nativeQueue));
|
|
568
|
+
#endif
|
|
567
569
|
|
|
568
570
|
modules.push_back(std::make_unique<CxxNativeModule>(
|
|
569
571
|
m_innerInstance,
|
|
@@ -631,8 +633,13 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
|
|
|
631
633
|
[]() { return std::make_unique<StatusBarManagerModule>(); },
|
|
632
634
|
nativeQueue));
|
|
633
635
|
|
|
634
|
-
//
|
|
635
|
-
|
|
636
|
+
// These modules are instantiated separately in MSRN (Universal Windows).
|
|
637
|
+
// When there are module name colisions, the last one registered is used.
|
|
638
|
+
// If this code is enabled, we will have unused module instances.
|
|
639
|
+
// Also, MSRN has a different property bag mechanism incompatible with this method's transitionalProps variable.
|
|
640
|
+
#if (defined(_MSC_VER) && !defined(WINRT))
|
|
641
|
+
if (Microsoft::React::GetRuntimeOptionBool("Blob.EnableModule") &&
|
|
642
|
+
!Microsoft::React::GetRuntimeOptionBool("Http.UseMonolithicModule")) {
|
|
636
643
|
modules.push_back(std::make_unique<CxxNativeModule>(
|
|
637
644
|
m_innerInstance,
|
|
638
645
|
Microsoft::React::GetBlobModuleName(),
|
|
@@ -645,6 +652,7 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
|
|
|
645
652
|
[transitionalProps]() { return Microsoft::React::CreateFileReaderModule(transitionalProps); },
|
|
646
653
|
nativeQueue));
|
|
647
654
|
}
|
|
655
|
+
#endif
|
|
648
656
|
|
|
649
657
|
return modules;
|
|
650
658
|
}
|
package/Shared/Shared.vcxitems
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
<ClCompile Include="$(MSBuildThisFileDirectory)Modules\StatusBarManagerModule.cpp" />
|
|
57
57
|
<ClCompile Include="$(MSBuildThisFileDirectory)Modules\WebSocketModule.cpp" />
|
|
58
58
|
<ClCompile Include="$(MSBuildThisFileDirectory)Networking\OriginPolicyHttpFilter.cpp" />
|
|
59
|
+
<ClCompile Include="$(MSBuildThisFileDirectory)Networking\RedirectHttpFilter.cpp" />
|
|
59
60
|
<ClCompile Include="$(MSBuildThisFileDirectory)Networking\WinRTHttpResource.cpp" />
|
|
60
61
|
<ClCompile Include="$(MSBuildThisFileDirectory)Networking\WinRTWebSocketResource.cpp" />
|
|
61
62
|
<ClCompile Include="$(MSBuildThisFileDirectory)OInstance.cpp" />
|
|
@@ -103,9 +104,12 @@
|
|
|
103
104
|
<ClInclude Include="$(MSBuildThisFileDirectory)Modules\HttpModule.h" />
|
|
104
105
|
<ClInclude Include="$(MSBuildThisFileDirectory)Modules\NetworkingModule.h" />
|
|
105
106
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\IHttpResource.h" />
|
|
107
|
+
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\IRedirectEventSource.h" />
|
|
106
108
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\IWebSocketResource.h" />
|
|
109
|
+
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\IWinRTHttpRequestFactory.h" />
|
|
107
110
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\OriginPolicy.h" />
|
|
108
111
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\OriginPolicyHttpFilter.h" />
|
|
112
|
+
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\RedirectHttpFilter.h" />
|
|
109
113
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\WinRTHttpResource.h" />
|
|
110
114
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\WinRTTypes.h" />
|
|
111
115
|
<ClInclude Include="$(MSBuildThisFileDirectory)Networking\WinRTWebSocketResource.h" />
|