react-native-windows 0.75.13 → 0.75.15
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/Directory.Build.props +2 -2
- package/Folly/TEMP_UntilFollyUpdate/json.cpp +4 -0
- package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.cpp +23 -15
- package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +5 -5
- package/Folly/cgmanifest.json +1 -1
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/Shared/Networking/WinRTWebSocketResource.cpp +371 -6
- package/Shared/Networking/WinRTWebSocketResource.h +118 -0
- package/package.json +1 -1
package/Directory.Build.props
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
-->
|
|
17
17
|
<EnableSourceLink Condition="'$(EnableSourceLink)' == ''">false</EnableSourceLink>
|
|
18
18
|
<!-- When bumping the Folly version, be sure to bump the git hash of that version's commit and build Folly.vcxproj (to update its cgmanifest.json) too. -->
|
|
19
|
-
<FollyVersion>
|
|
20
|
-
<FollyCommitHash>
|
|
19
|
+
<FollyVersion>2024.01.01.00</FollyVersion>
|
|
20
|
+
<FollyCommitHash>234d39a36a43106747d10cc19efada72fd810dd3</FollyCommitHash>
|
|
21
21
|
<!-- When bumping the fmt version, be sure to bump the git hash of that version's commit and build fmt.vcxproj (to update its cgmanifest.json) too. -->
|
|
22
22
|
<FmtVersion>10.1.0</FmtVersion>
|
|
23
23
|
<FmtCommitHash>ca2e3685b160617d3d95fcd9e789c4e06ca88</FmtCommitHash>
|
|
@@ -849,6 +849,10 @@ void escapeStringImpl(
|
|
|
849
849
|
}
|
|
850
850
|
auto prefix = firstEscapableInWord<EnableExtraAsciiEscapes>(word, opts);
|
|
851
851
|
DCHECK_LE(prefix, avail);
|
|
852
|
+
// [Windows Sometimes prefix is completely wrong (corrupt?), only in Release, causing a later AV (see issue #14394).
|
|
853
|
+
// Prefix should always be <= avail, capping it here as a workaround, hoping the assert above eventually catches this in Debug.
|
|
854
|
+
prefix = std::min(prefix, (size_t)avail);
|
|
855
|
+
// Windows]
|
|
852
856
|
firstEsc += prefix;
|
|
853
857
|
if (prefix < 8) {
|
|
854
858
|
break;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -38,7 +38,6 @@ struct to_ascii_array {
|
|
|
38
38
|
return data.data[index];
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
|
-
|
|
42
41
|
template <uint64_t Base, typename Alphabet>
|
|
43
42
|
alignas(kIsMobile ? sizeof(size_t) : hardware_constructive_interference_size)
|
|
44
43
|
typename to_ascii_array<Base, Alphabet>::data_type_ const
|
|
@@ -94,13 +93,13 @@ extern template to_ascii_table<10, to_ascii_alphabet_upper>::data_type_ const
|
|
|
94
93
|
extern template to_ascii_table<16, to_ascii_alphabet_upper>::data_type_ const
|
|
95
94
|
to_ascii_table<16, to_ascii_alphabet_upper>::data;
|
|
96
95
|
|
|
97
|
-
template <uint64_t Base, typename
|
|
96
|
+
template <uint64_t Base, typename Int>
|
|
98
97
|
struct to_ascii_powers {
|
|
99
|
-
static constexpr size_t size_(
|
|
98
|
+
static constexpr size_t size_(Int v) {
|
|
100
99
|
return 1 + (v < Base ? 0 : size_(v / Base));
|
|
101
100
|
}
|
|
102
|
-
static constexpr size_t const size = size_(~
|
|
103
|
-
using data_type_ = c_array<
|
|
101
|
+
static constexpr size_t const size = size_(~Int(0));
|
|
102
|
+
using data_type_ = c_array<Int, size>;
|
|
104
103
|
static constexpr data_type_ data_() {
|
|
105
104
|
data_type_ result{};
|
|
106
105
|
for (size_t i = 0; i < size; ++i) {
|
|
@@ -111,12 +110,14 @@ struct to_ascii_powers {
|
|
|
111
110
|
// @lint-ignore CLANGTIDY
|
|
112
111
|
static data_type_ const data;
|
|
113
112
|
};
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
#if FOLLY_CPLUSPLUS < 201703L
|
|
114
|
+
template <uint64_t Base, typename Int>
|
|
115
|
+
constexpr size_t const to_ascii_powers<Base, Int>::size;
|
|
116
|
+
#endif
|
|
117
|
+
template <uint64_t Base, typename Int>
|
|
117
118
|
alignas(hardware_constructive_interference_size)
|
|
118
|
-
typename to_ascii_powers<Base,
|
|
119
|
-
to_ascii_powers<Base,
|
|
119
|
+
typename to_ascii_powers<Base, Int>::data_type_ const
|
|
120
|
+
to_ascii_powers<Base, Int>::data = to_ascii_powers<Base, Int>::data_();
|
|
120
121
|
|
|
121
122
|
extern template to_ascii_powers<8, uint64_t>::data_type_ const
|
|
122
123
|
to_ascii_powers<8, uint64_t>::data;
|
|
@@ -151,7 +152,7 @@ template <uint64_t Base>
|
|
|
151
152
|
FOLLY_ALWAYS_INLINE size_t to_ascii_size_array(uint64_t v) {
|
|
152
153
|
using powers = to_ascii_powers<Base, uint64_t>;
|
|
153
154
|
for (size_t i = 0u; i < powers::size; ++i) {
|
|
154
|
-
if (
|
|
155
|
+
if (FOLLY_UNLIKELY(v < powers::data.data[i])) {
|
|
155
156
|
return i + size_t(i == 0);
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -272,6 +273,15 @@ FOLLY_ALWAYS_INLINE size_t to_ascii_with_table(char* out, uint64_t v) {
|
|
|
272
273
|
return size;
|
|
273
274
|
}
|
|
274
275
|
|
|
276
|
+
// Assumes that size >= number of digits in v. If >, the result is left-padded
|
|
277
|
+
// with 0s.
|
|
278
|
+
template <uint64_t Base, typename Alphabet>
|
|
279
|
+
FOLLY_ALWAYS_INLINE void to_ascii_with_route(
|
|
280
|
+
char* outb, size_t size, uint64_t v) {
|
|
281
|
+
kIsMobile //
|
|
282
|
+
? to_ascii_with_array<Base, Alphabet>(outb, size, v)
|
|
283
|
+
: to_ascii_with_table<Base, Alphabet>(outb, size, v);
|
|
284
|
+
}
|
|
275
285
|
template <uint64_t Base, typename Alphabet>
|
|
276
286
|
FOLLY_ALWAYS_INLINE size_t
|
|
277
287
|
to_ascii_with_route(char* outb, char const* oute, uint64_t v) {
|
|
@@ -279,9 +289,7 @@ to_ascii_with_route(char* outb, char const* oute, uint64_t v) {
|
|
|
279
289
|
if (FOLLY_UNLIKELY(oute < outb || size_t(oute - outb) < size)) {
|
|
280
290
|
return 0;
|
|
281
291
|
}
|
|
282
|
-
|
|
283
|
-
? to_ascii_with_array<Base, Alphabet>(outb, size, v)
|
|
284
|
-
: to_ascii_with_table<Base, Alphabet>(outb, size, v);
|
|
292
|
+
to_ascii_with_route<Base, Alphabet>(outb, size, v);
|
|
285
293
|
return size;
|
|
286
294
|
}
|
|
287
295
|
template <uint64_t Base, typename Alphabet, size_t N>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -61,14 +61,14 @@ using to_ascii_alphabet_upper = to_ascii_alphabet<true>;
|
|
|
61
61
|
// In base 10, u64 requires at most 20 bytes, u32 at most 10, u16 at most 5,
|
|
62
62
|
// and u8 at most 3.
|
|
63
63
|
/*
|
|
64
|
-
template <uint64_t Base, typename
|
|
64
|
+
template <uint64_t Base, typename Int>
|
|
65
65
|
FOLLY_INLINE_VARIABLE constexpr size_t to_ascii_size_max =
|
|
66
|
-
|
|
66
|
+
detail::to_ascii_powers<Base, Int>::size;
|
|
67
67
|
*/
|
|
68
68
|
// to_ascii_size_max_decimal
|
|
69
69
|
//
|
|
70
70
|
// An alias to to_ascii_size_max<10>.
|
|
71
|
-
template <typename
|
|
71
|
+
template <typename Int>
|
|
72
72
|
FOLLY_INLINE_VARIABLE constexpr size_t to_ascii_size_max_decimal;
|
|
73
73
|
|
|
74
74
|
template <>
|
|
@@ -170,7 +170,7 @@ size_t to_ascii_upper(char (&out)[N], uint64_t v) {
|
|
|
170
170
|
//
|
|
171
171
|
// An alias to to_ascii<10, false>.
|
|
172
172
|
//
|
|
173
|
-
// async-
|
|
173
|
+
// async-signal-safe
|
|
174
174
|
inline size_t to_ascii_decimal(char* outb, char const* oute, uint64_t v) {
|
|
175
175
|
return to_ascii_lower<10>(outb, oute, v);
|
|
176
176
|
}
|
package/Folly/cgmanifest.json
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
-->
|
|
11
11
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
12
12
|
<PropertyGroup>
|
|
13
|
-
<ReactNativeWindowsVersion>0.75.
|
|
13
|
+
<ReactNativeWindowsVersion>0.75.15</ReactNativeWindowsVersion>
|
|
14
14
|
<ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
|
|
15
15
|
<ReactNativeWindowsMinor>75</ReactNativeWindowsMinor>
|
|
16
|
-
<ReactNativeWindowsPatch>
|
|
16
|
+
<ReactNativeWindowsPatch>15</ReactNativeWindowsPatch>
|
|
17
17
|
<ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
|
|
18
|
-
<ReactNativeWindowsCommitId>
|
|
18
|
+
<ReactNativeWindowsCommitId>81be93a4099bcd296a9aec9ee1904c9f93bb7fea</ReactNativeWindowsCommitId>
|
|
19
19
|
</PropertyGroup>
|
|
20
20
|
</Project>
|
|
@@ -21,16 +21,18 @@
|
|
|
21
21
|
|
|
22
22
|
using Microsoft::Common::Utilities::CheckedReinterpretCast;
|
|
23
23
|
|
|
24
|
+
using Mso::DispatchQueue;
|
|
25
|
+
|
|
24
26
|
using std::function;
|
|
25
27
|
using std::lock_guard;
|
|
26
28
|
using std::mutex;
|
|
27
|
-
using std::size_t;
|
|
28
29
|
using std::string;
|
|
29
30
|
using std::vector;
|
|
30
31
|
|
|
31
32
|
using winrt::fire_and_forget;
|
|
32
33
|
using winrt::hresult;
|
|
33
34
|
using winrt::hresult_error;
|
|
35
|
+
using winrt::hstring;
|
|
34
36
|
using winrt::resume_background;
|
|
35
37
|
using winrt::resume_on_signal;
|
|
36
38
|
using winrt::Windows::Foundation::IAsyncAction;
|
|
@@ -38,6 +40,7 @@ using winrt::Windows::Foundation::Uri;
|
|
|
38
40
|
using winrt::Windows::Networking::Sockets::IMessageWebSocket;
|
|
39
41
|
using winrt::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs;
|
|
40
42
|
using winrt::Windows::Networking::Sockets::IWebSocket;
|
|
43
|
+
using winrt::Windows::Networking::Sockets::IWebSocketClosedEventArgs;
|
|
41
44
|
using winrt::Windows::Networking::Sockets::MessageWebSocket;
|
|
42
45
|
using winrt::Windows::Networking::Sockets::SocketMessageType;
|
|
43
46
|
using winrt::Windows::Networking::Sockets::WebSocketClosedEventArgs;
|
|
@@ -54,9 +57,9 @@ namespace {
|
|
|
54
57
|
///
|
|
55
58
|
/// Implements an awaiter for Mso::DispatchQueue
|
|
56
59
|
///
|
|
57
|
-
auto resume_in_queue(const
|
|
60
|
+
auto resume_in_queue(const DispatchQueue &queue) noexcept {
|
|
58
61
|
struct awaitable {
|
|
59
|
-
awaitable(const
|
|
62
|
+
awaitable(const DispatchQueue &queue) noexcept : m_queue{queue} {}
|
|
60
63
|
|
|
61
64
|
bool await_ready() const noexcept {
|
|
62
65
|
return false;
|
|
@@ -79,10 +82,367 @@ auto resume_in_queue(const Mso::DispatchQueue &queue) noexcept {
|
|
|
79
82
|
return awaitable{queue};
|
|
80
83
|
} // resume_in_queue
|
|
81
84
|
|
|
85
|
+
DispatchQueue GetCurrentOrSerialQueue() noexcept {
|
|
86
|
+
auto queue = DispatchQueue::CurrentQueue();
|
|
87
|
+
if (!queue)
|
|
88
|
+
queue = DispatchQueue::MakeSerialQueue();
|
|
89
|
+
|
|
90
|
+
return queue;
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
} // namespace
|
|
83
94
|
|
|
84
95
|
namespace Microsoft::React::Networking {
|
|
85
96
|
|
|
97
|
+
#pragma region WinRTWebSocketResource2
|
|
98
|
+
|
|
99
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(
|
|
100
|
+
IMessageWebSocket &&socket,
|
|
101
|
+
IDataWriter &&writer,
|
|
102
|
+
vector<ChainValidationResult> &&certExceptions,
|
|
103
|
+
DispatchQueue callingQueue)
|
|
104
|
+
: m_socket{std::move(socket)},
|
|
105
|
+
m_writer(std::move(writer)),
|
|
106
|
+
m_readyState{ReadyState::Connecting},
|
|
107
|
+
m_connectPerformed{CreateEvent(/*attributes*/ nullptr, /*manual reset*/ true, /*state*/ false, /*name*/ nullptr)},
|
|
108
|
+
m_callingQueue{callingQueue} {
|
|
109
|
+
for (const auto &certException : certExceptions) {
|
|
110
|
+
m_socket.Control().IgnorableServerCertificateErrors().Append(certException);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// private
|
|
115
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(
|
|
116
|
+
IMessageWebSocket &&socket,
|
|
117
|
+
vector<ChainValidationResult> &&certExceptions)
|
|
118
|
+
: WinRTWebSocketResource2(
|
|
119
|
+
std::move(socket),
|
|
120
|
+
DataWriter{socket.OutputStream()},
|
|
121
|
+
std::move(certExceptions),
|
|
122
|
+
GetCurrentOrSerialQueue()) {}
|
|
123
|
+
|
|
124
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(vector<ChainValidationResult> &&certExceptions)
|
|
125
|
+
: WinRTWebSocketResource2(MessageWebSocket{}, std::move(certExceptions)) {}
|
|
126
|
+
|
|
127
|
+
WinRTWebSocketResource2::~WinRTWebSocketResource2() noexcept /*override*/
|
|
128
|
+
{}
|
|
129
|
+
|
|
130
|
+
void WinRTWebSocketResource2::Fail(string &&message, ErrorType type) noexcept {
|
|
131
|
+
auto self = shared_from_this();
|
|
132
|
+
|
|
133
|
+
self->m_backgroundQueue.Post([self, message = std::move(message), type]() {
|
|
134
|
+
self->m_readyState = ReadyState::Closed;
|
|
135
|
+
self->m_callingQueue.Post([self, message = std::move(message), type]() {
|
|
136
|
+
if (self->m_errorHandler) {
|
|
137
|
+
self->m_errorHandler({std::move(message), type});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void WinRTWebSocketResource2::Fail(hresult &&error, ErrorType type) noexcept {
|
|
144
|
+
Fail(Utilities::HResultToString(std::move(error)), type);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void WinRTWebSocketResource2::Fail(hresult_error const &error, ErrorType type) noexcept {
|
|
148
|
+
Fail(Utilities::HResultToString(error), type);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
void WinRTWebSocketResource2::OnMessageReceived(
|
|
152
|
+
IMessageWebSocket const &,
|
|
153
|
+
IMessageWebSocketMessageReceivedEventArgs const &args) {
|
|
154
|
+
auto self = shared_from_this();
|
|
155
|
+
string response;
|
|
156
|
+
|
|
157
|
+
IDataReader reader{nullptr};
|
|
158
|
+
// Use WinRT ABI to avoid throwing exceptions on expected code paths
|
|
159
|
+
HRESULT hr =
|
|
160
|
+
reinterpret_cast<ABI::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs *>(
|
|
161
|
+
winrt::get_abi(args))
|
|
162
|
+
->GetDataReader(reinterpret_cast<ABI::Windows::Storage::Streams::IDataReader **>(winrt::put_abi(reader)));
|
|
163
|
+
|
|
164
|
+
if (FAILED(hr)) {
|
|
165
|
+
string errorMessage;
|
|
166
|
+
ErrorType errorType;
|
|
167
|
+
// See
|
|
168
|
+
// https://docs.microsoft.com/uwp/api/windows.networking.sockets.messagewebsocketmessagereceivedeventargs.getdatareader?view=winrt-22621#remarks
|
|
169
|
+
if (hr == WININET_E_CONNECTION_ABORTED) {
|
|
170
|
+
errorMessage = "[0x80072EFE] Underlying TCP connection suddenly terminated";
|
|
171
|
+
errorType = ErrorType::Connection;
|
|
172
|
+
// Note: It is not clear whether all read-related errors should close the socket.
|
|
173
|
+
Close(CloseCode::BadPayload, std::move(errorMessage));
|
|
174
|
+
} else {
|
|
175
|
+
errorMessage = Utilities::HResultToString(hr);
|
|
176
|
+
errorType = ErrorType::Receive;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
self->Fail(std::move(errorMessage), errorType);
|
|
180
|
+
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
auto len = reader.UnconsumedBufferLength();
|
|
186
|
+
if (args.MessageType() == SocketMessageType::Utf8) {
|
|
187
|
+
reader.UnicodeEncoding(UnicodeEncoding::Utf8);
|
|
188
|
+
vector<uint8_t> data(len);
|
|
189
|
+
reader.ReadBytes(data);
|
|
190
|
+
|
|
191
|
+
response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
|
|
192
|
+
} else {
|
|
193
|
+
auto buffer = reader.ReadBuffer(len);
|
|
194
|
+
auto data = CryptographicBuffer::EncodeToBase64String(buffer);
|
|
195
|
+
|
|
196
|
+
response = winrt::to_string(std::wstring_view(data));
|
|
197
|
+
}
|
|
198
|
+
} catch (hresult_error const &e) {
|
|
199
|
+
return self->Fail(e, ErrorType::Receive);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Posting inside try-catch block causes errors.
|
|
203
|
+
self->m_callingQueue.Post([self, response = std::move(response), messageType = args.MessageType()]() {
|
|
204
|
+
if (self->m_readHandler) {
|
|
205
|
+
self->m_readHandler(response.length(), response, messageType == SocketMessageType::Binary);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void WinRTWebSocketResource2::OnClosed(IWebSocket const &sender, IWebSocketClosedEventArgs const &args) {
|
|
211
|
+
auto self = shared_from_this();
|
|
212
|
+
|
|
213
|
+
self->m_backgroundQueue.Post([self]() { self->m_readyState = ReadyState::Closed; });
|
|
214
|
+
|
|
215
|
+
self->m_callingQueue.Post([self]() {
|
|
216
|
+
if (self->m_closeHandler) {
|
|
217
|
+
self->m_closeHandler(self->m_closeCode, self->m_closeReason);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
fire_and_forget WinRTWebSocketResource2::PerformConnect(Uri &&uri) noexcept {
|
|
223
|
+
auto self = shared_from_this();
|
|
224
|
+
auto coUri = std::move(uri);
|
|
225
|
+
|
|
226
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
227
|
+
|
|
228
|
+
auto async = self->m_socket.ConnectAsync(coUri);
|
|
229
|
+
co_await lessthrow_await_adapter<IAsyncAction>{async};
|
|
230
|
+
|
|
231
|
+
co_await resume_in_queue(self->m_callingQueue);
|
|
232
|
+
|
|
233
|
+
auto result = async.ErrorCode();
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
if (result >= 0) { // Non-failing HRESULT
|
|
237
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
238
|
+
self->m_readyState = ReadyState::Open;
|
|
239
|
+
|
|
240
|
+
co_await resume_in_queue(self->m_callingQueue);
|
|
241
|
+
if (self->m_connectHandler) {
|
|
242
|
+
self->m_connectHandler();
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
self->Fail(std::move(result), ErrorType::Connection);
|
|
246
|
+
}
|
|
247
|
+
} catch (hresult_error const &e) {
|
|
248
|
+
self->Fail(e, ErrorType::Connection);
|
|
249
|
+
} catch (std::exception const &e) {
|
|
250
|
+
self->Fail(e.what(), ErrorType::Connection);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
SetEvent(self->m_connectPerformed.get());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fire_and_forget WinRTWebSocketResource2::PerformClose() noexcept {
|
|
257
|
+
auto self = shared_from_this();
|
|
258
|
+
|
|
259
|
+
co_await resume_on_signal(self->m_connectPerformed.get());
|
|
260
|
+
|
|
261
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
262
|
+
|
|
263
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
|
|
264
|
+
co_await self->SendPendingMessages();
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
self->m_socket.Close(static_cast<uint16_t>(m_closeCode), winrt::to_hstring(m_closeReason));
|
|
268
|
+
self->m_readyState = ReadyState::Closing;
|
|
269
|
+
} catch (winrt::hresult_invalid_argument const &e) {
|
|
270
|
+
Fail(e, ErrorType::Close);
|
|
271
|
+
} catch (hresult_error const &e) {
|
|
272
|
+
Fail(e, ErrorType::Close);
|
|
273
|
+
} catch (const std::exception &e) {
|
|
274
|
+
Fail(e.what(), ErrorType::Close);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
fire_and_forget WinRTWebSocketResource2::PerformWrite(string &&message, bool isBinary) noexcept {
|
|
279
|
+
auto self = shared_from_this();
|
|
280
|
+
string coMessage = std::move(message);
|
|
281
|
+
|
|
282
|
+
co_await resume_in_queue(self->m_backgroundQueue); // Ensure writes happen sequentially
|
|
283
|
+
self->m_outgoingMessages.emplace(std::move(coMessage), isBinary);
|
|
284
|
+
|
|
285
|
+
co_await resume_on_signal(self->m_connectPerformed.get());
|
|
286
|
+
|
|
287
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
288
|
+
|
|
289
|
+
co_await self->SendPendingMessages();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
IAsyncAction WinRTWebSocketResource2::SendPendingMessages() noexcept {
|
|
293
|
+
auto self = shared_from_this();
|
|
294
|
+
|
|
295
|
+
while (!self->m_outgoingMessages.empty()) {
|
|
296
|
+
if (self->m_readyState != ReadyState::Open) {
|
|
297
|
+
co_return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
size_t length = 0;
|
|
301
|
+
string messageLocal;
|
|
302
|
+
bool isBinaryLocal;
|
|
303
|
+
try {
|
|
304
|
+
std::tie(messageLocal, isBinaryLocal) = self->m_outgoingMessages.front();
|
|
305
|
+
self->m_outgoingMessages.pop();
|
|
306
|
+
if (isBinaryLocal) {
|
|
307
|
+
self->m_socket.Control().MessageType(SocketMessageType::Binary);
|
|
308
|
+
|
|
309
|
+
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(messageLocal));
|
|
310
|
+
if (buffer) {
|
|
311
|
+
length = buffer.Length();
|
|
312
|
+
self->m_writer.WriteBuffer(buffer);
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
self->m_socket.Control().MessageType(SocketMessageType::Utf8);
|
|
316
|
+
|
|
317
|
+
length = messageLocal.size();
|
|
318
|
+
winrt::array_view<const uint8_t> view(
|
|
319
|
+
CheckedReinterpretCast<const uint8_t *>(messageLocal.c_str()),
|
|
320
|
+
CheckedReinterpretCast<const uint8_t *>(messageLocal.c_str()) + messageLocal.length());
|
|
321
|
+
self->m_writer.WriteBytes(view);
|
|
322
|
+
}
|
|
323
|
+
} catch (hresult_error const &e) { // TODO: Remove after fixing unit tests exceptions.
|
|
324
|
+
self->Fail(e, ErrorType::Send);
|
|
325
|
+
co_return;
|
|
326
|
+
} catch (const std::exception &e) {
|
|
327
|
+
self->Fail(e.what(), ErrorType::Send);
|
|
328
|
+
co_return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
auto async = self->m_writer.StoreAsync();
|
|
332
|
+
co_await lessthrow_await_adapter<DataWriterStoreOperation>{async};
|
|
333
|
+
|
|
334
|
+
auto result = async.ErrorCode();
|
|
335
|
+
if (result < 0) {
|
|
336
|
+
Fail(std::move(result), ErrorType::Send);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
#pragma region IWebSocketResource
|
|
342
|
+
|
|
343
|
+
void WinRTWebSocketResource2::Connect(string &&url, const Protocols &protocols, const Options &options) noexcept {
|
|
344
|
+
// Register MessageReceived BEFORE calling Connect
|
|
345
|
+
// https://learn.microsoft.com/en-us/uwp/api/windows.networking.sockets.messagewebsocket.messagereceived?view=winrt-22621
|
|
346
|
+
m_socket.MessageReceived([self = shared_from_this()](
|
|
347
|
+
IMessageWebSocket const &sender, IMessageWebSocketMessageReceivedEventArgs const &args) {
|
|
348
|
+
self->OnMessageReceived(sender, args);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
m_socket.Closed([self = shared_from_this()](IWebSocket const &sender, IWebSocketClosedEventArgs const &args) {
|
|
352
|
+
self->OnClosed(sender, args);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
auto supportedProtocols = m_socket.Control().SupportedProtocols();
|
|
356
|
+
for (const auto &protocol : protocols) {
|
|
357
|
+
supportedProtocols.Append(winrt::to_hstring(protocol));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
Uri uri{nullptr};
|
|
361
|
+
bool hasOriginHeader{false};
|
|
362
|
+
try {
|
|
363
|
+
uri = Uri{winrt::to_hstring(url)};
|
|
364
|
+
|
|
365
|
+
for (const auto &header : options) {
|
|
366
|
+
m_socket.SetRequestHeader(header.first, winrt::to_hstring(header.second));
|
|
367
|
+
if (boost::iequals(header.first, L"Origin")) {
|
|
368
|
+
hasOriginHeader = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// #12626 - If Origin header is not provided, set to connect endpoint.
|
|
373
|
+
if (!hasOriginHeader) {
|
|
374
|
+
auto scheme = uri.SchemeName();
|
|
375
|
+
auto host = uri.Host();
|
|
376
|
+
auto port = uri.Port();
|
|
377
|
+
|
|
378
|
+
if (scheme == L"ws") {
|
|
379
|
+
scheme = L"http";
|
|
380
|
+
} else if (scheme == L"wss") {
|
|
381
|
+
scheme = L"https";
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Only add a port if a port is defined.
|
|
385
|
+
hstring originPort = port != 0 ? L":" + winrt::to_hstring(port) : L"";
|
|
386
|
+
auto origin = hstring{scheme + L"://" + host + originPort};
|
|
387
|
+
|
|
388
|
+
m_socket.SetRequestHeader(L"Origin", std::move(origin));
|
|
389
|
+
}
|
|
390
|
+
} catch (hresult_error const &e) {
|
|
391
|
+
Fail(e, ErrorType::Connection);
|
|
392
|
+
|
|
393
|
+
SetEvent(m_connectPerformed.get());
|
|
394
|
+
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
PerformConnect(std::move(uri));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void WinRTWebSocketResource2::Ping() noexcept {}
|
|
402
|
+
|
|
403
|
+
void WinRTWebSocketResource2::Send(string &&message) noexcept {
|
|
404
|
+
PerformWrite(std::move(message), false);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
void WinRTWebSocketResource2::SendBinary(string &&base64String) noexcept {
|
|
408
|
+
PerformWrite(std::move(base64String), true);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
void WinRTWebSocketResource2::Close(CloseCode code, const string &reason) noexcept {
|
|
412
|
+
m_closeCode = code;
|
|
413
|
+
m_closeReason = reason;
|
|
414
|
+
PerformClose();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
IWebSocketResource::ReadyState WinRTWebSocketResource2::GetReadyState() const noexcept {
|
|
418
|
+
return m_readyState;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
void WinRTWebSocketResource2::SetOnConnect(function<void()> &&handler) noexcept {
|
|
422
|
+
m_connectHandler = std::move(handler);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
void WinRTWebSocketResource2::SetOnPing(function<void()> && /*handler*/) noexcept {}
|
|
426
|
+
|
|
427
|
+
void WinRTWebSocketResource2::SetOnSend(function<void(size_t)> && /*handler*/) noexcept {}
|
|
428
|
+
|
|
429
|
+
void WinRTWebSocketResource2::SetOnMessage(function<void(size_t, const string &, bool isBinary)> &&handler) noexcept {
|
|
430
|
+
m_readHandler = std::move(handler);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
void WinRTWebSocketResource2::SetOnClose(function<void(CloseCode, const string &)> &&handler) noexcept {
|
|
434
|
+
m_closeHandler = std::move(handler);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void WinRTWebSocketResource2::SetOnError(function<void(Error &&)> &&handler) noexcept {
|
|
438
|
+
m_errorHandler = std::move(handler);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#pragma endregion IWebSocketResource
|
|
442
|
+
|
|
443
|
+
#pragma endregion WinRTWebSocketResource2
|
|
444
|
+
|
|
445
|
+
#pragma region Legacy resource
|
|
86
446
|
// private
|
|
87
447
|
WinRTWebSocketResource::WinRTWebSocketResource(
|
|
88
448
|
IMessageWebSocket &&socket,
|
|
@@ -331,7 +691,7 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
331
691
|
response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
|
|
332
692
|
} else {
|
|
333
693
|
auto buffer = reader.ReadBuffer(len);
|
|
334
|
-
|
|
694
|
+
hstring data = CryptographicBuffer::EncodeToBase64String(buffer);
|
|
335
695
|
|
|
336
696
|
response = winrt::to_string(std::wstring_view(data));
|
|
337
697
|
}
|
|
@@ -360,7 +720,7 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
360
720
|
}
|
|
361
721
|
}
|
|
362
722
|
|
|
363
|
-
winrt::Windows::Foundation::Collections::IVector<
|
|
723
|
+
winrt::Windows::Foundation::Collections::IVector<hstring> supportedProtocols =
|
|
364
724
|
m_socket.Control().SupportedProtocols();
|
|
365
725
|
for (const auto &protocol : protocols) {
|
|
366
726
|
supportedProtocols.Append(winrt::to_hstring(protocol));
|
|
@@ -382,7 +742,10 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
382
742
|
scheme = L"https";
|
|
383
743
|
}
|
|
384
744
|
|
|
385
|
-
|
|
745
|
+
// Only add a port if a port is defined
|
|
746
|
+
hstring originPort = port != 0 ? L":" + winrt::to_hstring(port) : L"";
|
|
747
|
+
auto origin = hstring{scheme + L"://" + host + originPort};
|
|
748
|
+
|
|
386
749
|
m_socket.SetRequestHeader(L"Origin", std::move(origin));
|
|
387
750
|
}
|
|
388
751
|
|
|
@@ -458,4 +821,6 @@ void WinRTWebSocketResource::SetOnError(function<void(Error &&)> &&handler) noex
|
|
|
458
821
|
|
|
459
822
|
#pragma endregion IWebSocketResource
|
|
460
823
|
|
|
824
|
+
#pragma endregion Legacy resource
|
|
825
|
+
|
|
461
826
|
} // namespace Microsoft::React::Networking
|
|
@@ -16,6 +16,124 @@
|
|
|
16
16
|
|
|
17
17
|
namespace Microsoft::React::Networking {
|
|
18
18
|
|
|
19
|
+
class WinRTWebSocketResource2 : public IWebSocketResource,
|
|
20
|
+
public std::enable_shared_from_this<WinRTWebSocketResource2> {
|
|
21
|
+
winrt::Windows::Networking::Sockets::IMessageWebSocket m_socket;
|
|
22
|
+
|
|
23
|
+
///
|
|
24
|
+
// Connection attempt performed, either succeeding or failing
|
|
25
|
+
///
|
|
26
|
+
winrt::handle m_connectPerformed;
|
|
27
|
+
|
|
28
|
+
ReadyState m_readyState;
|
|
29
|
+
Mso::DispatchQueue m_callingQueue;
|
|
30
|
+
Mso::DispatchQueue m_backgroundQueue;
|
|
31
|
+
std::queue<std::pair<std::string, bool>> m_outgoingMessages;
|
|
32
|
+
CloseCode m_closeCode{CloseCode::Normal};
|
|
33
|
+
std::string m_closeReason;
|
|
34
|
+
|
|
35
|
+
std::function<void()> m_connectHandler;
|
|
36
|
+
std::function<void(std::size_t, const std::string &, bool)> m_readHandler;
|
|
37
|
+
std::function<void(CloseCode, const std::string &)> m_closeHandler;
|
|
38
|
+
std::function<void(Error &&)> m_errorHandler;
|
|
39
|
+
|
|
40
|
+
winrt::Windows::Storage::Streams::IDataWriter m_writer;
|
|
41
|
+
|
|
42
|
+
void Fail(std::string &&message, ErrorType type) noexcept;
|
|
43
|
+
void Fail(winrt::hresult &&e, ErrorType type) noexcept;
|
|
44
|
+
void Fail(winrt::hresult_error const &e, ErrorType type) noexcept;
|
|
45
|
+
|
|
46
|
+
void OnMessageReceived(
|
|
47
|
+
winrt::Windows::Networking::Sockets::IMessageWebSocket const &,
|
|
48
|
+
winrt::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs const &args);
|
|
49
|
+
|
|
50
|
+
void OnClosed(
|
|
51
|
+
winrt::Windows::Networking::Sockets::IWebSocket const &,
|
|
52
|
+
winrt::Windows::Networking::Sockets::IWebSocketClosedEventArgs const &args);
|
|
53
|
+
|
|
54
|
+
winrt::fire_and_forget PerformConnect(winrt::Windows::Foundation::Uri &&uri) noexcept;
|
|
55
|
+
winrt::fire_and_forget PerformWrite(std::string &&message, bool isBinary) noexcept;
|
|
56
|
+
winrt::fire_and_forget PerformClose() noexcept;
|
|
57
|
+
winrt::Windows::Foundation::IAsyncAction SendPendingMessages() noexcept;
|
|
58
|
+
|
|
59
|
+
WinRTWebSocketResource2(
|
|
60
|
+
winrt::Windows::Networking::Sockets::IMessageWebSocket &&socket,
|
|
61
|
+
std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions);
|
|
62
|
+
|
|
63
|
+
public:
|
|
64
|
+
WinRTWebSocketResource2(
|
|
65
|
+
winrt::Windows::Networking::Sockets::IMessageWebSocket &&socket,
|
|
66
|
+
winrt::Windows::Storage::Streams::IDataWriter &&writer,
|
|
67
|
+
std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions,
|
|
68
|
+
Mso::DispatchQueue callingQueue);
|
|
69
|
+
|
|
70
|
+
WinRTWebSocketResource2(
|
|
71
|
+
std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions);
|
|
72
|
+
|
|
73
|
+
~WinRTWebSocketResource2() noexcept override;
|
|
74
|
+
|
|
75
|
+
#pragma region IWebSocketResource
|
|
76
|
+
|
|
77
|
+
/// <summary>
|
|
78
|
+
/// <see cref="IWebSocketResource::Connect" />
|
|
79
|
+
/// </summary>
|
|
80
|
+
void Connect(std::string &&url, const Protocols &protocols, const Options &options) noexcept override;
|
|
81
|
+
|
|
82
|
+
/// <summary>
|
|
83
|
+
/// <see cref="IWebSocketResource::Ping" />
|
|
84
|
+
/// </summary>
|
|
85
|
+
void Ping() noexcept override;
|
|
86
|
+
|
|
87
|
+
/// <summary>
|
|
88
|
+
/// <see cref="IWebSocketResource::Send" />
|
|
89
|
+
/// </summary>
|
|
90
|
+
void Send(std::string &&message) noexcept override;
|
|
91
|
+
|
|
92
|
+
/// <summary>
|
|
93
|
+
/// <see cref="IWebSocketResource::SendBinary" />
|
|
94
|
+
/// </summary>
|
|
95
|
+
void SendBinary(std::string &&base64String) noexcept override;
|
|
96
|
+
|
|
97
|
+
/// <summary>
|
|
98
|
+
/// <see cref="IWebSocketResource::Close" />
|
|
99
|
+
/// </summary>
|
|
100
|
+
void Close(CloseCode code, const std::string &reason) noexcept override;
|
|
101
|
+
|
|
102
|
+
ReadyState GetReadyState() const noexcept override;
|
|
103
|
+
|
|
104
|
+
/// <summary>
|
|
105
|
+
/// <see cref="IWebSocketResource::SetOnConnect" />
|
|
106
|
+
/// </summary>
|
|
107
|
+
void SetOnConnect(std::function<void()> &&handler) noexcept override;
|
|
108
|
+
|
|
109
|
+
/// <summary>
|
|
110
|
+
/// <see cref="IWebSocketResource::SetOnPing" />
|
|
111
|
+
/// </summary>
|
|
112
|
+
void SetOnPing(std::function<void()> &&handler) noexcept override;
|
|
113
|
+
|
|
114
|
+
/// <summary>
|
|
115
|
+
/// <see cref="IWebSocketResource::SetOnSend" />
|
|
116
|
+
/// </summary>
|
|
117
|
+
void SetOnSend(std::function<void(std::size_t)> &&handler) noexcept override;
|
|
118
|
+
|
|
119
|
+
/// <summary>
|
|
120
|
+
/// <see cref="IWebSocketResource::SetOnMessage" />
|
|
121
|
+
/// </summary>
|
|
122
|
+
void SetOnMessage(std::function<void(std::size_t, const std::string &, bool isBinary)> &&handler) noexcept override;
|
|
123
|
+
|
|
124
|
+
/// <summary>
|
|
125
|
+
/// <see cref="IWebSocketResource::SetOnClose" />
|
|
126
|
+
/// </summary>
|
|
127
|
+
void SetOnClose(std::function<void(CloseCode, const std::string &)> &&handler) noexcept override;
|
|
128
|
+
|
|
129
|
+
/// <summary>
|
|
130
|
+
/// <see cref="IWebSocketResource::SetOnError" />
|
|
131
|
+
/// </summary>
|
|
132
|
+
void SetOnError(std::function<void(Error &&)> &&handler) noexcept override;
|
|
133
|
+
|
|
134
|
+
#pragma endregion IWebSocketResource
|
|
135
|
+
};
|
|
136
|
+
|
|
19
137
|
class WinRTWebSocketResource : public IWebSocketResource, public std::enable_shared_from_this<WinRTWebSocketResource> {
|
|
20
138
|
winrt::Windows::Networking::Sockets::IMessageWebSocket m_socket;
|
|
21
139
|
// TODO: Use or remove.
|