react-native-windows 0.67.6 → 0.67.9

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.
@@ -0,0 +1,317 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "WinRTHttpResource.h"
5
+
6
+ #include <Utils/CppWinrtLessExceptions.h>
7
+ #include <Utils/WinRTConversions.h>
8
+ #include <utilities.h>
9
+
10
+ // Windows API
11
+ #include <winrt/Windows.Security.Cryptography.h>
12
+ #include <winrt/Windows.Storage.Streams.h>
13
+ #include <winrt/Windows.Web.Http.Headers.h>
14
+
15
+ using std::function;
16
+ using std::scoped_lock;
17
+ using std::shared_ptr;
18
+ using std::string;
19
+
20
+ using winrt::fire_and_forget;
21
+ using winrt::hresult_error;
22
+ using winrt::to_hstring;
23
+ using winrt::to_string;
24
+ using winrt::Windows::Foundation::Uri;
25
+ using winrt::Windows::Security::Cryptography::CryptographicBuffer;
26
+ using winrt::Windows::Storage::StorageFile;
27
+ using winrt::Windows::Storage::Streams::DataReader;
28
+ using winrt::Windows::Storage::Streams::UnicodeEncoding;
29
+ using winrt::Windows::Web::Http::HttpBufferContent;
30
+ using winrt::Windows::Web::Http::HttpMethod;
31
+ using winrt::Windows::Web::Http::HttpRequestMessage;
32
+ using winrt::Windows::Web::Http::HttpStreamContent;
33
+ using winrt::Windows::Web::Http::HttpStringContent;
34
+ using winrt::Windows::Web::Http::IHttpClient;
35
+ using winrt::Windows::Web::Http::IHttpContent;
36
+ using winrt::Windows::Web::Http::Headers::HttpMediaTypeHeaderValue;
37
+
38
+ namespace Microsoft::React {
39
+
40
+ #pragma region WinRTHttpResource
41
+
42
+ // TODO: Check for multi-thread issues if there are multiple instances.
43
+ /*static*/ int64_t WinRTHttpResource::s_lastRequestId = 0;
44
+
45
+ WinRTHttpResource::WinRTHttpResource(IHttpClient &&client) noexcept : m_client{std::move(client)} {}
46
+
47
+ WinRTHttpResource::WinRTHttpResource() noexcept : WinRTHttpResource(winrt::Windows::Web::Http::HttpClient()) {}
48
+
49
+ #pragma region IHttpResource
50
+
51
+ void WinRTHttpResource::SendRequest(
52
+ string &&method,
53
+ string &&url,
54
+ Headers &&headers,
55
+ BodyData &&bodyData,
56
+ string &&responseType,
57
+ bool useIncrementalUpdates,
58
+ int64_t timeout,
59
+ bool withCredentials,
60
+ std::function<void(int64_t)> &&callback) noexcept /*override*/ {
61
+ auto requestId = ++s_lastRequestId;
62
+
63
+ // Enforce supported args
64
+ assert(responseType == "text" || responseType == "base64");
65
+
66
+ if (callback) {
67
+ callback(requestId);
68
+ }
69
+
70
+ try {
71
+ HttpMethod httpMethod{to_hstring(std::move(method))};
72
+ Uri uri{to_hstring(std::move(url))};
73
+ HttpRequestMessage request{httpMethod, uri};
74
+ HttpMediaTypeHeaderValue contentType{nullptr};
75
+ string contentEncoding;
76
+ string contentLength;
77
+
78
+ // Headers are generally case-insensitive
79
+ // https://www.ietf.org/rfc/rfc2616.txt section 4.2
80
+ for (auto &header : headers) {
81
+ if (_stricmp(header.first.c_str(), "content-type") == 0) {
82
+ bool success = HttpMediaTypeHeaderValue::TryParse(to_hstring(header.second), contentType);
83
+ if (!success && m_onError) {
84
+ return m_onError(requestId, "Failed to parse Content-Type");
85
+ }
86
+ } else if (_stricmp(header.first.c_str(), "content-encoding") == 0) {
87
+ contentEncoding = header.second;
88
+ } else if (_stricmp(header.first.c_str(), "content-length") == 0) {
89
+ contentLength = header.second;
90
+ } else if (_stricmp(header.first.c_str(), "authorization") == 0) {
91
+ bool success =
92
+ request.Headers().TryAppendWithoutValidation(to_hstring(header.first), to_hstring(header.second));
93
+ if (!success && m_onError) {
94
+ return m_onError(requestId, "Failed to append Authorization");
95
+ }
96
+ } else {
97
+ request.Headers().Append(to_hstring(header.first), to_hstring(header.second));
98
+ }
99
+ }
100
+
101
+ IHttpContent content{nullptr};
102
+ if (BodyData::Type::String == bodyData.Type) {
103
+ content = HttpStringContent{to_hstring(bodyData.Data)};
104
+ } else if (BodyData::Type::Base64 == bodyData.Type) {
105
+ auto buffer = CryptographicBuffer::DecodeFromBase64String(to_hstring(bodyData.Data));
106
+ content = HttpBufferContent{buffer};
107
+ } else if (BodyData::Type::Uri == bodyData.Type) {
108
+ auto file = StorageFile::GetFileFromApplicationUriAsync(Uri{to_hstring(bodyData.Data)}).get();
109
+ auto stream = file.OpenReadAsync().get();
110
+ content = HttpStreamContent{stream};
111
+ } else if (BodyData::Type::Form == bodyData.Type) {
112
+ // TODO: Add support
113
+ } else {
114
+ // BodyData::Type::Empty
115
+ // TODO: Error 'cause unsupported??
116
+ }
117
+
118
+ if (content != nullptr) {
119
+ // Attach content headers
120
+ if (contentType) {
121
+ content.Headers().ContentType(contentType);
122
+ }
123
+ if (!contentEncoding.empty()) {
124
+ if (!content.Headers().ContentEncoding().TryParseAdd(to_hstring(contentEncoding))) {
125
+ if (m_onError) {
126
+ m_onError(requestId, "Failed to parse Content-Encoding");
127
+ }
128
+ return;
129
+ }
130
+ }
131
+ if (!contentLength.empty()) {
132
+ const auto contentLengthHeader = _atoi64(contentLength.c_str()); // TODO: Alternatives to _atoi64?
133
+ content.Headers().ContentLength(contentLengthHeader);
134
+ }
135
+
136
+ request.Content(content);
137
+ }
138
+
139
+ PerformSendRequest(requestId, std::move(request), responseType == "text");
140
+ } catch (std::exception const &e) {
141
+ if (m_onError) {
142
+ m_onError(requestId, e.what());
143
+ }
144
+ } catch (hresult_error const &e) {
145
+ if (m_onError) {
146
+ m_onError(requestId, Utilities::HResultToString(e));
147
+ }
148
+ } catch (...) {
149
+ m_onError(requestId, "Unidentified error sending HTTP request");
150
+ }
151
+ }
152
+
153
+ void WinRTHttpResource::AbortRequest(int64_t requestId) noexcept /*override*/ {
154
+ ResponseType request{nullptr};
155
+
156
+ {
157
+ scoped_lock lock{m_mutex};
158
+ auto iter = m_responses.find(requestId);
159
+ if (iter == std::end(m_responses)) {
160
+ return;
161
+ }
162
+ request = iter->second;
163
+ }
164
+
165
+ try {
166
+ request.Cancel();
167
+ } catch (hresult_error const &e) {
168
+ m_onError(requestId, Utilities::HResultToString(e));
169
+ }
170
+ }
171
+
172
+ void WinRTHttpResource::ClearCookies() noexcept /*override*/ {
173
+ assert(false);
174
+ // NOT IMPLEMENTED
175
+ }
176
+
177
+ void WinRTHttpResource::SetOnRequest(function<void(int64_t requestId)> &&handler) noexcept /*override*/ {
178
+ m_onRequest = std::move(handler);
179
+ }
180
+
181
+ void WinRTHttpResource::SetOnResponse(function<void(int64_t requestId, Response &&response)> &&handler) noexcept
182
+ /*override*/ {
183
+ m_onResponse = std::move(handler);
184
+ }
185
+
186
+ void WinRTHttpResource::SetOnData(function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept
187
+ /*override*/ {
188
+ m_onData = std::move(handler);
189
+ }
190
+
191
+ void WinRTHttpResource::SetOnError(function<void(int64_t requestId, string &&errorMessage)> &&handler) noexcept
192
+ /*override*/ {
193
+ m_onError = std::move(handler);
194
+ }
195
+
196
+ #pragma endregion IHttpResource
197
+
198
+ void WinRTHttpResource::TrackResponse(int64_t requestId, ResponseType response) noexcept {
199
+ scoped_lock lock{m_mutex};
200
+ m_responses[requestId] = response;
201
+ }
202
+
203
+ void WinRTHttpResource::UntrackResponse(int64_t requestId) noexcept {
204
+ scoped_lock lock{m_mutex};
205
+ m_responses.erase(requestId);
206
+ }
207
+
208
+ fire_and_forget
209
+ WinRTHttpResource::PerformSendRequest(int64_t requestId, HttpRequestMessage &&request, bool textResponse) noexcept {
210
+ // Keep references after coroutine suspension.
211
+ auto self = shared_from_this();
212
+ auto coRequest = std::move(request);
213
+
214
+ // Ensure background thread
215
+ co_await winrt::resume_background();
216
+
217
+ try {
218
+ auto sendRequestOp = self->m_client.SendRequestAsync(coRequest);
219
+
220
+ self->TrackResponse(requestId, sendRequestOp);
221
+
222
+ co_await lessthrow_await_adapter<ResponseType>{sendRequestOp};
223
+ auto result = sendRequestOp.ErrorCode();
224
+ if (result < 0) {
225
+ if (self->m_onError) {
226
+ self->m_onError(requestId, Utilities::HResultToString(std::move(result)));
227
+ }
228
+ self->UntrackResponse(requestId);
229
+ co_return;
230
+ }
231
+
232
+ auto response = sendRequestOp.GetResults();
233
+ if (response) {
234
+ if (self->m_onResponse) {
235
+ Headers headers;
236
+
237
+ // Gather headers for both the response content and the response itself
238
+ // See Invoke-WebRequest PowerShell cmdlet or Chromium response handling
239
+ for (auto header : response.Headers()) {
240
+ headers.emplace(to_string(header.Key()), to_string(header.Value()));
241
+ }
242
+ for (auto header : response.Content().Headers()) {
243
+ headers.emplace(to_string(header.Key()), to_string(header.Value()));
244
+ }
245
+ string url = to_string(response.RequestMessage().RequestUri().AbsoluteUri());
246
+ self->m_onResponse(
247
+ requestId, {static_cast<int32_t>(response.StatusCode()), std::move(headers), std::move(url)});
248
+ }
249
+ }
250
+
251
+ // TODO: Incremental updates?
252
+ if (response && response.Content()) {
253
+ auto inputStream = co_await response.Content().ReadAsInputStreamAsync();
254
+ auto reader = DataReader{inputStream};
255
+
256
+ if (textResponse) {
257
+ reader.UnicodeEncoding(UnicodeEncoding::Utf8);
258
+ }
259
+
260
+ // Only support response sizes up to 10MB.
261
+ // TODO: WHY????
262
+ co_await reader.LoadAsync(10 * 1024 * 1024);
263
+ auto length = reader.UnconsumedBufferLength();
264
+
265
+ if (textResponse) {
266
+ std::vector<uint8_t> data(length);
267
+ reader.ReadBytes(data);
268
+ string responseData = string(Common::Utilities::CheckedReinterpretCast<char *>(data.data()), data.size());
269
+
270
+ if (self->m_onData) {
271
+ self->m_onData(requestId, std::move(responseData));
272
+ }
273
+ } else {
274
+ auto buffer = reader.ReadBuffer(length);
275
+ auto data = CryptographicBuffer::EncodeToBase64String(buffer);
276
+ auto responseData = to_string(std::wstring_view(data));
277
+
278
+ if (self->m_onData) {
279
+ self->m_onData(requestId, std::move(responseData));
280
+ }
281
+ }
282
+ } else {
283
+ if (self->m_onError) {
284
+ self->m_onError(requestId, response == nullptr ? "request failed" : "No response content");
285
+ }
286
+ }
287
+ } catch (std::exception const &e) {
288
+ if (self->m_onError) {
289
+ self->m_onError(requestId, e.what());
290
+ }
291
+ } catch (hresult_error const &e) {
292
+ if (self->m_onError) {
293
+ self->m_onError(requestId, Utilities::HResultToString(e));
294
+ }
295
+ } catch (...) {
296
+ if (self->m_onError) {
297
+ self->m_onError(requestId, "Unhandled exception during request");
298
+ }
299
+ }
300
+
301
+ self->UntrackResponse(requestId);
302
+
303
+ // TODO: keep? See https://devblogs.microsoft.com/oldnewthing/?p=106160
304
+ co_return;
305
+ }
306
+
307
+ #pragma endregion WinRTHttpResource
308
+
309
+ #pragma region IHttpResource
310
+
311
+ /*static*/ shared_ptr<IHttpResource> IHttpResource::Make() noexcept {
312
+ return std::make_shared<WinRTHttpResource>();
313
+ }
314
+
315
+ #pragma endregion IHttpResource
316
+
317
+ } // namespace Microsoft::React
@@ -0,0 +1,71 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include <IHttpResource.h>
7
+
8
+ // Windows API
9
+ #include <winrt/Windows.Web.Http.h>
10
+
11
+ // Standard Library
12
+ #include <mutex>
13
+
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;
23
+
24
+ winrt::Windows::Web::Http::IHttpClient m_client;
25
+ std::mutex m_mutex;
26
+ std::unordered_map<int64_t, ResponseType> m_responses;
27
+
28
+ std::function<void(int64_t requestId)> m_onRequest;
29
+ std::function<void(int64_t requestId, Response &&response)> m_onResponse;
30
+ std::function<void(int64_t requestId, std::string &&responseData)> m_onData;
31
+ std::function<void(int64_t requestId, std::string &&errorMessage /*, bool isTimeout*/)> m_onError;
32
+
33
+ void TrackResponse(int64_t requestId, ResponseType response) noexcept;
34
+
35
+ void UntrackResponse(int64_t requestId) noexcept;
36
+
37
+ winrt::fire_and_forget PerformSendRequest(
38
+ int64_t requestId,
39
+ winrt::Windows::Web::Http::HttpRequestMessage &&request,
40
+ bool textResponse) noexcept;
41
+
42
+ public:
43
+ WinRTHttpResource() noexcept;
44
+
45
+ WinRTHttpResource(winrt::Windows::Web::Http::IHttpClient &&client) noexcept;
46
+
47
+ #pragma region IHttpResource
48
+
49
+ void SendRequest(
50
+ std::string &&method,
51
+ std::string &&url,
52
+ Headers &&headers,
53
+ BodyData &&bodyData,
54
+ std::string &&responseType,
55
+ bool useIncrementalUpdates,
56
+ int64_t timeout,
57
+ bool withCredentials,
58
+ std::function<void(int64_t)> &&callback) noexcept override;
59
+ void AbortRequest(int64_t requestId) noexcept override;
60
+ void ClearCookies() noexcept override;
61
+
62
+ #pragma endregion IHttpResource
63
+
64
+ void SetOnRequest(std::function<void(int64_t requestId)> &&handler) noexcept override;
65
+ void SetOnResponse(std::function<void(int64_t requestId, Response &&response)> &&handler) noexcept override;
66
+ void SetOnData(std::function<void(int64_t requestId, std::string &&responseData)> &&handler) noexcept override;
67
+ void SetOnError(std::function<void(int64_t requestId, std::string &&errorMessage /*, bool isTimeout*/)>
68
+ &&handler) noexcept override;
69
+ };
70
+
71
+ } // namespace Microsoft::React
@@ -5,6 +5,10 @@
5
5
 
