Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Handle abrupt WebSocket connection interruption",
"packageName": "react-native-windows",
"email": "julio.rocha@microsoft.com",
"dependentChangeType": "patch"
}
29 changes: 29 additions & 0 deletions vnext/Desktop.IntegrationTests/WebSocketIntegrationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,35 @@ TEST_CLASS (WebSocketIntegrationTest)
Assert::AreEqual({}, errorMessage);
Assert::AreEqual(expected, result);
}

BEGIN_TEST_METHOD_ATTRIBUTE(AbruptDisconnectFailsWithSpecificMessage)
TEST_IGNORE() //TODO: Find a way to emulate abrupt disconnection using Test::WebSocketServer
END_TEST_METHOD_ATTRIBUTE()
TEST_METHOD(AbruptDisconnectFailsWithSpecificMessage)
{
promise<void> closedPromise;
auto ws = IWebSocketResource::Make();
IWebSocketResource::Error error{{}, IWebSocketResource::ErrorType::None};
CloseCode closeCode;
ws->SetOnClose([&closedPromise, &closeCode](CloseCode code, const string& reason)
{
closeCode = code;
closedPromise.set_value();
});
ws->SetOnError([&closedPromise, &error](IWebSocketResource::Error&& wsError)
{
error = std::move(wsError);
});

ws->Connect("ws://localhost:5555");

closedPromise.get_future().wait();

//NOTE: This message is implementation-specific (WinRTWebSocketResource)
Assert::AreEqual({"[0x80072EFE] Underlying TCP connection suddenly terminated"}, error.Message);
Assert::AreEqual(static_cast<size_t>(IWebSocketResource::ErrorType::Connection), static_cast<size_t>(error.Type));
Assert::AreEqual(static_cast<size_t>(CloseCode::BadPayload), static_cast<size_t>(closeCode));
}
};

uint16_t WebSocketIntegrationTest::s_port = 6666;
2 changes: 1 addition & 1 deletion vnext/Shared/Networking/IWebSocketResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct IWebSocketResource {

struct Error {
std::string Message;
const ErrorType Type;
ErrorType Type;
};

#pragma endregion Inner types
Expand Down
17 changes: 16 additions & 1 deletion vnext/Shared/Networking/WinRTWebSocketResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,22 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
}
} catch (hresult_error const &e) {
if (self->m_errorHandler) {
self->m_errorHandler({Utilities::HResultToString(e), ErrorType::Receive});
string errorMessage;
ErrorType errorType;
// See
// https://docs.microsoft.com/uwp/api/windows.networking.sockets.messagewebsocketmessagereceivedeventargs.getdatareader?view=winrt-19041#remarks
if (e.code() == WININET_E_CONNECTION_ABORTED) {
errorMessage = "[0x80072EFE] Underlying TCP connection suddenly terminated";
errorType = ErrorType::Connection;
self->m_errorHandler({errorMessage, errorType});

// Note: We are not clear whether all read-related errors should close the socket.
self->Close(CloseCode::BadPayload, std::move(errorMessage));
} else {
errorMessage = Utilities::HResultToString(e);
errorType = ErrorType::Receive;
self->m_errorHandler({errorMessage, errorType});
}
}
}
});
Expand Down