[2/2] webservices: Implement WsEncodeUrl.
Hans Leidekker
hans at codeweavers.com
Thu May 26 03:56:48 CDT 2016
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/tests/url.c | 110 ++++++++++++++++
dlls/webservices/url.c | 269 ++++++++++++++++++++++++++++++++++++++
dlls/webservices/webservices.spec | 2 +-
3 files changed, 380 insertions(+), 1 deletion(-)
diff --git a/dlls/webservices/tests/url.c b/dlls/webservices/tests/url.c
index 45b6745..3e11b5c 100644
--- a/dlls/webservices/tests/url.c
+++ b/dlls/webservices/tests/url.c
@@ -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();
}
diff --git a/dlls/webservices/url.c b/dlls/webservices/url.c
index 8884fd1..6951cd6 100644
--- a/dlls/webservices/url.c
+++ b/dlls/webservices/url.c
@@ -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;
+}
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index 55e19ca..1ecef6c 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -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)
--
2.8.1
More information about the wine-patches
mailing list