6
6
  #include <Utilities.h>
7
7
  #include <Utils/CppWinrtLessExceptions.h>
8
+ #include <Utils/WinRTConversions.h>
9
+
10
+ // MSO
11
+ #include <dispatchQueue/dispatchQueue.h>
8
12
 
9
13
  // Windows API
10
14
  #include <winrt/Windows.Foundation.Collections.h>
@@ -44,6 +48,7 @@ using winrt::Windows::Storage::Streams::IDataWriter;
44
48
  using winrt::Windows::Storage::Streams::UnicodeEncoding;
45
49
 
46
50
  namespace {
51
+
47
52
  ///
48
53
  /// Implements an awaiter for Mso::DispatchQueue
49
54
  ///
@@ -72,17 +77,6 @@ auto resume_in_queue(const Mso::DispatchQueue &queue) noexcept {
72
77
  return awaitable{queue};
73
78
  } // resume_in_queue
74
79
 
75
- string HResultToString(hresult_error const &e) {
76
- std::stringstream stream;
77
- stream << "[0x" << std::hex << e.code() << "] " << winrt::to_string(e.message());
78
-
79
- return stream.str();
80
- }
81
-
82
- string HResultToString(hresult &&result) {
83
- return HResultToString(hresult_error(std::move(result), hresult_error::from_abi));
84
- }
85
-
86
80
  } // namespace
