diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index 668ee6eff6ac..380b8bea89e8 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.4 + +* Fixes an issue where the URL logged would not be escaped on failure. + ## 3.1.3 * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index 629e9dc71963..99579d8925a2 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher_windows description: Windows implementation of the url_launcher plugin. repository: https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22 -version: 3.1.3 +version: 3.1.4 environment: sdk: ^3.3.0 diff --git a/packages/url_launcher/url_launcher_windows/windows/test/url_launcher_windows_test.cpp b/packages/url_launcher/url_launcher_windows/windows/test/url_launcher_windows_test.cpp index db46e1a4a983..ac933e2269e2 100644 --- a/packages/url_launcher/url_launcher_windows/windows/test/url_launcher_windows_test.cpp +++ b/packages/url_launcher/url_launcher_windows/windows/test/url_launcher_windows_test.cpp @@ -24,6 +24,7 @@ using flutter::EncodableMap; using flutter::EncodableValue; using ::testing::_; using ::testing::DoAll; +using ::testing::HasSubstr; using ::testing::Pointee; using ::testing::Return; using ::testing::SetArgPointee; @@ -160,5 +161,28 @@ TEST(UrlLauncherPlugin, LaunchUTF8EncodedFileURLSuccess) { EXPECT_TRUE(result.value()); } +TEST(UrlLauncherPlugin, LaunchUTF8LogsUnescapedOnFail) { + std::unique_ptr system = std::make_unique(); + + // Return a failure value (<32) from launching. + EXPECT_CALL( + *system, + ShellExecuteW( + _, StrEq(L"open"), + // 家の管理/スキャナ"), + StrEq( + L"file:///G:/\x5bb6\x306e\x7ba1\x7406/\x30b9\x30ad\x30e3\x30ca"), + _, _, _)) + .WillOnce(Return(reinterpret_cast(0))); + + UrlLauncherPlugin plugin(std::move(system)); + ErrorOr result = plugin.LaunchUrl( + "file:///G:/%E5%AE%B6%E3%81%AE%E7%AE%A1%E7%90%86/" + "%E3%82%B9%E3%82%AD%E3%83%A3%E3%83%8A"); + + ASSERT_TRUE(result.has_error()); + EXPECT_THAT(result.error().message(), HasSubstr("家の管理/スキャナ")); +} + } // namespace test } // namespace url_launcher_windows diff --git a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp index b737b4579b8b..373e1f361d6a 100644 --- a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp +++ b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp @@ -99,7 +99,7 @@ ErrorOr UrlLauncherPlugin::CanLaunchUrl(const std::string& url) { } ErrorOr UrlLauncherPlugin::LaunchUrl(const std::string& url) { - std::wstring url_wide; + std::string url_to_open; if (url.find("file:") == 0) { // ShellExecuteW does not process %-encoded UTF8 strings in file URLs. DWORD unescaped_len = 0; @@ -108,14 +108,15 @@ ErrorOr UrlLauncherPlugin::LaunchUrl(const std::string& url) { &unescaped_len, URL_UNESCAPE_INPLACE))) { return FlutterError("open_error", "Failed to unescape file URL"); } - url_wide = Utf16FromUtf8(unescaped_url); + url_to_open = unescaped_url; } else { - url_wide = Utf16FromUtf8(url); + url_to_open = url; } - int status = static_cast(reinterpret_cast( - system_apis_->ShellExecuteW(nullptr, TEXT("open"), url_wide.c_str(), - nullptr, nullptr, SW_SHOWNORMAL))); + int status = + static_cast(reinterpret_cast(system_apis_->ShellExecuteW( + nullptr, TEXT("open"), Utf16FromUtf8(url_to_open).c_str(), nullptr, + nullptr, SW_SHOWNORMAL))); // Per ::ShellExecuteW documentation, anything >32 indicates success. if (status <= 32) { @@ -126,8 +127,8 @@ ErrorOr UrlLauncherPlugin::LaunchUrl(const std::string& url) { return false; } std::ostringstream error_message; - error_message << "Failed to open " << url << ": ShellExecute error code " - << status; + error_message << "Failed to open " << url_to_open + << ": ShellExecute error code " << status; return FlutterError("open_error", error_message.str()); } return true;