Bug 1692971 [wpt PR 27638] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / widget / windows / tests / TestUriValidation.cpp
blobd8a0ca09cec47bdc842f1b0f69bf8c6722f1b02e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #define MOZ_USE_LAUNCHER_ERROR
9 #define UNICODE
10 #include "mozilla/UrlmonHeaderOnlyUtils.h"
11 #include "TestUrisToValidate.h"
13 #include <urlmon.h>
15 using namespace mozilla;
17 static LauncherResult<_bstr_t> ShellValidateUri(const wchar_t* aUri) {
18 LauncherResult<UniqueAbsolutePidl> pidlResult = ShellParseDisplayName(aUri);
19 if (pidlResult.isErr()) {
20 return pidlResult.propagateErr();
22 UniqueAbsolutePidl pidl = pidlResult.unwrap();
24 // |pidl| is an absolute path. IShellFolder::GetDisplayNameOf requires a
25 // valid child ID, so the first thing we need to resolve is the IShellFolder
26 // for |pidl|'s parent, as well as the childId that represents |pidl|.
27 // Fortunately SHBindToParent does exactly that!
28 PCUITEMID_CHILD childId = nullptr;
29 RefPtr<IShellFolder> parentFolder;
30 HRESULT hr = SHBindToParent(pidl.get(), IID_IShellFolder,
31 getter_AddRefs(parentFolder), &childId);
32 if (FAILED(hr)) {
33 return LAUNCHER_ERROR_FROM_HRESULT(hr);
36 // Now we retrieve the display name of |childId|, telling the shell that we
37 // plan to have the string parsed.
38 STRRET strret;
39 hr = parentFolder->GetDisplayNameOf(childId, SHGDN_FORPARSING, &strret);
40 if (FAILED(hr)) {
41 return LAUNCHER_ERROR_FROM_HRESULT(hr);
44 // StrRetToBSTR automatically takes care of freeing any dynamically
45 // allocated memory in |strret|.
46 _bstr_t bstrUri;
47 hr = StrRetToBSTR(&strret, nullptr, bstrUri.GetAddress());
48 if (FAILED(hr)) {
49 return LAUNCHER_ERROR_FROM_HRESULT(hr);
52 return bstrUri;
55 static LauncherResult<_bstr_t> GetFragment(const wchar_t* aUri) {
56 constexpr DWORD flags =
57 Uri_CREATE_NO_DECODE_EXTRA_INFO | Uri_CREATE_CANONICALIZE |
58 Uri_CREATE_CRACK_UNKNOWN_SCHEMES | Uri_CREATE_PRE_PROCESS_HTML_URI |
59 Uri_CREATE_IE_SETTINGS;
60 RefPtr<IUri> uri;
61 HRESULT hr = CreateUri(aUri, flags, 0, getter_AddRefs(uri));
62 if (FAILED(hr)) {
63 return LAUNCHER_ERROR_FROM_HRESULT(hr);
66 _bstr_t bstrFragment;
67 hr = uri->GetFragment(bstrFragment.GetAddress());
68 if (FAILED(hr)) {
69 return LAUNCHER_ERROR_FROM_HRESULT(hr);
71 return bstrFragment;
74 static bool RunSingleTest(const wchar_t* aUri) {
75 LauncherResult<_bstr_t> uriOld = ShellValidateUri(aUri),
76 uriNew = UrlmonValidateUri(aUri);
77 if (uriOld.isErr() != uriNew.isErr()) {
78 printf("TEST-FAILED | UriValidation | Validation result mismatch on %S\n",
79 aUri);
80 return false;
83 if (uriOld.isErr()) {
84 if (uriOld.unwrapErr().mError != uriNew.unwrapErr().mError) {
85 printf("TEST-FAILED | UriValidation | Error code mismatch on %S\n", aUri);
86 return false;
88 return true;
91 LauncherResult<_bstr_t> bstrFragment = GetFragment(aUri);
92 if (bstrFragment.isErr()) {
93 printf("TEST-FAILED | UriValidation | Failed to get a fragment from %S\n",
94 aUri);
95 return false;
98 // We validate a uri with two logics: the current one UrlmonValidateUri and
99 // the older one ShellValidateUri, to make sure the same validation result.
100 // We introduced UrlmonValidateUri because ShellValidateUri drops a fragment
101 // in a uri due to the design of Windows. To bypass the fragment issue, we
102 // extract a fragment and appends it into the validated string, and compare.
103 _bstr_t bstrUriOldCorrected = uriOld.unwrap() + bstrFragment.unwrap();
104 const _bstr_t& bstrUriNew = uriNew.unwrap();
105 if (bstrUriOldCorrected != bstrUriNew) {
106 printf("TEST-FAILED | UriValidation | %S %S %S\n", aUri,
107 static_cast<const wchar_t*>(bstrUriOldCorrected),
108 static_cast<const wchar_t*>(bstrUriNew));
109 return false;
112 return true;
115 int wmain(int argc, wchar_t* argv[]) {
116 HRESULT hr = CoInitialize(nullptr);
117 if (FAILED(hr)) {
118 return 1;
121 bool isOk = true;
123 if (argc == 2) {
124 isOk = RunSingleTest(argv[1]);
125 } else {
126 for (const wchar_t*& testUri : kTestUris) {
127 if (!RunSingleTest(testUri)) {
128 isOk = false;
133 CoUninitialize();
134 return isOk ? 0 : 1;