Commit d2a0da17 authored by Thomas Mullaly's avatar Thomas Mullaly Committed by Alexandre Julliard

urlmon: Implemented canonicalization of IUriBuilder components.

parent bc3f8bb0
......@@ -4520,9 +4520,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"username",NULL,Uri_PROPERTY_USER_NAME,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://username:password@google.com/?query=x#fragment",S_OK},
{"username:password@google.com",S_OK},
......@@ -4552,9 +4552,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"test",NULL,Uri_PROPERTY_SCHEME_NAME,S_OK,FALSE}
},
{TRUE,TRUE,120,S_OK,FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"test://google.com:120/",S_OK},
{"google.com:120",S_OK},
......@@ -4586,9 +4586,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,NULL,NULL,Uri_PROPERTY_PATH,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://[::192.2.3.4]/",S_OK},
{"[::192.2.3.4]",S_OK},
......@@ -4618,9 +4618,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"Frag","#Frag",Uri_PROPERTY_FRAGMENT,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/#Frag",S_OK},
{"google.com",S_OK},
......@@ -4650,9 +4650,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"","#",Uri_PROPERTY_FRAGMENT,S_OK,FALSE},
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/#",S_OK},
{"google.com",S_OK},
......@@ -4682,9 +4682,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,":password",NULL,Uri_PROPERTY_PASSWORD,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://::password@google.com/",S_OK},
{"::password@google.com",S_OK},
......@@ -4714,9 +4714,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"password",NULL,Uri_PROPERTY_PASSWORD,S_OK,FALSE}
},
{FALSE},
Uri_CREATE_ALLOW_RELATIVE,S_OK,TRUE,
0,S_OK,TRUE,
Uri_CREATE_ALLOW_RELATIVE,0,0,S_OK,TRUE,
Uri_CREATE_ALLOW_RELATIVE,S_OK,FALSE,
0,S_OK,FALSE,
Uri_CREATE_ALLOW_RELATIVE,0,0,S_OK,FALSE,
{
{":password@test/test",S_OK},
{":password@",S_OK},
......@@ -4746,9 +4746,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"test/test",NULL,Uri_PROPERTY_PATH,S_OK,FALSE},
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/test/test",S_OK},
{"google.com",S_OK},
......@@ -4778,9 +4778,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"test",NULL,Uri_PROPERTY_PATH,S_OK,FALSE},
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"zip:test",S_OK},
{"",S_FALSE},
......@@ -4811,9 +4811,9 @@ static const uri_builder_test uri_builder_tests[] = {
},
/* 555 will be returned from GetPort even though FALSE was passed as the hasPort parameter. */
{TRUE,FALSE,555,S_OK,FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/",S_OK},
{"google.com",S_OK},
......@@ -4847,9 +4847,9 @@ static const uri_builder_test uri_builder_tests[] = {
* you'll get 122345 instead.
*/
{TRUE,122345,222,S_OK,FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com:222/",S_OK},
{"google.com:222",S_OK},
......@@ -4880,9 +4880,9 @@ static const uri_builder_test uri_builder_tests[] = {
{FALSE},
},
{TRUE,TRUE,999999,S_OK,FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com:999999/",S_OK},
{"google.com:999999",S_OK},
......@@ -4913,9 +4913,9 @@ static const uri_builder_test uri_builder_tests[] = {
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/?test",S_OK},
{"google.com",S_OK},
......@@ -4979,9 +4979,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"google.com",NULL,Uri_PROPERTY_HOST,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://google.com/",S_OK},
{"google.com",S_OK},
......@@ -5110,9 +5110,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"#Fr<|>g",NULL,Uri_PROPERTY_FRAGMENT,S_OK,FALSE}
},
{FALSE},
-1,S_OK,TRUE,
0,S_OK,TRUE,
Uri_CREATE_NO_DECODE_EXTRA_INFO,UriBuilder_USE_ORIGINAL_FLAGS,0,S_OK,TRUE,
-1,S_OK,FALSE,
0,S_OK,FALSE,
Uri_CREATE_NO_DECODE_EXTRA_INFO,UriBuilder_USE_ORIGINAL_FLAGS,0,S_OK,FALSE,
{
{"http://google.com/#Fr%3C%7C%3Eg",S_OK},
{"google.com",S_OK},
......@@ -5143,8 +5143,8 @@ static const uri_builder_test uri_builder_tests[] = {
},
{FALSE},
Uri_CREATE_CANONICALIZE|Uri_CREATE_NO_CANONICALIZE,E_INVALIDARG,FALSE,
0,S_OK,TRUE,
Uri_CREATE_CANONICALIZE|Uri_CREATE_NO_CANONICALIZE,UriBuilder_USE_ORIGINAL_FLAGS,0,S_OK,TRUE,
0,S_OK,FALSE,
Uri_CREATE_CANONICALIZE|Uri_CREATE_NO_CANONICALIZE,UriBuilder_USE_ORIGINAL_FLAGS,0,S_OK,FALSE,
{
{"http://google.com/#Fr%3C%7C%3Eg",S_OK},
{"google.com",S_OK},
......@@ -5325,9 +5325,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"winehq.org:test",NULL,Uri_PROPERTY_HOST,S_OK,FALSE},
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http://winehq.org:test/",S_OK},
{"winehq.org:test",S_OK},
......@@ -5391,9 +5391,9 @@ static const uri_builder_test uri_builder_tests[] = {
{TRUE,"",NULL,Uri_PROPERTY_HOST,S_OK,FALSE}
},
{FALSE},
0,S_OK,TRUE,
0,S_OK,TRUE,
0,0,0,S_OK,TRUE,
0,S_OK,FALSE,
0,S_OK,FALSE,
0,0,0,S_OK,FALSE,
{
{"http:///",S_OK},
{"",S_OK},
......@@ -5466,15 +5466,15 @@ typedef struct _uri_builder_remove_test {
static const uri_builder_remove_test uri_builder_remove_tests[] = {
{ "http://google.com/test?test=y#Frag",0,S_OK,FALSE,
Uri_HAS_FRAGMENT|Uri_HAS_PATH|Uri_HAS_QUERY,S_OK,FALSE,
"http://google.com/",0,S_OK,TRUE
"http://google.com/",0,S_OK,FALSE
},
{ "http://user:pass@winehq.org/",0,S_OK,FALSE,
Uri_HAS_USER_NAME|Uri_HAS_PASSWORD,S_OK,FALSE,
"http://winehq.org/",0,S_OK,TRUE
"http://winehq.org/",0,S_OK,FALSE
},
{ "zip://google.com?Test=x",0,S_OK,FALSE,
Uri_HAS_HOST,S_OK,FALSE,
"zip:/?Test=x",0,S_OK,TRUE
"zip:/?Test=x",0,S_OK,FALSE
},
/* Doesn't remove the whole userinfo component. */
{ "http://username:pass@google.com/",0,S_OK,FALSE,
......@@ -8400,14 +8400,10 @@ static void test_IUriBuilder_IUriProperty(void) {
*/
test = NULL;
hr = IUriBuilder_CreateUri(builder, Uri_CREATE_ALLOW_RELATIVE, 0, 0, &test);
todo_wine {
ok(hr == S_OK, "Error: IUriBuilder_CreateUri returned 0x%08x, expected 0x%08x.\n", hr, S_OK);
}
if(SUCCEEDED(hr)) {
todo_wine {
ok(test != uri, "Error: Wasn't expecting 'test' to be 'uri'\n");
}
}
ok(hr == S_OK, "Error: IUriBuilder_CreateUri returned 0x%08x, expected 0x%08x.\n", hr, S_OK);
if(SUCCEEDED(hr))
ok(test != uri, "Error: Wasn't expecting 'test' to be 'uri'\n");
if(test) IUri_Release(test);
/* Still returns the same IUri, even though the base one wasn't created with CREATE_CANONICALIZE
......@@ -8452,14 +8448,10 @@ static void test_IUriBuilder_IUriProperty(void) {
*/
test = NULL;
hr = IUriBuilder_CreateUriWithFlags(builder, Uri_CREATE_ALLOW_RELATIVE, 0, 0, 0, &test);
todo_wine {
ok(hr == S_OK, "Error: IUriBuilder_CreateUriWithFlags returned 0x%08x, expected 0x%08x.\n", hr, S_OK);
}
if(SUCCEEDED(hr)) {
todo_wine {
ok(test != uri, "Error: Wasn't expecting 'test' to be 'uri'\n");
}
}
ok(hr == S_OK, "Error: IUriBuilder_CreateUriWithFlags returned 0x%08x, expected 0x%08x.\n", hr, S_OK);
if(SUCCEEDED(hr))
ok(test != uri, "Error: Wasn't expecting 'test' to be 'uri'\n");
if(test) IUri_Release(test);
/* Still returns the same IUri, even though the base one wasn't created with CREATE_CANONICALIZE
......
......@@ -62,7 +62,7 @@ typedef struct {
DWORD host_len;
Uri_HOST_TYPE host_type;
USHORT port;
DWORD port;
BOOL has_port;
INT authority_start;
......@@ -1329,19 +1329,13 @@ static BOOL parse_username(const WCHAR **ptr, parse_data *data, DWORD flags, DWO
}
static BOOL parse_password(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
const WCHAR *start = *ptr;
if(**ptr != ':')
return TRUE;
++(*ptr);
data->password = *ptr;
while(**ptr != '@') {
if(**ptr == '%') {
if(!check_pct_encoded(ptr)) {
if(data->scheme_type != URL_SCHEME_UNKNOWN) {
*ptr = start;
*ptr = data->password;
data->password = NULL;
return FALSE;
}
......@@ -1350,7 +1344,7 @@ static BOOL parse_password(const WCHAR **ptr, parse_data *data, DWORD flags, DWO
} else if(extras & ALLOW_NULL_TERM_PASSWORD && !**ptr)
break;
else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
*ptr = start;
*ptr = data->password;
data->password = NULL;
return FALSE;
}
......@@ -1389,12 +1383,15 @@ static void parse_userinfo(const WCHAR **ptr, parse_data *data, DWORD flags) {
return;
}
if(!parse_password(ptr, data, flags, 0)) {
*ptr = start;
data->username = NULL;
data->username_len = 0;
TRACE("(%p %p %x): URI contained no userinfo.\n", ptr, data, flags);
return;
if(**ptr == ':') {
++(*ptr);
if(!parse_password(ptr, data, flags, 0)) {
*ptr = start;
data->username = NULL;
data->username_len = 0;
TRACE("(%p %p %x): URI contained no userinfo.\n", ptr, data, flags);
return;
}
}
if(**ptr != '@') {
......@@ -2840,7 +2837,7 @@ static BOOL canonicalize_authority(const parse_data *data, Uri *uri, DWORD flags
if(!canonicalize_port(data, uri, flags, computeOnly))
return FALSE;
if(uri->host_start != -1)
if(uri->host_start != -1 || (data->is_relative && (data->password || data->username)))
uri->authority_len = uri->canon_len - uri->authority_start;
else
uri->authority_start = -1;
......@@ -3135,9 +3132,15 @@ static BOOL canonicalize_path_opaque(const parse_data *data, Uri *uri, DWORD fla
static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
uri->display_absolute = TRUE;
if(!data->is_opaque) {
/* "//" is only added for non-wildcard scheme types. */
if(data->scheme_type != URL_SCHEME_WILDCARD) {
if(!data->is_opaque || (data->is_relative && (data->password || data->username))) {
/* "//" is only added for non-wildcard scheme types.
*
* A "//" is only added to a relative URI if it has a
* host or port component (this only happens if a IUriBuilder
* is generating an IUri).
*/
if((data->is_relative && (data->host || data->has_port)) ||
(!data->is_relative && data->scheme_type != URL_SCHEME_WILDCARD)) {
if(!computeOnly) {
INT pos = uri->canon_len;
......@@ -3150,10 +3153,13 @@ static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags,
if(!canonicalize_authority(data, uri, flags, computeOnly))
return FALSE;
/* TODO: Canonicalize the path of the URI. */
if(!canonicalize_path_hierarchical(data, uri, flags, computeOnly))
return FALSE;
if(data->is_relative && (data->password || data->username)) {
if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
return FALSE;
} else {
if(!canonicalize_path_hierarchical(data, uri, flags, computeOnly))
return FALSE;
}
} else {
/* Opaque URI's don't have an authority. */
uri->userinfo_start = uri->userinfo_split = -1;
......@@ -4019,6 +4025,7 @@ static DWORD generate_raw_uri(const parse_data *data, BSTR uri) {
}
static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, Uri *uri, DWORD flags) {
HRESULT hr;
DWORD length = generate_raw_uri(data, NULL);
uri->raw_uri = SysAllocStringLen(NULL, length);
if(!uri->raw_uri)
......@@ -4026,65 +4033,14 @@ static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, U
generate_raw_uri(data, uri->raw_uri);
return E_NOTIMPL;
}
static HRESULT build_uri(const UriBuilder *builder, IUri **uri, DWORD create_flags,
DWORD use_orig_flags, DWORD encoding_mask)
{
HRESULT hr;
parse_data data;
Uri *ret;
if(!uri)
return E_POINTER;
if(encoding_mask && (!builder->uri || builder->modified_props)) {
*uri = NULL;
return E_NOTIMPL;
}
/* Decide what flags should be used when creating the Uri. */
if((use_orig_flags & UriBuilder_USE_ORIGINAL_FLAGS) && builder->uri)
create_flags = builder->uri->create_flags;
else {
if(has_invalid_flag_combination(create_flags)) {
*uri = NULL;
return E_INVALIDARG;
}
/* Set the default flags if they don't cause a conflict. */
apply_default_flags(&create_flags);
}
/* Return the base IUri if no changes have been made and the create_flags match. */
if(builder->uri && !builder->modified_props && builder->uri->create_flags == create_flags) {
*uri = URI(builder->uri);
IUri_AddRef(*uri);
return S_OK;
}
hr = validate_components(builder, &data, create_flags);
hr = canonicalize_uri(data, uri, flags);
if(FAILED(hr)) {
*uri = NULL;
return hr;
}
ret = heap_alloc_zero(sizeof(Uri));
if(!ret) {
*uri = NULL;
return E_OUTOFMEMORY;
}
hr = generate_uri(builder, &data, ret, create_flags);
if(FAILED(hr)) {
SysFreeString(ret->raw_uri);
heap_free(ret->canon_uri);
heap_free(ret);
*uri = NULL;
if(hr == E_INVALIDARG)
return INET_E_INVALID_URL;
return hr;
}
uri->create_flags = flags;
return S_OK;
}
......@@ -4907,6 +4863,16 @@ static const IUriVtbl UriVtbl = {
Uri_IsEqual
};
static Uri* create_uri_obj(void) {
Uri *ret = heap_alloc_zero(sizeof(Uri));
if(ret) {
ret->lpIUriVtbl = &UriVtbl;
ret->ref = 1;
}
return ret;
}
/***********************************************************************
* CreateUri (urlmon.@)
*
......@@ -5084,6 +5050,64 @@ HRESULT WINAPI CreateUriWithFragment(LPCWSTR pwzURI, LPCWSTR pwzFragment, DWORD
return hres;
}
static HRESULT build_uri(const UriBuilder *builder, IUri **uri, DWORD create_flags,
DWORD use_orig_flags, DWORD encoding_mask)
{
HRESULT hr;
parse_data data;
Uri *ret;
if(!uri)
return E_POINTER;
if(encoding_mask && (!builder->uri || builder->modified_props)) {
*uri = NULL;
return E_NOTIMPL;
}
/* Decide what flags should be used when creating the Uri. */
if((use_orig_flags & UriBuilder_USE_ORIGINAL_FLAGS) && builder->uri)
create_flags = builder->uri->create_flags;
else {
if(has_invalid_flag_combination(create_flags)) {
*uri = NULL;
return E_INVALIDARG;
}
/* Set the default flags if they don't cause a conflict. */
apply_default_flags(&create_flags);
}
/* Return the base IUri if no changes have been made and the create_flags match. */
if(builder->uri && !builder->modified_props && builder->uri->create_flags == create_flags) {
*uri = URI(builder->uri);
IUri_AddRef(*uri);
return S_OK;
}
hr = validate_components(builder, &data, create_flags);
if(FAILED(hr)) {
*uri = NULL;
return hr;
}
ret = create_uri_obj();
if(!ret) {
*uri = NULL;
return E_OUTOFMEMORY;
}
hr = generate_uri(builder, &data, ret, create_flags);
if(FAILED(hr)) {
IUri_Release(URI(ret));
*uri = NULL;
return hr;
}
*uri = URI(ret);
return S_OK;
}
#define URIBUILDER_THIS(iface) DEFINE_THIS(UriBuilder, IUriBuilder, iface)
static HRESULT WINAPI UriBuilder_QueryInterface(IUriBuilder *iface, REFIID riid, void **ppv)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment