From: Zhiyi Zhang <zzhang@codeweavers.com> --- dlls/iertutil/main.c | 2 +- dlls/iertutil/private.h | 4 + dlls/iertutil/tests/iertutil.c | 2 + dlls/iertutil/uri.c | 179 ++++++++++++++++++++++++++------- 4 files changed, 152 insertions(+), 35 deletions(-) diff --git a/dlls/iertutil/main.c b/dlls/iertutil/main.c index 0ad7e38ddfb..83f70be4a12 100644 --- a/dlls/iertutil/main.c +++ b/dlls/iertutil/main.c @@ -415,7 +415,7 @@ static HRESULT STDMETHODCALLTYPE uri_factory_CreateUri(IUriRuntimeClassFactory * return E_POINTER; raw_buffer = WindowsGetStringRawBuffer(uri_string, NULL); - hr = CreateUri(raw_buffer, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME | Uri_CREATE_NO_DECODE_EXTRA_INFO, 0, &uri); + hr = create_uri(raw_buffer, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME | Uri_CREATE_NO_DECODE_EXTRA_INFO | WINE_URI_RUNTIME_CLASS, 0, &uri); if (FAILED(hr)) { *instance = NULL; diff --git a/dlls/iertutil/private.h b/dlls/iertutil/private.h index 5c416aba80a..bf2e363f6cc 100644 --- a/dlls/iertutil/private.h +++ b/dlls/iertutil/private.h @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" #include "winstring.h" +#include "urlmon.h" #include "wine/debug.h" #include "activation.h" @@ -71,6 +72,9 @@ DEFINE_IINSPECTABLE_(pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, \ &impl->base_iface) +#define WINE_URI_RUNTIME_CLASS 0x80000000 /* IUriRuntimeClass URI parser */ + +extern HRESULT create_uri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI); extern HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); #endif /* __WINE_IERTUTIL_PRIVATE_H */ diff --git a/dlls/iertutil/tests/iertutil.c b/dlls/iertutil/tests/iertutil.c index 7acd31047fa..dc157f46caa 100644 --- a/dlls/iertutil/tests/iertutil.c +++ b/dlls/iertutil/tests/iertutil.c @@ -233,6 +233,8 @@ static void test_IUriRuntimeClass(void) {L"ftp://us er:pass word@exam ple.com/pa th?qu ery=val ue#frag ment", L"ftp://us er:pass word@exam ple.com/pa th?qu ery=val ue#frag ment", L"ftp://us%20er:pass%20word@exam%20ple.com/pa%20th?qu ery=val ue#frag ment", L"ftp://exam%20ple.com/pa%20th?qu ery=val ue#frag ment", L"exam%20ple.com", NULL, L"#frag ment", L"exam%20ple.com", L"pass%20word", L"/pa%20th", L"?qu ery=val ue", L"ftp", L"us%20er", 21}, {L"file://a b/c d", L"file://a b/c d", L"file://a%20b/c%20d", L"file://a%20b/c%20d", NULL, NULL, NULL, L"a%20b", NULL, L"/c%20d", NULL, L"file", NULL, -1}, {L"http://example.com/path/to /resource", L"http://example.com/path/to /resource", L"http://example.com/path/to%20/resource", L"http://example.com/path/to%20/resource", L"example.com", NULL, NULL, L"example.com", NULL, L"/path/to%20/resource", NULL, L"http", NULL, 80}, + /* Punycode */ + {L"http://xn--0zwm56d.example.com/", L"http://xn--0zwm56d.example.com/", L"http://\u6d4b\u8bd5.example.com/", L"http://\u6d4b\u8bd5.example.com/", L"example.com", NULL, NULL, L"\u6d4b\u8bd5.example.com", NULL, L"/", NULL, L"http", NULL, 80}, /* Unicode */ {L"http://example.com/\u00e4\u00f6\u00fc", L"http://example.com/\u00e4\u00f6\u00fc", L"http://example.com/\u00e4\u00f6\u00fc", L"http://example.com/\u00e4\u00f6\u00fc", L"example.com", NULL, NULL, L"example.com", NULL, L"/\u00e4\u00f6\u00fc", NULL, L"http", NULL, 80}, /* Miscellaneous tests */ diff --git a/dlls/iertutil/uri.c b/dlls/iertutil/uri.c index 7a32b6f0f4e..e15b4d7f25a 100644 --- a/dlls/iertutil/uri.c +++ b/dlls/iertutil/uri.c @@ -691,6 +691,66 @@ static WCHAR *strdupwn(const WCHAR *str, DWORD length) return ret; } +static WCHAR *strdupwn_lower(const WCHAR *src, DWORD len) +{ + WCHAR *dst = strdupwn(src, len); + DWORD i; + + if (!dst) + return NULL; + + for (i = 0; i < len; i++) + dst[i] = towlower(dst[i]); + + return dst; +} + +/* Duplicate string, percent-encoding ASCII characters that are not unreserved or reserved according + * to RFC 3986, while preserving existing valid %XX sequences. Free the result when it's done */ +static WCHAR *pct_encode_forbidden(const WCHAR *src, DWORD src_len, DWORD *out_len) +{ + DWORD i, j, extra = 0; + WCHAR *dst; + + for (i = 0; i < src_len; i++) + { + if (src[i] == '%' && i+2 < src_len && is_hexdigit(src[i+1]) && is_hexdigit(src[i+2])) + { + i += 2; + continue; + } + if (is_ascii(src[i]) && !is_unreserved(src[i]) && !is_reserved(src[i])) + extra += 2; + } + + *out_len = src_len+extra; + dst = malloc((*out_len+1)*sizeof(WCHAR)); + if (!dst) + return NULL; + + for (i = 0, j = 0; i < src_len; i++) + { + if (src[i] == '%' && i+2 < src_len && is_hexdigit(src[i+1]) && is_hexdigit(src[i+2])) + { + dst[j++] = src[i++]; + dst[j++] = src[i++]; + dst[j++] = src[i]; + continue; + } + if (is_ascii(src[i]) && !is_unreserved(src[i]) && !is_reserved(src[i])) + { + pct_encode_val(src[i], dst + j); + j += 3; + } + else + { + dst[j++] = src[i]; + } + } + dst[j] = 0; + return dst; +} + /* Removes all the leading and trailing white spaces or * control characters from the URI and removes all control * characters inside of the URI string. @@ -2004,6 +2064,51 @@ static BOOL canonicalize_reg_name(const parse_data *data, Uri *uri, } } + if(flags & WINE_URI_RUNTIME_CLASS) { + uri->host_start = uri->canon_len; + + if(is_hierarchical_scheme(data->scheme_type)) { + DWORD encoded_len, lower_len; + WCHAR *encoded, *lower; + int decoded_len; + + lower = strdupwn_lower(data->host, data->host_len); + lower_len = data->host_len; + + /* Punycode decode */ + decoded_len = IdnToUnicode(0, lower, lower_len, NULL, 0); + if(decoded_len > 0 && decoded_len != lower_len) { + WCHAR *decoded = malloc(decoded_len * sizeof(WCHAR)); + if(decoded) { + IdnToUnicode(0, lower, lower_len, decoded, decoded_len); + free(lower); + lower = decoded; + lower_len = decoded_len; + } + } + + /* Percent-encode forbidden characters */ + encoded = pct_encode_forbidden(lower, lower_len, &encoded_len); + free(lower); + + if(!computeOnly) + memcpy(uri->canon_uri+uri->canon_len, encoded, encoded_len*sizeof(WCHAR)); + uri->canon_len += encoded_len; + free(encoded); + } else { + if(!computeOnly) + memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR)); + uri->canon_len += data->host_len; + } + + uri->host_len = uri->canon_len-uri->host_start; + + if(!computeOnly) + find_domain_name(uri->canon_uri+uri->host_start, uri->host_len, &uri->domain_offset); + + return TRUE; + } + if(data->scheme_type == URL_SCHEME_FILE && flags & Uri_CREATE_FILE_USE_DOS_PATH) { if(!computeOnly) { uri->canon_uri[uri->canon_len] = '\\'; @@ -5294,37 +5399,8 @@ HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) return S_OK; } -/*********************************************************************** - * CreateUri (iertutil.@) - * - * Creates a new IUri object using the URI represented by pwzURI. This function - * parses and validates the components of pwzURI and then canonicalizes the - * parsed components. - * - * PARAMS - * pwzURI [I] The URI to parse, validate, and canonicalize. - * dwFlags [I] Flags which can affect how the parsing/canonicalization is performed. - * dwReserved [I] Reserved (not used). - * ppURI [O] The resulting IUri after parsing/canonicalization occurs. - * - * RETURNS - * Success: Returns S_OK. ppURI contains the pointer to the newly allocated IUri. - * Failure: E_INVALIDARG if there are invalid flag combinations in dwFlags, or an - * invalid parameter, or pwzURI doesn't represent a valid URI. - * E_OUTOFMEMORY if any memory allocation fails. - * - * NOTES - * Default flags: - * Uri_CREATE_CANONICALIZE, Uri_CREATE_DECODE_EXTRA_INFO, Uri_CREATE_CRACK_UNKNOWN_SCHEMES, - * Uri_CREATE_PRE_PROCESS_HTML_URI, Uri_CREATE_NO_IE_SETTINGS. - */ -HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI) +HRESULT create_uri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI) { - const DWORD supported_flags = Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME| - Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|Uri_CREATE_NO_CANONICALIZE|Uri_CREATE_CANONICALIZE| - Uri_CREATE_DECODE_EXTRA_INFO|Uri_CREATE_NO_DECODE_EXTRA_INFO|Uri_CREATE_CRACK_UNKNOWN_SCHEMES| - Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES|Uri_CREATE_PRE_PROCESS_HTML_URI|Uri_CREATE_NO_PRE_PROCESS_HTML_URI| - Uri_CREATE_NO_IE_SETTINGS|Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS|Uri_CREATE_FILE_USE_DOS_PATH; Uri *ret; HRESULT hr; parse_data data; @@ -5345,10 +5421,6 @@ HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IU return E_INVALIDARG; } - /* Currently unsupported. */ - if(dwFlags & ~supported_flags) - FIXME("Ignoring unsupported flag(s) %lx\n", dwFlags & ~supported_flags); - hr = Uri_Construct(NULL, (void**)&ret); if(FAILED(hr)) { *ppURI = NULL; @@ -5394,6 +5466,45 @@ HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IU return S_OK; } +/*********************************************************************** + * CreateUri (iertutil.@) + * + * Creates a new IUri object using the URI represented by pwzURI. This function + * parses and validates the components of pwzURI and then canonicalizes the + * parsed components. + * + * PARAMS + * pwzURI [I] The URI to parse, validate, and canonicalize. + * dwFlags [I] Flags which can affect how the parsing/canonicalization is performed. + * dwReserved [I] Reserved (not used). + * ppURI [O] The resulting IUri after parsing/canonicalization occurs. + * + * RETURNS + * Success: Returns S_OK. ppURI contains the pointer to the newly allocated IUri. + * Failure: E_INVALIDARG if there are invalid flag combinations in dwFlags, or an + * invalid parameter, or pwzURI doesn't represent a valid URI. + * E_OUTOFMEMORY if any memory allocation fails. + * + * NOTES + * Default flags: + * Uri_CREATE_CANONICALIZE, Uri_CREATE_DECODE_EXTRA_INFO, Uri_CREATE_CRACK_UNKNOWN_SCHEMES, + * Uri_CREATE_PRE_PROCESS_HTML_URI, Uri_CREATE_NO_IE_SETTINGS. + */ +HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI) +{ + const DWORD supported_flags = Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME| + Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|Uri_CREATE_NO_CANONICALIZE|Uri_CREATE_CANONICALIZE| + Uri_CREATE_DECODE_EXTRA_INFO|Uri_CREATE_NO_DECODE_EXTRA_INFO|Uri_CREATE_CRACK_UNKNOWN_SCHEMES| + Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES|Uri_CREATE_PRE_PROCESS_HTML_URI|Uri_CREATE_NO_PRE_PROCESS_HTML_URI| + Uri_CREATE_NO_IE_SETTINGS|Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS|Uri_CREATE_FILE_USE_DOS_PATH; + + /* Currently unsupported. */ + if(dwFlags & ~supported_flags) + FIXME("Ignoring unsupported flag(s) %lx\n", dwFlags & ~supported_flags); + + return create_uri(pwzURI, dwFlags, dwReserved, ppURI); +} + /*********************************************************************** * CreateUriWithFragment (iertutil.@) * -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10542