87
81
 
88
82
  namespace Microsoft::React {
@@ -134,12 +128,12 @@ IAsyncAction WinRTWebSocketResource::PerformConnect(Uri &&uri) noexcept {
134
128
  }
135
129
  } else {
136
130
  if (self->m_errorHandler) {
137
- self->m_errorHandler({HResultToString(std::move(result)), ErrorType::Connection});
131
+ self->m_errorHandler({Utilities::HResultToString(std::move(result)), ErrorType::Connection});
138
132
  }
139
133
  }
140
134
  } catch (hresult_error const &e) {
141
135
  if (self->m_errorHandler) {
142
- self->m_errorHandler({HResultToString(e), ErrorType::Connection});
136
+ self->m_errorHandler({Utilities::HResultToString(e), ErrorType::Connection});
143
137
  }
144
138
  }
145
139
 
@@ -180,12 +174,12 @@ fire_and_forget WinRTWebSocketResource::PerformPing() noexcept {
180
174
  }
181
175
  } else {
182
176
  if (self->m_errorHandler) {
183
- self->m_errorHandler({HResultToString(std::move(result)), ErrorType::Ping});
177
+ self->m_errorHandler({Utilities::HResultToString(std::move(result)), ErrorType::Ping});
184
178
  }
185
179
  }
186
180
  } catch (hresult_error const &e) {
187
181
  if (self->m_errorHandler) {
188
- self->m_errorHandler({HResultToString(e), ErrorType::Ping});
182
+ self->m_errorHandler({Utilities::HResultToString(e), ErrorType::Ping});
189
183
  }
190
184
  }
191
185
  }
@@ -246,7 +240,7 @@ fire_and_forget WinRTWebSocketResource::PerformWrite(string &&message, bool isBi
246
240
  }
247
241
  } else {
248
242
  if (self->m_errorHandler) {
249
- self->m_errorHandler({HResultToString(std::move(result)), ErrorType::Send});
243
+ self->m_errorHandler({Utilities::HResultToString(std::move(result)), ErrorType::Send});
250
244
  }
251
245
  }
252
246
  } catch (std::exception const &e) {
@@ -256,7 +250,7 @@ fire_and_forget WinRTWebSocketResource::PerformWrite(string &&message, bool isBi
256
250
  } catch (hresult_error const &e) {
257
251
  // TODO: Remove after fixing unit tests exceptions.
258
252
  if (self->m_errorHandler) {
259
- self->m_errorHandler({HResultToString(e), ErrorType::Ping});
253
+ self->m_errorHandler({Utilities::HResultToString(e), ErrorType::Ping});
260
254
  }
261
255
  }
262
256
  }
