From bba66c99b6ea19ddb306919d13d8c2dbf167b338 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 23 Sep 2008 13:32:26 +0200 Subject: [PATCH] winhttp: Implement WinHttpCreateUrl. --- dlls/winhttp/Makefile.in | 3 +- dlls/winhttp/main.c | 38 ----- dlls/winhttp/url.c | 333 +++++++++++++++++++++++++++++++++++++++ include/winhttp.h | 2 + 4 files changed, 337 insertions(+), 39 deletions(-) create mode 100644 dlls/winhttp/url.c diff --git a/dlls/winhttp/Makefile.in b/dlls/winhttp/Makefile.in index cf188c7217c..3d85c4df01b 100644 --- a/dlls/winhttp/Makefile.in +++ b/dlls/winhttp/Makefile.in @@ -13,7 +13,8 @@ C_SRCS = \ main.c \ net.c \ request.c \ - session.c + session.c \ + url.c RC_SRCS = \ version.rc diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c index 4a4aea8f65a..1a4a1313ac2 100644 --- a/dlls/winhttp/main.c +++ b/dlls/winhttp/main.c @@ -84,41 +84,3 @@ HRESULT WINAPI DllUnregisterServer(void) FIXME("()\n"); return S_OK; } - -#define SCHEME_HTTP 3 -#define SCHEME_HTTPS 4 - -BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW ); -BOOL WINAPI InternetCreateUrlW( LPURL_COMPONENTS, DWORD, LPWSTR, LPDWORD ); - -/*********************************************************************** - * WinHttpCrackUrl (winhttp.@) - */ -BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW components ) -{ - BOOL ret; - - TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, components); - - if ((ret = InternetCrackUrlW( url, len, flags, components ))) - { - /* fix up an incompatibility between wininet and winhttp */ - if (components->nScheme == SCHEME_HTTP) components->nScheme = INTERNET_SCHEME_HTTP; - else if (components->nScheme == SCHEME_HTTPS) components->nScheme = INTERNET_SCHEME_HTTPS; - else - { - set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ); - return FALSE; - } - } - return ret; -} - -/*********************************************************************** - * WinHttpCreateUrl (winhttp.@) - */ -BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS comps, DWORD flags, LPWSTR url, LPDWORD len ) -{ - TRACE("%p, 0x%08x, %p, %p\n", comps, flags, url, len); - return InternetCreateUrlW( comps, flags, url, len ); -} diff --git a/dlls/winhttp/url.c b/dlls/winhttp/url.c new file mode 100644 index 00000000000..7d739d5a050 --- /dev/null +++ b/dlls/winhttp/url.c @@ -0,0 +1,333 @@ +/* + * Copyright 2008 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include + +#include "wine/debug.h" + +#include "windef.h" +#include "winbase.h" +#include "winhttp.h" + +#include "winhttp_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhttp); + +#define SCHEME_HTTP 3 +#define SCHEME_HTTPS 4 + +BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW ); + +/*********************************************************************** + * WinHttpCrackUrl (winhttp.@) + */ +BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW components ) +{ + BOOL ret; + + TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, components); + + if ((ret = InternetCrackUrlW( url, len, flags, components ))) + { + /* fix up an incompatibility between wininet and winhttp */ + if (components->nScheme == SCHEME_HTTP) components->nScheme = INTERNET_SCHEME_HTTP; + else if (components->nScheme == SCHEME_HTTPS) components->nScheme = INTERNET_SCHEME_HTTPS; + else + { + set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ); + return FALSE; + } + } + return ret; +} + +static const WCHAR scheme_http[] = {'h','t','t','p',0}; +static const WCHAR scheme_https[] = {'h','t','t','p','s',0}; + +static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len ) +{ + if (!strncmpW( scheme, scheme_http, len )) return INTERNET_SCHEME_HTTP; + if (!strncmpW( scheme, scheme_https, len )) return INTERNET_SCHEME_HTTPS; + return 0; +} + +static const WCHAR *get_scheme_string( INTERNET_SCHEME scheme ) +{ + if (scheme == INTERNET_SCHEME_HTTP) return scheme_http; + if (scheme == INTERNET_SCHEME_HTTPS) return scheme_https; + return NULL; +} + +static BOOL uses_default_port( INTERNET_SCHEME scheme, INTERNET_PORT port ) +{ + if ((scheme == INTERNET_SCHEME_HTTP) && (port == INTERNET_DEFAULT_HTTP_PORT)) return TRUE; + if ((scheme == INTERNET_SCHEME_HTTPS) && (port == INTERNET_DEFAULT_HTTPS_PORT)) return TRUE; + return FALSE; +} + +static BOOL need_escape( WCHAR c ) +{ + if (isalnumW( c )) return FALSE; + + if (c <= 31 || c >= 127) return TRUE; + else + { + switch (c) + { + case ' ': + case '"': + case '#': + case '%': + case '<': + case '>': + case ']': + case '\\': + case '[': + case '^': + case '`': + case '{': + case '|': + case '}': + case '~': + return TRUE; + default: + return FALSE; + } + } +} + +static DWORD copy_escape( WCHAR *dst, const WCHAR *src, DWORD len ) +{ + static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + DWORD ret = len; + unsigned int i; + WCHAR *p = dst; + + for (i = 0; i < len; i++, p++) + { + if (need_escape( src[i] )) + { + p[0] = '%'; + p[1] = hex[(src[i] >> 4) & 0xf]; + p[2] = hex[src[i] & 0xf]; + ret += 2; + p += 2; + } + else *p = src[i]; + } + dst[ret] = 0; + return ret; +} + +static DWORD comp_length( DWORD len, DWORD flags, WCHAR *comp ) +{ + DWORD ret; + unsigned int i; + + ret = len ? len : strlenW( comp ); + if (!(flags & ICU_ESCAPE)) return ret; + for (i = 0; i < len; i++) if (need_escape( comp[i] )) ret += 2; + return ret; +} + +static BOOL calc_length( URL_COMPONENTS *uc, DWORD flags, LPDWORD len ) +{ + static const WCHAR formatW[] = {'%','d',0}; + INTERNET_SCHEME scheme; + + *len = 0; + if (uc->lpszScheme) + { + DWORD scheme_len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme ); + *len += scheme_len; + scheme = get_scheme( uc->lpszScheme, scheme_len ); + } + else + { + scheme = uc->nScheme; + if (!scheme) scheme = INTERNET_SCHEME_HTTP; + *len += strlenW( get_scheme_string( scheme ) ); + } + *len += 1; /* ':' */ + if (uc->lpszHostName) *len += 2; /* "//" */ + + if (uc->lpszUserName) + { + *len += comp_length( uc->dwUserNameLength, 0, uc->lpszUserName ); + *len += 1; /* "@" */ + } + else + { + if (uc->lpszPassword) + { + set_last_error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + } + if (uc->lpszPassword) + { + *len += 1; /* ":" */ + *len += comp_length( uc->dwPasswordLength, 0, uc->lpszPassword ); + } + if (uc->lpszHostName) + { + *len += comp_length( uc->dwHostNameLength, 0, uc->lpszHostName ); + + if (!uses_default_port( scheme, uc->nPort )) + { + WCHAR port[sizeof("65535")]; + + sprintfW( port, formatW, uc->nPort ); + *len += strlenW( port ); + *len += 1; /* ":" */ + } + if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') *len += 1; /* '/' */ + } + if (uc->lpszUrlPath) *len += comp_length( uc->dwUrlPathLength, flags, uc->lpszUrlPath ); + if (uc->lpszExtraInfo) *len += comp_length( uc->dwExtraInfoLength, flags, uc->lpszExtraInfo ); + return TRUE; +} + +/*********************************************************************** + * WinHttpCreateUrl (winhttp.@) + */ +BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDWORD required ) +{ + static const WCHAR formatW[] = {'%','d',0}; + static const WCHAR twoslashW[] = {'/','/'}; + + DWORD len; + INTERNET_SCHEME scheme; + + TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required); + + if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required) + { + set_last_error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!calc_length( uc, flags, &len )) return FALSE; + + if (!url || *required < len) + { + *required = len + 1; + set_last_error( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + + url[0] = 0; + *required = len; + if (uc->lpszScheme) + { + len = comp_length( uc->dwSchemeLength, 0, uc->lpszScheme ); + memcpy( url, uc->lpszScheme, len * sizeof(WCHAR) ); + url += len; + + scheme = get_scheme( uc->lpszScheme, len ); + } + else + { + const WCHAR *schemeW; + scheme = uc->nScheme; + + if (!scheme) scheme = INTERNET_SCHEME_HTTP; + + schemeW = get_scheme_string( scheme ); + len = strlenW( schemeW ); + memcpy( url, schemeW, len * sizeof(WCHAR) ); + url += len; + } + + /* all schemes are followed by at least a colon */ + *url = ':'; + url++; + + if (uc->lpszHostName) + { + memcpy( url, twoslashW, sizeof(twoslashW) ); + url += sizeof(twoslashW) / sizeof(twoslashW[0]); + } + if (uc->lpszUserName) + { + len = comp_length( uc->dwUserNameLength, 0, uc->lpszUserName ); + memcpy( url, uc->lpszUserName, len * sizeof(WCHAR) ); + url += len; + + if (uc->lpszPassword) + { + *url = ':'; + url++; + + len = comp_length( uc->dwPasswordLength, 0, uc->lpszPassword ); + memcpy( url, uc->lpszPassword, len * sizeof(WCHAR) ); + url += len; + } + *url = '@'; + url++; + } + if (uc->lpszHostName) + { + len = comp_length( uc->dwHostNameLength, 0, uc->lpszHostName ); + memcpy( url, uc->lpszHostName, len * sizeof(WCHAR) ); + url += len; + + if (!uses_default_port( scheme, uc->nPort )) + { + WCHAR port[sizeof("65535")]; + + sprintfW( port, formatW, uc->nPort ); + *url = ':'; + url++; + + len = strlenW( port ); + memcpy( url, port, len * sizeof(WCHAR) ); + url += len; + } + + /* add slash between hostname and path if necessary */ + if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') + { + *url = '/'; + url++; + } + } + if (uc->lpszUrlPath) + { + len = comp_length( uc->dwUrlPathLength, 0, uc->lpszUrlPath ); + if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszUrlPath, len ); + else + { + memcpy( url, uc->lpszUrlPath, len * sizeof(WCHAR) ); + url += len; + } + } + if (uc->lpszExtraInfo) + { + len = comp_length( uc->dwExtraInfoLength, 0, uc->lpszExtraInfo ); + if (flags & ICU_ESCAPE) url += copy_escape( url, uc->lpszExtraInfo, len ); + else + { + memcpy( url, uc->lpszExtraInfo, len * sizeof(WCHAR) ); + url += len; + } + } + *url = 0; + return TRUE; +} diff --git a/include/winhttp.h b/include/winhttp.h index e67d6c2a830..17fc38a8f02 100644 --- a/include/winhttp.h +++ b/include/winhttp.h @@ -36,6 +36,8 @@ typedef INTERNET_PORT *LPINTERNET_PORT; #define INTERNET_SCHEME_HTTPS 2 typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; +#define ICU_ESCAPE 0x80000000 + /* flags for WinHttpOpen */ #define WINHTTP_FLAG_ASYNC 0x10000000