webservices: Implement WsEncodeUrl.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
24bdad63e4
commit
57e69a6b48
|
@ -188,7 +188,117 @@ static void test_WsDecodeUrl(void)
|
|||
WsFreeHeap( heap );
|
||||
}
|
||||
|
||||
static void test_WsEncodeUrl(void)
|
||||
{
|
||||
static WCHAR host[] = {'h','o','s','t'};
|
||||
static WCHAR host2[] = {'h','o','s','t',' ','2'};
|
||||
static WCHAR path[] = {'/','p','a','t','h'};
|
||||
static WCHAR path2[] = {'/','p','a','t','h',' ','2'};
|
||||
static WCHAR query[] = {'q','u','e','r','y'};
|
||||
static WCHAR query2[] = {'q','u','e','r','y',' ','2'};
|
||||
static WCHAR frag[] = {'f','r','a','g'};
|
||||
static WCHAR frag2[] = {'f','r','a','g',' ','2'};
|
||||
static WCHAR port[] = {'8','0','8','0'};
|
||||
static WCHAR port2[] = {'6','5','5','3','6'};
|
||||
static const WCHAR url1[] = {'h','t','t','p',':','/','/','h','o','s','t'};
|
||||
static const WCHAR url2[] = {'h','t','t','p',':','/','/'};
|
||||
static const WCHAR url3[] = {'h','t','t','p',':','/','/','/','p','a','t','h'};
|
||||
static const WCHAR url4[] = {'h','t','t','p',':','/','/','?','q','u','e','r','y'};
|
||||
static const WCHAR url5[] = {'h','t','t','p',':','/','/','#','f','r','a','g'};
|
||||
static const WCHAR url6[] = {'h','t','t','p',':','/','/','h','o','s','t',':','8','0','8','0',
|
||||
'/','p','a','t','h','?','q','u','e','r','y','#','f','r','a','g'};
|
||||
static const WCHAR url7[] = {'h','t','t','p',':','/','/',':','8','0','8','0'};
|
||||
static const WCHAR url8[] = {'h','t','t','p',':','/','/'};
|
||||
static const WCHAR url9[] = {'h','t','t','p',':','/','/','/','p','a','t','h','%','2','0','2'};
|
||||
static const WCHAR url10[] = {'h','t','t','p',':','/','/','?','q','u','e','r','y','%','2','0','2'};
|
||||
static const WCHAR url11[] = {'h','t','t','p',':','/','/','#','f','r','a','g','%','2','0','2'};
|
||||
static const WCHAR url12[] = {'h','t','t','p',':','/','/','h','o','s','t','%','2','0','2'};
|
||||
static const struct
|
||||
{
|
||||
WS_URL_SCHEME_TYPE scheme;
|
||||
WCHAR *host;
|
||||
ULONG host_len;
|
||||
USHORT port;
|
||||
WCHAR *port_str;
|
||||
ULONG port_len;
|
||||
WCHAR *path;
|
||||
ULONG path_len;
|
||||
WCHAR *query;
|
||||
ULONG query_len;
|
||||
WCHAR *fragment;
|
||||
ULONG fragment_len;
|
||||
HRESULT hr;
|
||||
ULONG len;
|
||||
const WCHAR *chars;
|
||||
}
|
||||
tests[] =
|
||||
{
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, host, 4, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, S_OK, 11, url1 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, S_OK, 7, url2 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, path, 5, NULL, 0, NULL, 0, S_OK, 12, url3 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, NULL, 0, query, 5, NULL, 0, S_OK, 13, url4 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0, frag, 4, S_OK, 12, url5 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, host, 4, 0, port, 4, path, 5, query, 5, frag, 4, S_OK, 32, url6 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 8080, NULL, 0, NULL, 0, NULL, 0, NULL, 0, S_OK, 12, url7 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, port, 4, NULL, 0, NULL, 0, NULL, 0, S_OK, 12, url7 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 8080, port, 4, NULL, 0, NULL, 0, NULL, 0, S_OK, 12, url7 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 8181, port, 4, NULL, 0, NULL, 0, NULL, 0, E_INVALIDARG, 0, NULL },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, port2, 5, NULL, 0, NULL, 0, NULL, 0, WS_E_INVALID_FORMAT, 0, NULL },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 80, NULL, 0, NULL, 0, NULL, 0, NULL, 0, S_OK, 7, url8 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, path2, 7, NULL, 0, NULL, 0, S_OK, 16, url9 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, NULL, 0, query2, 7, NULL, 0, S_OK, 17, url10 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0, frag2, 6, S_OK, 16, url11 },
|
||||
{ WS_URL_HTTP_SCHEME_TYPE, host2, 6, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, S_OK, 15, url12 },
|
||||
};
|
||||
WS_HEAP *heap;
|
||||
WS_STRING str;
|
||||
WS_HTTP_URL url;
|
||||
HRESULT hr;
|
||||
UINT i;
|
||||
|
||||
hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
|
||||
ok( hr == S_OK, "got %08x\n", hr );
|
||||
|
||||
hr = WsEncodeUrl( NULL, 0, heap, &str, NULL );
|
||||
ok( hr == E_INVALIDARG, "got %08x\n", hr );
|
||||
|
||||
hr = WsEncodeUrl( (const WS_URL *)&url, 0, NULL, &str, NULL );
|
||||
ok( hr == E_INVALIDARG, "got %08x\n", hr );
|
||||
|
||||
hr = WsEncodeUrl( (const WS_URL *)&url, 0, heap, NULL, NULL );
|
||||
ok( hr == E_INVALIDARG, "got %08x\n", hr );
|
||||
|
||||
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
|
||||
{
|
||||
memset( &url, 0, sizeof(url) );
|
||||
url.url.scheme = tests[i].scheme;
|
||||
url.host.chars = tests[i].host;
|
||||
url.host.length = tests[i].host_len;
|
||||
url.port = tests[i].port;
|
||||
url.portAsString.chars = tests[i].port_str;
|
||||
url.portAsString.length = tests[i].port_len;
|
||||
url.path.chars = tests[i].path;
|
||||
url.path.length = tests[i].path_len;
|
||||
url.query.chars = tests[i].query;
|
||||
url.query.length = tests[i].query_len;
|
||||
url.fragment.chars = tests[i].fragment;
|
||||
url.fragment.length = tests[i].fragment_len;
|
||||
|
||||
memset( &str, 0, sizeof(str) );
|
||||
hr = WsEncodeUrl( (const WS_URL *)&url, 0, heap, &str, NULL );
|
||||
ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
|
||||
if (hr != S_OK) continue;
|
||||
|
||||
ok( str.length == tests[i].len, "%u: got %u\n", i, str.length );
|
||||
ok( !memcmp( str.chars, tests[i].chars, tests[i].len * sizeof(WCHAR) ),
|
||||
"%u: wrong url %s\n", i, wine_dbgstr_wn(str.chars, str.length) );
|
||||
}
|
||||
|
||||
WsFreeHeap( heap );
|
||||
}
|
||||
|
||||
START_TEST(url)
|
||||
{
|
||||
test_WsDecodeUrl();
|
||||
test_WsEncodeUrl();
|
||||
}
|
||||
|
|
|
@ -212,3 +212,272 @@ error:
|
|||
ws_free( heap, url );
|
||||
return hr;
|
||||
}
|
||||
|
||||
static const WCHAR *scheme_str( WS_URL_SCHEME_TYPE scheme, ULONG *len )
|
||||
{
|
||||
switch (scheme)
|
||||
{
|
||||
case WS_URL_HTTP_SCHEME_TYPE:
|
||||
*len = sizeof(http)/sizeof(http[0]);
|
||||
return http;
|
||||
|
||||
case WS_URL_HTTPS_SCHEME_TYPE:
|
||||
*len = sizeof(https)/sizeof(https[0]);
|
||||
return https;
|
||||
|
||||
case WS_URL_NETTCP_SCHEME_TYPE:
|
||||
*len = sizeof(nettcp)/sizeof(nettcp[0]);
|
||||
return nettcp;
|
||||
|
||||
case WS_URL_SOAPUDP_SCHEME_TYPE:
|
||||
*len = sizeof(soapudp)/sizeof(soapudp[0]);
|
||||
return soapudp;
|
||||
|
||||
case WS_URL_NETPIPE_SCHEME_TYPE:
|
||||
*len = sizeof(netpipe)/sizeof(netpipe[0]);
|
||||
return netpipe;
|
||||
|
||||
default:
|
||||
ERR( "unhandled scheme %u\n", scheme );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline ULONG escape_size( unsigned char ch, const char *except )
|
||||
{
|
||||
const char *p = except;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == ch) return 1;
|
||||
p++;
|
||||
}
|
||||
if ((ch >= 'a' && ch <= 'z' ) || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) return 1;
|
||||
if (ch < 33 || ch > 126) return 3;
|
||||
switch (ch)
|
||||
{
|
||||
case '/':
|
||||
case '?':
|
||||
case '"':
|
||||
case '#':
|
||||
case '%':
|
||||
case '<':
|
||||
case '>':
|
||||
case '\\':
|
||||
case '[':
|
||||
case ']':
|
||||
case '^':
|
||||
case '`':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
return 3;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static char *strdup_utf8( const WCHAR *str, ULONG len, ULONG *ret_len )
|
||||
{
|
||||
char *ret;
|
||||
*ret_len = WideCharToMultiByte( CP_UTF8, 0, str, len, NULL, 0, NULL, NULL );
|
||||
if ((ret = heap_alloc( *ret_len )))
|
||||
WideCharToMultiByte( CP_UTF8, 0, str, len, ret, *ret_len, NULL, NULL );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT url_encode_size( const WCHAR *str, ULONG len, const char *except, ULONG *ret_len )
|
||||
{
|
||||
ULONG i, len_utf8;
|
||||
BOOL convert = FALSE;
|
||||
char *utf8;
|
||||
|
||||
*ret_len = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (str[i] > 159)
|
||||
{
|
||||
convert = TRUE;
|
||||
break;
|
||||
}
|
||||
*ret_len += escape_size( str[i], except );
|
||||
}
|
||||
if (!convert) return S_OK;
|
||||
|
||||
*ret_len = 0;
|
||||
if (!(utf8 = strdup_utf8( str, len, &len_utf8 ))) return E_OUTOFMEMORY;
|
||||
for (i = 0; i < len_utf8; i++) *ret_len += escape_size( utf8[i], except );
|
||||
heap_free( utf8 );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG url_encode_byte( unsigned char byte, const char *except, WCHAR *buf )
|
||||
{
|
||||
static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
switch (escape_size( byte, except ))
|
||||
{
|
||||
case 3:
|
||||
buf[0] = '%';
|
||||
buf[1] = hex[(byte >> 4) & 0xf];
|
||||
buf[2] = hex[byte & 0xf];
|
||||
return 3;
|
||||
|
||||
case 1:
|
||||
buf[0] = byte;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
ERR( "unhandled escape size\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static HRESULT url_encode( const WCHAR *str, ULONG len, WCHAR *buf, const char *except, ULONG *ret_len )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ULONG i, len_utf8, len_enc;
|
||||
BOOL convert = FALSE;
|
||||
WCHAR *p = buf;
|
||||
char *utf8;
|
||||
|
||||
*ret_len = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (str[i] > 159)
|
||||
{
|
||||
convert = TRUE;
|
||||
break;
|
||||
}
|
||||
len_enc = url_encode_byte( str[i], except, p );
|
||||
*ret_len += len_enc;
|
||||
p += len_enc;
|
||||
}
|
||||
if (!convert) return S_OK;
|
||||
|
||||
p = buf;
|
||||
*ret_len = 0;
|
||||
if (!(utf8 = strdup_utf8( str, len, &len_utf8 ))) return E_OUTOFMEMORY;
|
||||
for (i = 0; i < len_utf8; i++)
|
||||
{
|
||||
len_enc = url_encode_byte( utf8[i], except, p );
|
||||
*ret_len += len_enc;
|
||||
p += len_enc;
|
||||
}
|
||||
|
||||
heap_free( utf8 );
|
||||
return hr;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* WsEncodeUrl [webservices.@]
|
||||
*/
|
||||
HRESULT WINAPI WsEncodeUrl( const WS_URL *base, ULONG flags, WS_HEAP *heap, WS_STRING *ret,
|
||||
WS_ERROR *error )
|
||||
{
|
||||
static const WCHAR fmtW[] = {':','%','u',0};
|
||||
ULONG len = 0, len_scheme, len_enc;
|
||||
const WS_HTTP_URL *url = (const WS_HTTP_URL *)base;
|
||||
const WCHAR *scheme;
|
||||
WCHAR *str, *p, *q;
|
||||
ULONG port = 0;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE( "%p %08x %p %p %p\n", base, flags, heap, ret, error );
|
||||
if (error) FIXME( "ignoring error parameter\n" );
|
||||
|
||||
if (!url || !heap || !ret) return E_INVALIDARG;
|
||||
if (flags)
|
||||
{
|
||||
FIXME( "unimplemented flags %08x\n", flags );
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
if (!(scheme = scheme_str( url->url.scheme, &len_scheme ))) return WS_E_INVALID_FORMAT;
|
||||
len = len_scheme + 3; /* '://' */
|
||||
len += 6; /* ':65535' */
|
||||
|
||||
if ((hr = url_encode_size( url->host.chars, url->host.length, "", &len_enc )) != S_OK)
|
||||
return hr;
|
||||
len += len_enc;
|
||||
|
||||
if ((hr = url_encode_size( url->path.chars, url->path.length, "/", &len_enc )) != S_OK)
|
||||
return hr;
|
||||
len += len_enc;
|
||||
|
||||
if ((hr = url_encode_size( url->query.chars, url->query.length, "/?", &len_enc )) != S_OK)
|
||||
return hr;
|
||||
len += len_enc + 1; /* '?' */
|
||||
|
||||
if ((hr = url_encode_size( url->fragment.chars, url->fragment.length, "/?", &len_enc )) != S_OK)
|
||||
return hr;
|
||||
len += len_enc + 1; /* '#' */
|
||||
|
||||
if (!(str = ws_alloc( heap, len * sizeof(WCHAR) ))) return WS_E_QUOTA_EXCEEDED;
|
||||
|
||||
memcpy( str, scheme, len_scheme * sizeof(WCHAR) );
|
||||
p = str + len_scheme;
|
||||
p[0] = ':';
|
||||
p[1] = p[2] = '/';
|
||||
p += 3;
|
||||
|
||||
if ((hr = url_encode( url->host.chars, url->host.length, p, "", &len_enc )) != S_OK)
|
||||
goto error;
|
||||
p += len_enc;
|
||||
|
||||
if (url->portAsString.length)
|
||||
{
|
||||
q = url->portAsString.chars;
|
||||
len = url->portAsString.length;
|
||||
while (len && isdigitW( *q ))
|
||||
{
|
||||
if ((port = port * 10 + *q - '0') > 65535)
|
||||
{
|
||||
hr = WS_E_INVALID_FORMAT;
|
||||
goto error;
|
||||
}
|
||||
q++; len--;
|
||||
}
|
||||
if (url->port && port != url->port)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto error;
|
||||
}
|
||||
} else port = url->port;
|
||||
|
||||
if (port == default_port( url->url.scheme )) port = 0;
|
||||
if (port)
|
||||
{
|
||||
WCHAR buf[7];
|
||||
len = sprintfW( buf, fmtW, port );
|
||||
memcpy( p, buf, len * sizeof(WCHAR) );
|
||||
p += len;
|
||||
}
|
||||
|
||||
if ((hr = url_encode( url->path.chars, url->path.length, p, "/", &len_enc )) != S_OK)
|
||||
goto error;
|
||||
p += len_enc;
|
||||
|
||||
if (url->query.length)
|
||||
{
|
||||
*p++ = '?';
|
||||
if ((hr = url_encode( url->query.chars, url->query.length, p, "/?", &len_enc )) != S_OK)
|
||||
goto error;
|
||||
p += len_enc;
|
||||
}
|
||||
|
||||
if (url->fragment.length)
|
||||
{
|
||||
*p++ = '#';
|
||||
if ((hr = url_encode( url->fragment.chars, url->fragment.length, p, "/?", &len_enc )) != S_OK)
|
||||
goto error;
|
||||
p += len_enc;
|
||||
}
|
||||
|
||||
ret->length = p - str;
|
||||
ret->chars = str;
|
||||
return S_OK;
|
||||
|
||||
error:
|
||||
ws_free( heap, str );
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
@ stub WsCreateXmlSecurityToken
|
||||
@ stdcall WsDateTimeToFileTime(ptr ptr ptr)
|
||||
@ stdcall WsDecodeUrl(ptr long ptr ptr ptr)
|
||||
@ stub WsEncodeUrl
|
||||
@ stdcall WsEncodeUrl(ptr long ptr ptr ptr)
|
||||
@ stub WsEndReaderCanonicalization
|
||||
@ stub WsEndWriterCanonicalization
|
||||
@ stdcall WsFileTimeToDateTime(ptr ptr ptr)
|
||||
|
|
Loading…
Reference in New Issue