@@ -278,7 +272,7 @@ fire_and_forget WinRTWebSocketResource::PerformClose() noexcept {
278
272
  }
279
273
  } catch (hresult_error const &e) {
280
274
  if (m_errorHandler) {
281
- m_errorHandler({HResultToString(e), ErrorType::Close});
275
+ m_errorHandler({Utilities::HResultToString(e), ErrorType::Close});
282
276
  }
283
277
  }
284
278
 
@@ -322,7 +316,22 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
322
316
  }
323
317
  } catch (hresult_error const &e) {
324
318
  if (self->m_errorHandler) {
325
- self->m_errorHandler({HResultToString(e), ErrorType::Receive});
319
+ string errorMessage;
320
+ ErrorType errorType;
321
+ // See
322
+ // https://docs.microsoft.com/uwp/api/windows.networking.sockets.messagewebsocketmessagereceivedeventargs.getdatareader?view=winrt-19041#remarks
323
+ if (e.code() == WININET_E_CONNECTION_ABORTED) {
324
+ errorMessage = "[0x80072EFE] Underlying TCP connection suddenly terminated";
325
+ errorType = ErrorType::Connection;
326
+ self->m_errorHandler({errorMessage, errorType});
327
+
328
+ // Note: We are not clear whether all read-related errors should close the socket.
329
+ self->Close(CloseCode::BadPayload, std::move(errorMessage));
330
+ } else {
331
+ errorMessage = Utilities::HResultToString(e);
332
+ errorType = ErrorType::Receive;
333
+ self->m_errorHandler({errorMessage, errorType});
334
+ }
326
335
  }
327
336
  }
328
337
  });
@@ -346,7 +355,7 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
346
355
  uri = Uri{winrt::to_hstring(url)};
347
356
  } catch (hresult_error const &e) {
348
357
  if (m_errorHandler) {
349
- m_errorHandler({HResultToString(e), ErrorType::Connection});
358
+ m_errorHandler({Utilities::HResultToString(e), ErrorType::Connection});
350
359
  }
351
360
 
352
361
  // Abort - Mark connection as concluded.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-windows",
3
- "version": "0.67.6",
3
+ "version": "0.67.9",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,8 +26,8 @@
26
26
  "@react-native-community/cli": "^6.0.0",
27
27
  "@react-native-community/cli-platform-android": "^6.0.0",
28
28
  "@react-native-community/cli-platform-ios": "^6.0.0",
29
- "@react-native-windows/cli": "0.67.1",
30
- "@react-native-windows/virtualized-list": "0.67.0",
29
+ "@react-native-windows/cli": "0.67.2",
30
+ "@react-native-windows/virtualized-list": "0.67.1",
31
31
  "@react-native/assets": "1.0.0",
32
32
  "@react-native/normalize-color": "2.0.0",
33
33
  "@react-native/polyfills": "2.0.0",
@@ -57,7 +57,7 @@
57
57
  "ws": "^6.1.4"
58
58
  },
59
59
  "devDependencies": {
60
- "@react-native-windows/codegen": "0.67.0",
60
+ "@react-native-windows/codegen": "0.67.1",
61
61
  "@rnw-scripts/eslint-config": "1.1.8",
62
62
  "@rnw-scripts/jest-out-of-tree-snapshot-resolver": "^1.0.2",
63
63
  "@rnx-kit/jest-preset": "^0.1.0",
@@ -83,7 +83,7 @@
83
83
  "react-native": "^0.67.0"
84
84
  },
85
85
  "beachball": {
86
- "defaultNpmTag": "latest",
86
+ "defaultNpmTag": "v0.67-stable",
87
87
  "gitTags": true,
88
88
  "disallowedChangeTypes": [
89
89
  "major",