From 3e4b8ea4f14df0fe879a2524a28d33a18c37d396 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Mon, 15 Mar 2010 11:35:51 +0000 Subject: [PATCH] [WININET] sync wininet with wine 1.1.40 svn path=/trunk/; revision=46202 --- reactos/dll/win32/wininet/cookie.c | 295 +- reactos/dll/win32/wininet/dialogs.c | 252 +- reactos/dll/win32/wininet/ftp.c | 951 +++--- reactos/dll/win32/wininet/http.c | 3561 ++++++++++++--------- reactos/dll/win32/wininet/internet.c | 862 +++-- reactos/dll/win32/wininet/internet.h | 193 +- reactos/dll/win32/wininet/netconnection.c | 653 ++-- reactos/dll/win32/wininet/resource.h | 5 + reactos/dll/win32/wininet/rsrc.rc | 18 +- reactos/dll/win32/wininet/urlcache.c | 192 +- reactos/dll/win32/wininet/utility.c | 88 +- reactos/dll/win32/wininet/wininet.rbuild | 1 + reactos/dll/win32/wininet/wininet.spec | 16 +- reactos/dll/win32/wininet/wininet_Bg.rc | 2 + reactos/dll/win32/wininet/wininet_Cs.rc | 2 + reactos/dll/win32/wininet/wininet_Da.rc | 2 + reactos/dll/win32/wininet/wininet_De.rc | 29 +- reactos/dll/win32/wininet/wininet_En.rc | 22 + reactos/dll/win32/wininet/wininet_Eo.rc | 2 + reactos/dll/win32/wininet/wininet_Es.rc | 2 + reactos/dll/win32/wininet/wininet_Fi.rc | 2 + reactos/dll/win32/wininet/wininet_Fr.rc | 60 +- reactos/dll/win32/wininet/wininet_Hu.rc | 2 + reactos/dll/win32/wininet/wininet_It.rc | 22 + reactos/dll/win32/wininet/wininet_Ja.rc | 4 +- reactos/dll/win32/wininet/wininet_Ko.rc | 2 + reactos/dll/win32/wininet/wininet_Lt.rc | 69 + reactos/dll/win32/wininet/wininet_Nl.rc | 22 + reactos/dll/win32/wininet/wininet_No.rc | 28 +- reactos/dll/win32/wininet/wininet_Pl.rc | 2 + reactos/dll/win32/wininet/wininet_Pt.rc | 34 +- reactos/dll/win32/wininet/wininet_Ro.rc | 26 +- reactos/dll/win32/wininet/wininet_Ru.rc | 43 +- reactos/dll/win32/wininet/wininet_Si.rc | 4 +- reactos/dll/win32/wininet/wininet_Sv.rc | 2 + reactos/dll/win32/wininet/wininet_Tr.rc | 2 + reactos/dll/win32/wininet/wininet_Uk.rc | 2 + reactos/dll/win32/wininet/wininet_Zh.rc | 4 +- 38 files changed, 4750 insertions(+), 2728 deletions(-) create mode 100644 reactos/dll/win32/wininet/wininet_Lt.rc diff --git a/reactos/dll/win32/wininet/cookie.c b/reactos/dll/win32/wininet/cookie.c index 12d841bc7b9..75cf049308b 100644 --- a/reactos/dll/win32/wininet/cookie.c +++ b/reactos/dll/win32/wininet/cookie.c @@ -23,6 +23,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -48,7 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); * Cookies are currently memory only. * Cookies are NOT THREAD SAFE * Cookies could use A LOT OF MEMORY. We need some kind of memory management here! - * Cookies should care about the expiry time */ typedef struct _cookie_domain cookie_domain; @@ -62,7 +65,7 @@ struct _cookie LPWSTR lpCookieName; LPWSTR lpCookieData; - time_t expiry; /* FIXME: not used */ + FILETIME expiry; }; struct _cookie_domain @@ -76,7 +79,7 @@ struct _cookie_domain static struct list domain_list = LIST_INIT(domain_list); -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data); +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry); static cookie *COOKIE_findCookie(cookie_domain *domain, LPCWSTR lpszCookieName); static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain); static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path); @@ -84,24 +87,16 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain); /* adds a cookie to the domain */ -static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data) +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCWSTR name, LPCWSTR data, FILETIME expiry) { cookie *newCookie = HeapAlloc(GetProcessHeap(), 0, sizeof(cookie)); list_init(&newCookie->entry); newCookie->lpCookieName = NULL; newCookie->lpCookieData = NULL; - - if (name) - { - newCookie->lpCookieName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieName, name); - } - if (data) - { - newCookie->lpCookieData = HeapAlloc(GetProcessHeap(), 0, (strlenW(data) + 1)*sizeof(WCHAR)); - lstrcpyW(newCookie->lpCookieData, data); - } + newCookie->expiry = expiry; + newCookie->lpCookieName = heap_strdupW(name); + newCookie->lpCookieData = heap_strdupW(data); TRACE("added cookie %p (data is %s)\n", newCookie, debugstr_w(data) ); @@ -156,17 +151,8 @@ static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path) list_init(&newDomain->cookie_list); newDomain->lpCookieDomain = NULL; newDomain->lpCookiePath = NULL; - - if (domain) - { - newDomain->lpCookieDomain = HeapAlloc(GetProcessHeap(), 0, (strlenW(domain) + 1)*sizeof(WCHAR)); - strcpyW(newDomain->lpCookieDomain, domain); - } - if (path) - { - newDomain->lpCookiePath = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1)*sizeof(WCHAR)); - lstrcpyW(newDomain->lpCookiePath, path); - } + newDomain->lpCookieDomain = heap_strdupW(domain); + newDomain->lpCookiePath = heap_strdupW(path); list_add_tail(&domain_list, &newDomain->entry); @@ -191,7 +177,28 @@ static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostName UrlComponents.dwHostNameLength = hostNameLen; UrlComponents.dwUrlPathLength = pathLen; - return InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents); + if (!InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents)) return FALSE; + + /* discard the webpage off the end of the path */ + if (UrlComponents.dwUrlPathLength) + { + if (path[UrlComponents.dwUrlPathLength - 1] != '/') + { + WCHAR *ptr; + if ((ptr = strrchrW(path, '/'))) *(++ptr) = 0; + else + { + path[0] = '/'; + path[1] = 0; + } + } + } + else if (pathLen >= 2) + { + path[0] = '/'; + path[1] = 0; + } + return TRUE; } /* match a domain. domain must match if the domain is not NULL. path must match if the path is not NULL */ @@ -215,11 +222,22 @@ static BOOL COOKIE_matchDomain(LPCWSTR lpszCookieDomain, LPCWSTR lpszCookiePath, } if (lpszCookiePath) { + INT len; TRACE("comparing paths: %s with %s\n", debugstr_w(lpszCookiePath), debugstr_w(searchDomain->lpCookiePath)); + /* paths match at the beginning. so a path of /foo would match + * /foobar and /foo/bar + */ if (!searchDomain->lpCookiePath) return FALSE; - if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) + if (allow_partial) + { + len = lstrlenW(searchDomain->lpCookiePath); + if (strncmpiW(searchDomain->lpCookiePath, lpszCookiePath, len)!=0) + return FALSE; + } + else if (strcmpW(lpszCookiePath, searchDomain->lpCookiePath)) return FALSE; + } return TRUE; } @@ -262,6 +280,7 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, struct list * cursor; unsigned int cnt = 0, domain_count = 0, cookie_count = 0; WCHAR hostName[2048], path[2048]; + FILETIME tm; TRACE("(%s, %s, %p, %p)\n", debugstr_w(lpszUrl),debugstr_w(lpszCookieName), lpCookieData, lpdwSize); @@ -276,10 +295,12 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; + GetSystemTimeAsFileTime(&tm); + LIST_FOR_EACH(cursor, &domain_list) { cookie_domain *cookiesDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(hostName, NULL /* FIXME: path */, cookiesDomain, TRUE)) + if (COOKIE_matchDomain(hostName, path, cookiesDomain, TRUE)) { struct list * cursor; domain_count++; @@ -288,6 +309,14 @@ BOOL WINAPI InternetGetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LIST_FOR_EACH(cursor, &cookiesDomain->cookie_list) { cookie *thisCookie = LIST_ENTRY(cursor, cookie, entry); + /* check for expiry */ + if ((thisCookie->expiry.dwLowDateTime != 0 || thisCookie->expiry.dwHighDateTime != 0) && CompareFileTime(&tm,&thisCookie->expiry) > 0) + { + TRACE("Found expired cookie. deleting\n"); + COOKIE_deleteCookie(thisCookie, FALSE); + continue; + } + if (lpCookieData == NULL) /* return the size of the buffer required to lpdwSize */ { unsigned int len; @@ -356,27 +385,16 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPSTR lpCookieData, LPDWORD lpdwSize) { DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR szCookieData = NULL, url, name; BOOL r; TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), lpCookieData); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } - - r = InternetGetCookieW( szUrl, szCookieName, NULL, &len ); + r = InternetGetCookieW( url, name, NULL, &len ); if( r ) { szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); @@ -386,7 +404,7 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } else { - r = InternetGetCookieW( szUrl, szCookieName, szCookieData, &len ); + r = InternetGetCookieW( url, name, szCookieData, &len ); *lpdwSize = WideCharToMultiByte( CP_ACP, 0, szCookieData, len, lpCookieData, *lpdwSize, NULL, NULL ); @@ -394,8 +412,8 @@ BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, } HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -405,27 +423,129 @@ static BOOL set_cookie(LPCWSTR domain, LPCWSTR path, LPCWSTR cookie_name, LPCWST cookie_domain *thisCookieDomain = NULL; cookie *thisCookie; struct list *cursor; + LPWSTR data, value; + WCHAR *ptr; + FILETIME expiry; + BOOL expired = FALSE; + + value = data = heap_strdupW(cookie_data); + if (!data) + { + ERR("could not allocate %zu bytes for the cookie data buffer\n", (strlenW(cookie_data) + 1) * sizeof(WCHAR)); + return FALSE; + } + + memset(&expiry,0,sizeof(expiry)); + + /* lots of information can be parsed out of the cookie value */ + + ptr = data; + for (;;) + { + static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; + static const WCHAR szPath[] = {'p','a','t','h','=',0}; + static const WCHAR szExpires[] = {'e','x','p','i','r','e','s','=',0}; + static const WCHAR szSecure[] = {'s','e','c','u','r','e',0}; + static const WCHAR szHttpOnly[] = {'h','t','t','p','o','n','l','y',0}; + + if (!(ptr = strchrW(ptr,';'))) break; + *ptr++ = 0; + + if (value != data) + HeapFree(GetProcessHeap(), 0, value); + value = HeapAlloc(GetProcessHeap(), 0, (ptr - data) * sizeof(WCHAR)); + if (value == NULL) + { + HeapFree(GetProcessHeap(), 0, data); + ERR("could not allocate %zu bytes for the cookie value buffer\n", (ptr - data) * sizeof(WCHAR)); + return FALSE; + } + strcpyW(value, data); + + while (*ptr == ' ') ptr++; /* whitespace */ + + if (strncmpiW(ptr, szDomain, 7) == 0) + { + ptr+=strlenW(szDomain); + domain = ptr; + TRACE("Parsing new domain %s\n",debugstr_w(domain)); + } + else if (strncmpiW(ptr, szPath, 5) == 0) + { + ptr+=strlenW(szPath); + path = ptr; + TRACE("Parsing new path %s\n",debugstr_w(path)); + } + else if (strncmpiW(ptr, szExpires, 8) == 0) + { + FILETIME ft; + SYSTEMTIME st; + FIXME("persistent cookies not handled (%s)\n",debugstr_w(ptr)); + ptr+=strlenW(szExpires); + if (InternetTimeToSystemTimeW(ptr, &st, 0)) + { + SystemTimeToFileTime(&st, &expiry); + GetSystemTimeAsFileTime(&ft); + + if (CompareFileTime(&ft,&expiry) > 0) + { + TRACE("Cookie already expired.\n"); + expired = TRUE; + } + } + } + else if (strncmpiW(ptr, szSecure, 6) == 0) + { + FIXME("secure not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szSecure); + } + else if (strncmpiW(ptr, szHttpOnly, 8) == 0) + { + FIXME("httponly not handled (%s)\n",debugstr_w(ptr)); + ptr += strlenW(szHttpOnly); + } + else if (*ptr) + { + FIXME("Unknown additional option %s\n",debugstr_w(ptr)); + break; + } + } LIST_FOR_EACH(cursor, &domain_list) { thisCookieDomain = LIST_ENTRY(cursor, cookie_domain, entry); - if (COOKIE_matchDomain(domain, NULL /* FIXME: path */, thisCookieDomain, FALSE)) + if (COOKIE_matchDomain(domain, path, thisCookieDomain, FALSE)) break; thisCookieDomain = NULL; } if (!thisCookieDomain) - thisCookieDomain = COOKIE_addDomain(domain, path); + { + if (!expired) + thisCookieDomain = COOKIE_addDomain(domain, path); + else + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); + return TRUE; + } + } if ((thisCookie = COOKIE_findCookie(thisCookieDomain, cookie_name))) COOKIE_deleteCookie(thisCookie, FALSE); - TRACE("setting cookie %s=%s for domain %s\n", debugstr_w(cookie_name), - debugstr_w(cookie_data), debugstr_w(thisCookieDomain->lpCookieDomain)); + TRACE("setting cookie %s=%s for domain %s path %s\n", debugstr_w(cookie_name), + debugstr_w(value), debugstr_w(thisCookieDomain->lpCookieDomain),debugstr_w(thisCookieDomain->lpCookiePath)); - if (!COOKIE_addCookie(thisCookieDomain, cookie_name, cookie_data)) + if (!expired && !COOKIE_addCookie(thisCookieDomain, cookie_name, value, expiry)) + { + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return FALSE; + } + HeapFree(GetProcessHeap(),0,data); + if (value != data) HeapFree(GetProcessHeap(), 0, value); return TRUE; } @@ -454,28 +574,26 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, return FALSE; } - hostName[0] = path[0] = 0; + hostName[0] = 0; ret = COOKIE_crackUrlSimple(lpszUrl, hostName, sizeof(hostName)/sizeof(hostName[0]), path, sizeof(path)/sizeof(path[0])); if (!ret || !hostName[0]) return FALSE; if (!lpszCookieName) { - unsigned int len; WCHAR *cookie, *data; - len = strlenW(lpCookieData); - if (!(cookie = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) + cookie = heap_strdupW(lpCookieData); + if (!cookie) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - strcpyW(cookie, lpCookieData); /* some apps (or is it us??) try to add a cookie with no cookie name, but * the cookie data in the form of name[=data]. */ - if (!(data = strchrW(cookie, '='))) data = cookie + len; - else data++; + if (!(data = strchrW(cookie, '='))) data = cookie + strlenW(cookie); + else *data++ = 0; ret = set_cookie(hostName, path, cookie, data); @@ -499,39 +617,21 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, LPCSTR lpCookieData) { - DWORD len; - LPWSTR szCookieData = NULL, szUrl = NULL, szCookieName = NULL; + LPWSTR data, url, name; BOOL r; TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), debugstr_a(lpszCookieName), debugstr_a(lpCookieData)); - if( lpszUrl ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszUrl, -1, szUrl, len ); - } + url = heap_strdupAtoW(lpszUrl); + name = heap_strdupAtoW(lpszCookieName); + data = heap_strdupAtoW(lpCookieData); - if( lpszCookieName ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, NULL, 0 ); - szCookieName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpszCookieName, -1, szCookieName, len ); - } + r = InternetSetCookieW( url, name, data ); - if( lpCookieData ) - { - len = MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, NULL, 0 ); - szCookieData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpCookieData, -1, szCookieData, len ); - } - - r = InternetSetCookieW( szUrl, szCookieName, szCookieData ); - - HeapFree( GetProcessHeap(), 0, szCookieData ); - HeapFree( GetProcessHeap(), 0, szCookieName ); - HeapFree( GetProcessHeap(), 0, szUrl ); + HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, name ); + HeapFree( GetProcessHeap(), 0, url ); return r; } @@ -692,3 +792,28 @@ BOOL WINAPI InternetSetPerSiteCookieDecisionW( LPCWSTR pchHostName, DWORD dwDeci FIXME("(%s, 0x%08x) stub\n", debugstr_w(pchHostName), dwDecision); return FALSE; } + +/*********************************************************************** + * IsDomainLegalCookieDomainW (WININET.@) + */ +BOOL WINAPI IsDomainLegalCookieDomainW( LPCWSTR s1, LPCWSTR s2 ) +{ + const WCHAR *p; + + FIXME("(%s, %s)\n", debugstr_w(s1), debugstr_w(s2)); + + if (!s1 || !s2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (s1[0] == '.' || !s1[0] || s2[0] == '.' || !s2[0]) + { + SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + if (!(p = strchrW(s2, '.'))) return FALSE; + if (strchrW(p + 1, '.') && !strcmpW(p + 1, s1)) return TRUE; + else if (!strcmpW(s1, s2)) return TRUE; + return FALSE; +} diff --git a/reactos/dll/win32/wininet/dialogs.c b/reactos/dll/win32/wininet/dialogs.c index dd5aa315a63..2c4a5278569 100644 --- a/reactos/dll/win32/wininet/dialogs.c +++ b/reactos/dll/win32/wininet/dialogs.c @@ -21,6 +21,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include "windef.h" @@ -58,22 +62,23 @@ struct WININET_ErrorDlgParams */ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + BOOL ret = FALSE; LPWSTR p; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if (NULL == lpwhr) - return FALSE; + return FALSE; lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs) - return FALSE; + goto done; hIC = lpwhs->lpAppInfo; if (NULL == hIC) - return FALSE; + goto done; lstrcpynW(szBuf, hIC->lpszProxy, sz); @@ -82,7 +87,39 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) if (p) *p = 0; - return TRUE; + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; +} + +/*********************************************************************** + * WININET_GetServer + * + * Determine the name of the web server + */ +static BOOL WININET_GetServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + BOOL ret = FALSE; + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + if (NULL == lpwhr) + return FALSE; + + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs) + goto done; + + lstrcpynW(szBuf, lpwhs->lpszHostName, sz); + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -90,16 +127,20 @@ static BOOL WININET_GetProxyServer( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) * * Determine the name of the (basic) Authentication realm */ -static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) +static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz, BOOL proxy ) { LPWSTR p, q; - DWORD index; + DWORD index, query; static const WCHAR szRealm[] = { 'r','e','a','l','m','=',0 }; - /* extract the Realm from the proxy response and show it */ + if (proxy) + query = HTTP_QUERY_PROXY_AUTHENTICATE; + else + query = HTTP_QUERY_WWW_AUTHENTICATE; + + /* extract the Realm from the response and show it */ index = 0; - if( !HttpQueryInfoW( hRequest, HTTP_QUERY_PROXY_AUTHENTICATE, - szBuf, &sz, &index) ) + if( !HttpQueryInfoW( hRequest, query, szBuf, &sz, &index) ) return FALSE; /* @@ -109,11 +150,10 @@ static BOOL WININET_GetAuthRealm( HINTERNET hRequest, LPWSTR szBuf, DWORD sz ) p = strchrW( szBuf, ' ' ); if( !p || strncmpW( p+1, szRealm, strlenW(szRealm) ) ) { - ERR("proxy response wrong? (%s)\n", debugstr_w(szBuf)); + ERR("response wrong? (%s)\n", debugstr_w(szBuf)); return FALSE; } - /* remove quotes */ p += 7; if( *p == '"' ) @@ -194,44 +234,62 @@ static BOOL WININET_GetSetPassword( HWND hdlg, LPCWSTR szServer, } /*********************************************************************** - * WININET_SetProxyAuthorization + * WININET_SetAuthorization */ -static BOOL WININET_SetProxyAuthorization( HINTERNET hRequest, - LPWSTR username, LPWSTR password ) +static BOOL WININET_SetAuthorization( HINTERNET hRequest, LPWSTR username, + LPWSTR password, BOOL proxy ) { - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - LPWSTR p; + http_request_t *lpwhr; + http_session_t *lpwhs; + BOOL ret = FALSE; + LPWSTR p, q; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); if( !lpwhr ) - return FALSE; - + return FALSE; + lpwhs = lpwhr->lpHttpSession; if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - return FALSE; + goto done; } - hIC = lpwhs->lpAppInfo; - - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( username ) + 1)*sizeof(WCHAR) ); + p = heap_strdupW(username); if( !p ) - return FALSE; - - lstrcpyW( p, username ); - hIC->lpszProxyUsername = p; + goto done; - p = HeapAlloc( GetProcessHeap(), 0, (strlenW( password ) + 1)*sizeof(WCHAR) ); - if( !p ) - return FALSE; - - lstrcpyW( p, password ); - hIC->lpszProxyPassword = p; + q = heap_strdupW(password); + if( !q ) + { + HeapFree(GetProcessHeap(), 0, username); + goto done; + } - return TRUE; + if (proxy) + { + appinfo_t *hIC = lpwhs->lpAppInfo; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyUsername); + hIC->lpszProxyUsername = p; + + HeapFree(GetProcessHeap(), 0, hIC->lpszProxyPassword); + hIC->lpszProxyPassword = q; + } + else + { + HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); + lpwhs->lpszUserName = p; + + HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword); + lpwhs->lpszPassword = q; + } + + ret = TRUE; + +done: + WININET_Release( &lpwhr->hdr ); + return ret; } /*********************************************************************** @@ -254,7 +312,7 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( /* extract the Realm from the proxy response and show it */ if( WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) ) + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) ) { hitem = GetDlgItem( hdlg, IDC_REALM ); SetWindowTextW( hitem, szRealm ); @@ -297,13 +355,97 @@ static INT_PTR WINAPI WININET_ProxyPasswordDialog( if( hitem && SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && WININET_GetAuthRealm( params->hRequest, - szRealm, sizeof szRealm/sizeof(WCHAR)) && + szRealm, sizeof szRealm/sizeof(WCHAR), TRUE ) && WININET_GetProxyServer( params->hRequest, szServer, sizeof szServer/sizeof(WCHAR)) ) { WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); } - WININET_SetProxyAuthorization( params->hRequest, username, password ); + WININET_SetAuthorization( params->hRequest, username, password, TRUE ); + + EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + EndDialog( hdlg, 0 ); + return TRUE; + } + break; + } + return FALSE; +} + +/*********************************************************************** + * WININET_PasswordDialog + */ +static INT_PTR WINAPI WININET_PasswordDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + HWND hitem; + struct WININET_ErrorDlgParams *params; + WCHAR szRealm[0x80], szServer[0x80]; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + params = (struct WININET_ErrorDlgParams*) lParam; + SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); + + /* extract the Realm from the response and show it */ + if( WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) ) + { + hitem = GetDlgItem( hdlg, IDC_REALM ); + SetWindowTextW( hitem, szRealm ); + } + + /* extract the name of the server */ + if( WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + hitem = GetDlgItem( hdlg, IDC_SERVER ); + SetWindowTextW( hitem, szServer ); + } + + WININET_GetSetPassword( hdlg, szServer, szRealm, FALSE ); + + return TRUE; + } + + params = (struct WININET_ErrorDlgParams*) + GetWindowLongPtrW( hdlg, GWLP_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + WCHAR username[0x20], password[0x20]; + + username[0] = 0; + hitem = GetDlgItem( hdlg, IDC_USERNAME ); + if( hitem ) + GetWindowTextW( hitem, username, sizeof username/sizeof(WCHAR) ); + + password[0] = 0; + hitem = GetDlgItem( hdlg, IDC_PASSWORD ); + if( hitem ) + GetWindowTextW( hitem, password, sizeof password/sizeof(WCHAR) ); + + hitem = GetDlgItem( hdlg, IDC_SAVEPASSWORD ); + if( hitem && + SendMessageW( hitem, BM_GETSTATE, 0, 0 ) && + WININET_GetAuthRealm( params->hRequest, + szRealm, sizeof szRealm/sizeof(WCHAR), FALSE ) && + WININET_GetServer( params->hRequest, + szServer, sizeof szServer/sizeof(WCHAR)) ) + { + WININET_GetSetPassword( hdlg, szServer, szRealm, TRUE ); + } + WININET_SetAuthorization( params->hRequest, username, password, FALSE ); EndDialog( hdlg, ERROR_INTERNET_FORCE_RETRY ); return TRUE; @@ -362,17 +504,23 @@ DWORD WINAPI InternetErrorDlg(HWND hWnd, HINTERNET hRequest, switch( dwError ) { case ERROR_SUCCESS: - if( !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) + case ERROR_INTERNET_INCORRECT_PASSWORD: + if( !dwError && !(dwFlags & FLAGS_ERROR_UI_FILTER_FOR_ERRORS ) ) return 0; - dwStatus = WININET_GetConnectionStatus( hRequest ); - if( HTTP_STATUS_PROXY_AUTH_REQ != dwStatus ) - return ERROR_SUCCESS; - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); - case ERROR_INTERNET_INCORRECT_PASSWORD: - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + dwStatus = WININET_GetConnectionStatus( hRequest ); + switch (dwStatus) + { + case HTTP_STATUS_PROXY_AUTH_REQ: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + hWnd, WININET_ProxyPasswordDialog, (LPARAM) ¶ms ); + case HTTP_STATUS_DENIED: + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_AUTHDLG ), + hWnd, WININET_PasswordDialog, (LPARAM) ¶ms ); + default: + WARN("unhandled status %u\n", dwStatus); + return 0; + } case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_INVALID_CA: diff --git a/reactos/dll/win32/wininet/ftp.c b/reactos/dll/win32/wininet/ftp.c index 770fef2886a..1f031996811 100644 --- a/reactos/dll/win32/wininet/ftp.c +++ b/reactos/dll/win32/wininet/ftp.c @@ -30,6 +30,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -39,9 +43,15 @@ #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_ARPA_INET_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #include #include @@ -61,43 +71,47 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); -typedef struct _WININETFTPSESSIONW WININETFTPSESSIONW; +typedef struct _ftp_session_t ftp_session_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; BOOL session_deleted; int nDataSocket; -} WININETFTPFILE, *LPWININETFTPFILE; + WCHAR *cache_file; + HANDLE cache_file_handle; +} ftp_file_t; -typedef struct _WININETFTPSESSIONW +struct _ftp_session_t { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; int sndSocket; int lstnSocket; int pasvSocket; /* data socket connected by us in case of passive FTP */ - LPWININETFTPFILE download_in_progress; + ftp_file_t *download_in_progress; struct sockaddr_in socketAddress; struct sockaddr_in lstnSocketAddress; + LPWSTR servername; + INTERNET_PORT serverport; LPWSTR lpszPassword; LPWSTR lpszUserName; -} *LPWININETFTPSESSIONW; +}; typedef struct { BOOL bIsDirectory; LPWSTR lpszName; DWORD nSize; - struct tm tmLastModified; + SYSTEMTIME tmLastModified; unsigned short permissions; } FILEPROPERTIESW, *LPFILEPROPERTIESW; typedef struct { - WININETHANDLEHEADER hdr; - WININETFTPSESSIONW *lpFtpSession; + object_header_t hdr; + ftp_session_t *lpFtpSession; DWORD index; DWORD size; LPFILEPROPERTIESW lpafp; @@ -165,46 +179,51 @@ static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'}; static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext); -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket); -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext); -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType); -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile); -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType); -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs); -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs); + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext); +static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket); +static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext); +static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType); +static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile); +static BOOL FTP_InitListenSocket(ftp_session_t*); +static BOOL FTP_ConnectToHost(ftp_session_t*); +static BOOL FTP_SendPassword(ftp_session_t*); +static BOOL FTP_SendAccount(ftp_session_t*); +static BOOL FTP_SendType(ftp_session_t*, DWORD dwType); +static BOOL FTP_SendPort(ftp_session_t*); +static BOOL FTP_DoPassive(ftp_session_t*); +static BOOL FTP_SendPortOrPasv(ftp_session_t*); static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp); static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop); -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp); -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext); static DWORD FTP_SetResponseError(DWORD dwResponse); static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData); -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory); -static BOOL FTP_FtpRenameFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest); -static BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory); -static BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName); -static HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName, - DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext); -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest); +static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory); +static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName); +static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext); +/* A temporary helper until we get rid of INTERNET_GetLastError calls */ +static BOOL res_to_le(DWORD res) +{ + if(res != ERROR_SUCCESS) + INTERNET_SetLastError(res); + return res == ERROR_SUCCESS; +} /*********************************************************************** * FtpPutFileA (WININET.@) @@ -223,8 +242,8 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, LPWSTR lpwzNewRemoteFile; BOOL ret; - lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL; - lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL; + lpwzLocalFile = heap_strdupAtoW(lpszLocalFile); + lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile); ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzLocalFile); @@ -235,7 +254,7 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -259,8 +278,8 @@ static void AsyncFtpPutFileProc(WORKREQUEST *workRequest) BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszLocalFile || !lpszNewRemoteFile) @@ -269,7 +288,7 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -302,12 +321,12 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile, workRequest.asyncproc = AsyncFtpPutFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); - req->lpszLocalFile = WININET_strdupW(lpszLocalFile); - req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile); + req->lpszLocalFile = heap_strdupW(lpszLocalFile); + req->lpszNewRemoteFile = heap_strdupW(lpszNewRemoteFile); req->dwFlags = dwFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -331,12 +350,12 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, +static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile, LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext) { HANDLE hFile; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; INT nResCode; TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile)); @@ -375,7 +394,10 @@ static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) { @@ -408,7 +430,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -418,7 +440,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -438,8 +460,8 @@ static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs = NULL; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs = NULL; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszDirectory) @@ -448,7 +470,7 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) goto lend; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -472,9 +494,9 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpSetCurrentDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -499,10 +521,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -554,7 +576,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpCreateDirectoryW(hConnect, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -564,7 +586,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE(" %p\n", lpwfs); @@ -584,11 +606,11 @@ static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -622,9 +644,9 @@ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpCreateDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpCreateDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -647,11 +669,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory)); @@ -703,14 +725,14 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, LPWIN32_FIND_DATAW lpFindFileDataW; HINTERNET ret; - lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL; + lpwzSearchFile = heap_strdupAtoW(lpszSearchFile); lpFindFileDataW = lpFindFileData?&wfd:NULL; ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzSearchFile); if (ret && lpFindFileData) WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData); - + return ret; } @@ -718,7 +740,7 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -740,11 +762,11 @@ static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest) HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; HINTERNET r = NULL; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) { INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); @@ -766,7 +788,7 @@ HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect, workRequest.asyncproc = AsyncFtpFindFirstFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpFindFirstFileW; - req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile); + req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : heap_strdupW(lpszSearchFile); req->lpFindFileData = lpFindFileData; req->dwFlags = dwFlags; req->dwContext= dwContext; @@ -797,11 +819,11 @@ lend: * NULL on failure * */ -static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, +static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; HINTERNET hFindNext = NULL; TRACE("\n"); @@ -845,7 +867,10 @@ static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs, lend: if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } hIC = lpwfs->lpAppInfo; if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) @@ -854,13 +879,13 @@ lend: if (hFindNext) { - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, &iar, sizeof(INTERNET_ASYNC_RESULT)); } - iar.dwResult = (DWORD)hFindNext; + iar.dwResult = (DWORD_PTR)hFindNext; iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, sizeof(INTERNET_ASYNC_RESULT)); @@ -913,7 +938,7 @@ BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDire static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -933,13 +958,13 @@ static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest) BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory); - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -982,7 +1007,7 @@ BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDir req->lpszDirectory = lpszCurrentDirectory; req->lpdwDirectory = lpdwCurrentDirectory; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1008,11 +1033,11 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory, +static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory, LPDWORD lpdwCurrentDirectory) { INT nResCode; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; DWORD bSuccess = FALSE; /* Clear any error information */ @@ -1029,7 +1054,7 @@ static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszC if (nResCode == 257) /* Extract directory name */ { DWORD firstpos, lastpos, len; - LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer()); + LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer()); for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) { @@ -1071,118 +1096,6 @@ lend: return bSuccess; } -/*********************************************************************** - * FtpOpenFileA (WININET.@) - * - * Open a remote file for writing or reading - * - * RETURNS - * HINTERNET handle on success - * NULL on failure - * - */ -HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, - LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, - DWORD_PTR dwContext) -{ - LPWSTR lpwzFileName; - HINTERNET ret; - - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; - ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); - HeapFree(GetProcessHeap(), 0, lpwzFileName); - return ret; -} - - -static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest) -{ - struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; - - TRACE("%p\n", lpwfs); - - FTP_FtpOpenFileW(lpwfs, req->lpszFilename, - req->dwAccess, req->dwFlags, req->dwContext); - HeapFree(GetProcessHeap(), 0, req->lpszFilename); -} - -/*********************************************************************** - * FtpOpenFileW (WININET.@) - * - * Open a remote file for writing or reading - * - * RETURNS - * HINTERNET handle on success - * NULL on failure - * - */ -HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, - LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, - DWORD_PTR dwContext) -{ - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; - HINTERNET r = NULL; - - TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, - debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); - - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); - if (!lpwfs) - { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (WH_HFTPSESSION != lpwfs->hdr.htype) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - if ((!lpszFileName) || - ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) || - ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)) - { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); - goto lend; - } - - if (lpwfs->download_in_progress != NULL) - { - INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); - goto lend; - } - - hIC = lpwfs->lpAppInfo; - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_FTPOPENFILEW *req; - - workRequest.asyncproc = AsyncFtpOpenFileProc; - workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); - req = &workRequest.u.FtpOpenFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); - req->dwAccess = fdwAccess; - req->dwFlags = dwFlags; - req->dwContext = dwContext; - - INTERNET_AsyncCall(&workRequest); - r = NULL; - } - else - { - r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext); - } - -lend: - WININET_Release( &lpwfs->hdr ); - - return r; -} - /*********************************************************************** * FTPFILE_Destroy(internal) @@ -1191,15 +1104,18 @@ lend: * the 'transfer complete' message (this is a bit of a hack though :-/ ) * */ -static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr) +static void FTPFILE_Destroy(object_header_t *hdr) { - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; - LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession; + ftp_file_t *lpwh = (ftp_file_t*) hdr; + ftp_session_t *lpwfs = lpwh->lpFtpSession; INT nResCode; TRACE("\n"); - WININET_Release(&lpwh->lpFtpSession->hdr); + if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE) + CloseHandle(lpwh->cache_file_handle); + + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); if (!lpwh->session_deleted) lpwfs->download_in_progress = NULL; @@ -1210,10 +1126,12 @@ static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr) nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n"); + WININET_Release(&lpwh->lpFtpSession->hdr); + HeapFree(GetProcessHeap(), 0, lpwh); } -static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -1225,15 +1143,47 @@ static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b *size = sizeof(DWORD); *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE; return ERROR_SUCCESS; - } + case INTERNET_OPTION_DATAFILE_NAME: + { + DWORD required; + ftp_file_t *file = (ftp_file_t *)hdr; + TRACE("INTERNET_OPTION_DATAFILE_NAME\n"); + + if (!file->cache_file) + { + *size = 0; + return ERROR_INTERNET_ITEM_NOT_FOUND; + } + if (unicode) + { + required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR); + if (*size < required) + return ERROR_INSUFFICIENT_BUFFER; + + *size = required; + memcpy(buffer, file->cache_file, *size); + return ERROR_SUCCESS; + } + else + { + required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL); + if (required > *size) + return ERROR_INSUFFICIENT_BUFFER; + + *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL); + return ERROR_SUCCESS; + } + } + } return INET_QueryOption(option, buffer, size, unicode); } -static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) +static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) { - WININETFTPFILE *file = (WININETFTPFILE*)hdr; + ftp_file_t *file = (ftp_file_t*)hdr; int res; + DWORD error; if (file->nDataSocket == -1) return ERROR_INTERNET_DISCONNECTED; @@ -1242,29 +1192,119 @@ static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size res = recv(file->nDataSocket, buffer, size, MSG_WAITALL); *read = res>0 ? res : 0; - return res>=0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME*/ + error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */ + if (error == ERROR_SUCCESS && file->cache_file) + { + DWORD bytes_written; + + if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL)) + WARN("WriteFile failed: %u\n", GetLastError()); + } + return error; +} + +static DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); } -static BOOL FTPFILE_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) +static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) { - LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) +{ + ftp_file_t *lpwh = (ftp_file_t*) hdr; int res; res = send(lpwh->nDataSocket, buffer, size, 0); *written = res>0 ? res : 0; - return res >= 0; + return res >= 0 ? ERROR_SUCCESS : sock_get_error(errno); +} + +static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + BYTE buffer[4096]; + int available; + + TRACE("%p\n", file); + + available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK); + + if(available != -1) { + iar.dwResult = (DWORD_PTR)file->hdr.hInternet; + iar.dwError = first_notif ? 0 : available; + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + } + + INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) +{ + ftp_file_t *file = (ftp_file_t*)workRequest->hdr; + + FTP_ReceiveRequestData(file, FALSE); +} + +static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +{ + ftp_file_t *file = (ftp_file_t*) hdr; + int retval, unread = 0; + + TRACE("(%p %p %x %lx)\n", file, available, flags, ctx); + +#ifdef FIONREAD + retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread); + if (!retval) + TRACE("%d bytes of queued, but unread data\n", unread); +#else + FIXME("FIONREAD not available\n"); +#endif + + *available = unread; + + if(!unread) { + BYTE byte; + + *available = 0; + + retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK); + if(retval > 0) { + WORKREQUEST workRequest; + + *available = 0; + workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc; + workRequest.hdr = WININET_AddRef( &file->hdr ); + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + } + + return ERROR_SUCCESS; } -static const HANDLEHEADERVtbl FTPFILEVtbl = { + +static const object_vtbl_t FTPFILEVtbl = { FTPFILE_Destroy, NULL, FTPFILE_QueryOption, NULL, FTPFILE_ReadFile, - NULL, + FTPFILE_ReadFileExA, + FTPFILE_ReadFileExW, FTPFILE_WriteFile, - NULL, + FTPFILE_QueryDataAvailable, NULL }; @@ -1278,14 +1318,14 @@ static const HANDLEHEADERVtbl FTPFILEVtbl = { * NULL on failure * */ -HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, +static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext) { INT nDataSocket; BOOL bSuccess = FALSE; - LPWININETFTPFILE lpwh = NULL; - LPWININETAPPINFOW hIC = NULL; + ftp_file_t *lpwh = NULL; + appinfo_t *hIC = NULL; HINTERNET handle = NULL; TRACE("\n"); @@ -1307,15 +1347,18 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, /* Get data socket to server */ if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) { - lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE)); + lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_file_t)); lpwh->hdr.htype = WH_HFILE; lpwh->hdr.vtbl = &FTPFILEVtbl; lpwh->hdr.dwFlags = dwFlags; lpwh->hdr.dwContext = dwContext; + lpwh->hdr.dwInternalFlags = 0; lpwh->hdr.refs = 1; lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB; lpwh->nDataSocket = nDataSocket; - lpwh->session_deleted = FALSE; + lpwh->cache_file = NULL; + lpwh->cache_file_handle = INVALID_HANDLE_VALUE; + lpwh->session_deleted = FALSE; WININET_AddRef( &lpwfs->hdr ); lpwh->lpFtpSession = lpwfs; @@ -1330,7 +1373,45 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } + + if (bSuccess && fdwAccess == GENERIC_READ) + { + WCHAR filename[MAX_PATH + 1]; + URL_COMPONENTSW uc; + DWORD len; + + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.nScheme = INTERNET_SCHEME_FTP; + uc.lpszHostName = lpwfs->servername; + uc.nPort = lpwfs->serverport; + uc.lpszUserName = lpwfs->lpszUserName; + uc.lpszUrlPath = heap_strdupW(lpszFileName); + + if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + WCHAR *url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0)) + { + lpwh->cache_file = heap_strdupW(filename); + lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE) + { + WARN("Could not create cache file: %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, lpwh->cache_file); + lpwh->cache_file = NULL; + } + } + HeapFree(GetProcessHeap(), 0, url); + } + HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath); + } hIC = lpwfs->lpAppInfo; if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) @@ -1339,16 +1420,20 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, if (lpwh) { - iar.dwResult = (DWORD)handle; + iar.dwResult = (DWORD_PTR)handle; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, &iar, sizeof(INTERNET_ASYNC_RESULT)); } - iar.dwResult = (DWORD)bSuccess; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); + if(bSuccess) { + FTP_ReceiveRequestData(lpwh, TRUE); + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, + &iar, sizeof(INTERNET_ASYNC_RESULT)); + } } lend: @@ -1359,6 +1444,119 @@ lend: } +/*********************************************************************** + * FtpOpenFileA (WININET.@) + * + * Open a remote file for writing or reading + * + * RETURNS + * HINTERNET handle on success + * NULL on failure + * + */ +HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, + LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, + DWORD_PTR dwContext) +{ + LPWSTR lpwzFileName; + HINTERNET ret; + + lpwzFileName = heap_strdupAtoW(lpszFileName); + ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext); + HeapFree(GetProcessHeap(), 0, lpwzFileName); + return ret; +} + + +static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest) +{ + struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; + + TRACE("%p\n", lpwfs); + + FTP_FtpOpenFileW(lpwfs, req->lpszFilename, + req->dwAccess, req->dwFlags, req->dwContext); + HeapFree(GetProcessHeap(), 0, req->lpszFilename); +} + +/*********************************************************************** + * FtpOpenFileW (WININET.@) + * + * Open a remote file for writing or reading + * + * RETURNS + * HINTERNET handle on success + * NULL on failure + * + */ +HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession, + LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, + DWORD_PTR dwContext) +{ + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; + HINTERNET r = NULL; + + TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession, + debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext); + + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); + if (!lpwfs) + { + INTERNET_SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (WH_HFTPSESSION != lpwfs->hdr.htype) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + goto lend; + } + + if ((!lpszFileName) || + ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) || + ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)) + { + INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + goto lend; + } + + if (lpwfs->download_in_progress != NULL) + { + INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); + goto lend; + } + + hIC = lpwfs->lpAppInfo; + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_FTPOPENFILEW *req; + + workRequest.asyncproc = AsyncFtpOpenFileProc; + workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); + req = &workRequest.u.FtpOpenFileW; + req->lpszFilename = heap_strdupW(lpszFileName); + req->dwAccess = fdwAccess; + req->dwFlags = dwFlags; + req->dwContext = dwContext; + + INTERNET_AsyncCall(&workRequest); + r = NULL; + } + else + { + r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext); + } + +lend: + WININET_Release( &lpwfs->hdr ); + + return r; +} + + /*********************************************************************** * FtpGetFileA (WININET.@) * @@ -1377,8 +1575,8 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN LPWSTR lpwzNewFile; BOOL ret; - lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL; - lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL; + lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile); + lpwzNewFile = heap_strdupAtoW(lpszNewFile); ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); HeapFree(GetProcessHeap(), 0, lpwzRemoteFile); @@ -1390,7 +1588,7 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN static void AsyncFtpGetFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1416,8 +1614,8 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; if (!lpszRemoteFile || !lpszNewFile) @@ -1426,7 +1624,7 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet ); + lpwfs = (ftp_session_t*) WININET_GetObject( hInternet ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1460,14 +1658,14 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps workRequest.asyncproc = AsyncFtpGetFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpGetFileW; - req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile); - req->lpszNewFile = WININET_strdupW(lpszNewFile); + req->lpszRemoteFile = heap_strdupW(lpszRemoteFile); + req->lpszNewFile = heap_strdupW(lpszNewFile); req->dwLocalFlagsAttribute = dwLocalFlagsAttribute; req->fFailIfExists = fFailIfExists; req->dwFlags = dwInternetFlags; req->dwContext = dwContext; - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1492,13 +1690,13 @@ lend: * FALSE on failure * */ -static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, +static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext) { BOOL bSuccess = FALSE; HANDLE hFile; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile)); @@ -1537,7 +1735,10 @@ static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, } if (lpwfs->lstnSocket != -1) + { closesocket(lpwfs->lstnSocket); + lpwfs->lstnSocket = -1; + } CloseHandle(hFile); @@ -1584,7 +1785,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) LPWSTR lpwzFileName; BOOL ret; - lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL; + lpwzFileName = heap_strdupAtoW(lpszFileName); ret = FtpDeleteFileW(hFtpSession, lpwzFileName); HeapFree(GetProcessHeap(), 0, lpwzFileName); return ret; @@ -1593,7 +1794,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1613,11 +1814,11 @@ static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1651,9 +1852,9 @@ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName) workRequest.asyncproc = AsyncFtpDeleteFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpDeleteFileW; - req->lpszFilename = WININET_strdupW(lpszFileName); + req->lpszFilename = heap_strdupW(lpszFileName); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1676,11 +1877,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName) +BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("%p\n", lpwfs); @@ -1729,7 +1930,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) LPWSTR lpwzDirectory; BOOL ret; - lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL; + lpwzDirectory = heap_strdupAtoW(lpszDirectory); ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory); HeapFree(GetProcessHeap(), 0, lpwzDirectory); return ret; @@ -1738,7 +1939,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1758,11 +1959,11 @@ static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1796,9 +1997,9 @@ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory) workRequest.asyncproc = AsyncFtpRemoveDirectoryProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRemoveDirectoryW; - req->lpszDirectory = WININET_strdupW(lpszDirectory); + req->lpszDirectory = heap_strdupW(lpszDirectory); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1821,11 +2022,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory) +BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -1876,8 +2077,8 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes LPWSTR lpwzDest; BOOL ret; - lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL; - lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL; + lpwzSrc = heap_strdupAtoW(lpszSrc); + lpwzDest = heap_strdupAtoW(lpszDest); ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest); HeapFree(GetProcessHeap(), 0, lpwzSrc); HeapFree(GetProcessHeap(), 0, lpwzDest); @@ -1887,7 +2088,7 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) { struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW; - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr; + ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr; TRACE("%p\n", lpwfs); @@ -1908,11 +2109,11 @@ static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest) */ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest) { - LPWININETFTPSESSIONW lpwfs; - LPWININETAPPINFOW hIC = NULL; + ftp_session_t *lpwfs; + appinfo_t *hIC = NULL; BOOL r = FALSE; - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession ); + lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -1946,10 +2147,10 @@ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszD workRequest.asyncproc = AsyncFtpRenameFileProc; workRequest.hdr = WININET_AddRef( &lpwfs->hdr ); req = &workRequest.u.FtpRenameFileW; - req->lpszSrcFile = WININET_strdupW(lpszSrc); - req->lpszDestFile = WININET_strdupW(lpszDest); + req->lpszSrcFile = heap_strdupW(lpszSrc); + req->lpszDestFile = heap_strdupW(lpszDest); - r = INTERNET_AsyncCall(&workRequest); + r = res_to_le(INTERNET_AsyncCall(&workRequest)); } else { @@ -1972,12 +2173,11 @@ lend: * FALSE on failure * */ -BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs, - LPCWSTR lpszSrc, LPCWSTR lpszDest) +BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest) { INT nResCode; BOOL bSuccess = FALSE; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; TRACE("\n"); @@ -2040,7 +2240,7 @@ BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - if (!(cmdW = WININET_strdup_AtoW(lpszCommand))) + if (!(cmdW = heap_strdupAtoW(lpszCommand))) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -2059,7 +2259,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) { BOOL r = FALSE; - LPWININETFTPSESSIONW lpwfs; + ftp_session_t *lpwfs; LPSTR cmd = NULL; DWORD len, nBytesSent= 0; INT nResCode, nRC = 0; @@ -2079,7 +2279,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags return FALSE; } - lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + lpwfs = (ftp_session_t*) WININET_GetObject( hConnect ); if (!lpwfs) { INTERNET_SetLastError(ERROR_INVALID_HANDLE); @@ -2142,9 +2342,9 @@ lend: * * Deallocate session handle */ -static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void FTPSESSION_Destroy(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2152,12 +2352,13 @@ static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); + HeapFree(GetProcessHeap(), 0, lpwfs->servername); HeapFree(GetProcessHeap(), 0, lpwfs); } -static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) +static void FTPSESSION_CloseConnection(object_header_t *hdr) { - LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr; + ftp_session_t *lpwfs = (ftp_session_t*) hdr; TRACE("\n"); @@ -2180,7 +2381,7 @@ static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -2197,7 +2398,7 @@ static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl FTPSESSIONVtbl = { +static const object_vtbl_t FTPSESSIONVtbl = { FTPSESSION_Destroy, FTPSESSION_CloseConnection, FTPSESSION_QueryOption, @@ -2230,7 +2431,7 @@ static const HANDLEHEADERVtbl FTPSESSIONVtbl = { * */ -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags) @@ -2247,8 +2448,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, INT nsocket = -1; UINT sock_namelen; BOOL bSuccess = FALSE; - LPWININETFTPSESSIONW lpwfs = NULL; + ftp_session_t *lpwfs = NULL; HINTERNET handle = NULL; + char szaddr[INET_ADDRSTRLEN]; TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n", hIC, debugstr_w(lpszServerName), @@ -2256,13 +2458,13 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, assert( hIC->hdr.htype == WH_HINIT ); - if (NULL == lpszUserName && NULL != lpszPassword) + if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword) { INTERNET_SetLastError(ERROR_INVALID_PARAMETER); goto lerror; } - lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW)); + lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_session_t)); if (NULL == lpwfs) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -2270,7 +2472,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (nServerPort == INTERNET_INVALID_PORT_NUMBER) - nServerPort = INTERNET_DEFAULT_FTP_PORT; + lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT; + else + lpwfs->serverport = nServerPort; lpwfs->hdr.htype = WH_HFTPSESSION; lpwfs->hdr.vtbl = &FTPSESSIONVtbl; @@ -2302,12 +2506,12 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if(hIC->lpszProxyBypass) FIXME("Proxy bypass is ignored.\n"); } - if ( !lpszUserName) { + if (!lpszUserName || !strlenW(lpszUserName)) { HKEY key; WCHAR szPassword[MAX_PATH]; DWORD len = sizeof(szPassword); - lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername); + lpwfs->lpszUserName = heap_strdupW(szDefaultUsername); RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key); if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) { @@ -2320,23 +2524,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, RegCloseKey(key); TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword)); - lpwfs->lpszPassword = WININET_strdupW(szPassword); + lpwfs->lpszPassword = heap_strdupW(szPassword); } else { - lpwfs->lpszUserName = WININET_strdupW(lpszUserName); - - if (lpszPassword) - lpwfs->lpszPassword = WININET_strdupW(lpszPassword); - else - lpwfs->lpszPassword = WININET_strdupW(szEmpty); + lpwfs->lpszUserName = heap_strdupW(lpszUserName); + lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty); } + lpwfs->servername = heap_strdupW(lpszServerName); /* Don't send a handle created callback if this handle was created with InternetOpenUrl */ if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL)) { INTERNET_ASYNC_RESULT iar; - iar.dwResult = (DWORD)handle; + iar.dwResult = (DWORD_PTR)handle; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&hIC->hdr, dwContext, @@ -2345,16 +2546,25 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + (LPWSTR) lpszServerName, (strlenW(lpszServerName)+1) * sizeof(WCHAR)); - if (!GetAddress(lpszServerName, nServerPort, &socketAddr)) + sock_namelen = sizeof(socketAddr); + if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen)) { INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); goto lerror; } + if (socketAddr.sin_family != AF_INET) + { + WARN("unsupported address family %d\n", socketAddr.sin_family); + INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + goto lerror; + } + + inet_ntop(socketAddr.sin_family, &socketAddr.sin_addr, szaddr, sizeof(szaddr)); SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED, - (LPWSTR) lpszServerName, strlenW(lpszServerName)); + szaddr, strlen(szaddr)+1); nsocket = socket(AF_INET,SOCK_STREAM,0); if (nsocket == -1) @@ -2364,19 +2574,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); - if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0) + if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0) { ERR("Unable to connect (%s)\n", strerror(errno)); INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); + closesocket(nsocket); } else { TRACE("Connected to server\n"); lpwfs->sndSocket = nsocket; SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, - &socketAddr, sizeof(struct sockaddr_in)); + szaddr, strlen(szaddr)+1); sock_namelen = sizeof(lpwfs->socketAddress); getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); @@ -2397,16 +2608,6 @@ lerror: handle = NULL; } - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - INTERNET_ASYNC_RESULT iar; - - iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); - SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE, - &iar, sizeof(INTERNET_ASYNC_RESULT)); - } - return handle; } @@ -2421,7 +2622,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2465,7 +2666,7 @@ lend: * */ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { DWORD len; CHAR *buf; @@ -2520,10 +2721,10 @@ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, * */ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, - INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext) + INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext) { BOOL ret; - LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL; + LPSTR lpszParamA = heap_strdupWtoA(lpszParam); ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext); HeapFree(GetProcessHeap(), 0, lpszParamA); return ret; @@ -2539,7 +2740,7 @@ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam, * 0 on failure * */ -INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext) +INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext) { LPSTR lpszResponse = INTERNET_GetResponseBuffer(); DWORD nRecv; @@ -2602,7 +2803,7 @@ lerror: * NULL on failure * */ -static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPassword(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2642,7 +2843,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendAccount(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2672,7 +2873,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL bSuccess = FALSE; @@ -2719,10 +2920,10 @@ lend: * FALSE on failure * */ -static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs) { BOOL bSuccess = FALSE; - socklen_t namelen = sizeof(struct sockaddr_in); + socklen_t namelen = sizeof(lpwfs->lstnSocketAddress); TRACE("\n"); @@ -2737,9 +2938,9 @@ static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs) lpwfs->lstnSocketAddress = lpwfs->socketAddress; /* and get the system to assign us a port */ - lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0); + lpwfs->lstnSocketAddress.sin_port = htons(0); - if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1) + if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1) { TRACE("Unable to bind socket\n"); goto lend; @@ -2778,7 +2979,7 @@ lend: * (i.e. it sends it always), * so we probably don't want to do that either. */ -static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType) +static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType) { INT nResCode; WCHAR type[] = { 'I','\0' }; @@ -2816,7 +3017,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) +static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize) { INT nResCode; BOOL bSuccess = FALSE; @@ -2860,7 +3061,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPort(ftp_session_t *lpwfs) { static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'}; INT nResCode; @@ -2904,7 +3105,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_DoPassive(ftp_session_t *lpwfs) { INT nResCode; BOOL bSuccess = FALSE; @@ -2976,7 +3177,7 @@ lend: } -static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) +static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs) { if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { @@ -3005,7 +3206,7 @@ static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs) * FALSE on failure * */ -static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) +static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket) { struct sockaddr_in saddr; socklen_t addrlen = sizeof(struct sockaddr); @@ -3014,6 +3215,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) { *nDataSocket = lpwfs->pasvSocket; + lpwfs->pasvSocket = -1; } else { @@ -3035,7 +3237,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket) * FALSE on failure * */ -static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { BY_HANDLE_FILE_INFORMATION fi; DWORD nBytesRead = 0; @@ -3116,7 +3318,7 @@ static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFi * 0 on failure * */ -static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) +static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType) { INT nResCode; BOOL ret; @@ -3162,7 +3364,7 @@ lend: * FALSE on failure * */ -static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile) +static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile) { DWORD nBytesWritten; INT nRC = 0; @@ -3202,7 +3404,7 @@ recv_end: * * Deallocate session handle */ -static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) +static void FTPFINDNEXT_Destroy(object_header_t *hdr) { LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr; DWORD i; @@ -3220,7 +3422,7 @@ static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwfn); } -static DWORD WINAPI FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) +static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data) { WIN32_FIND_DATAW *find_data = data; DWORD res = ERROR_SUCCESS; @@ -3260,7 +3462,7 @@ static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest) FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData); } -static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3277,7 +3479,7 @@ static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) +static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data) { WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr; @@ -3299,7 +3501,7 @@ static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data) return FTPFINDNEXT_FindNextFileProc(find, data); } -static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { +static const object_vtbl_t FTPFINDNEXTVtbl = { FTPFINDNEXT_Destroy, NULL, FTPFINDNEXT_QueryOption, @@ -3308,6 +3510,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { NULL, NULL, NULL, + NULL, FTPFINDNEXT_FindNextFileW }; @@ -3321,7 +3524,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { * NULL on failure * */ -static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext) { DWORD dwSize = 0; @@ -3382,9 +3585,7 @@ static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFi if (lpafp) { - /* Convert 'Unix' time to Windows time */ - RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified), - (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime)); + SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime ); lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime; lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime; @@ -3452,12 +3653,12 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT lpfp->nSize = atol(pszToken); } - lpfp->tmLastModified.tm_sec = 0; - lpfp->tmLastModified.tm_min = 0; - lpfp->tmLastModified.tm_hour = 0; - lpfp->tmLastModified.tm_mday = 0; - lpfp->tmLastModified.tm_mon = 0; - lpfp->tmLastModified.tm_year = 0; + lpfp->tmLastModified.wSecond = 0; + lpfp->tmLastModified.wMinute = 0; + lpfp->tmLastModified.wHour = 0; + lpfp->tmLastModified.wDay = 0; + lpfp->tmLastModified.wMonth = 0; + lpfp->tmLastModified.wYear = 0; /* Determine month */ pszToken = strtok(NULL, szSpace); @@ -3465,38 +3666,35 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT if(strlen(pszToken) >= 3) { pszToken[3] = 0; if((pszTmp = StrStrIA(szMonths, pszToken))) - lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1; + lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1; } /* Determine day */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->tmLastModified.tm_mday = atoi(pszToken); + lpfp->tmLastModified.wDay = atoi(pszToken); /* Determine time or year */ pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if((pszTmp = strchr(pszToken, ':'))) { - struct tm* apTM; - time_t aTime; + SYSTEMTIME curr_time; *pszTmp = 0; pszTmp++; - lpfp->tmLastModified.tm_min = atoi(pszTmp); - lpfp->tmLastModified.tm_hour = atoi(pszToken); - time(&aTime); - apTM = localtime(&aTime); - lpfp->tmLastModified.tm_year = apTM->tm_year; + lpfp->tmLastModified.wMinute = atoi(pszTmp); + lpfp->tmLastModified.wHour = atoi(pszToken); + GetLocalTime( &curr_time ); + lpfp->tmLastModified.wYear = curr_time.wYear; } else { - lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900; - lpfp->tmLastModified.tm_hour = 12; + lpfp->tmLastModified.wYear = atoi(pszToken); + lpfp->tmLastModified.wHour = 12; } - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("File: %s\n", debugstr_w(lpfp->lpszName)); } /* NT way of parsing ... : @@ -3505,32 +3703,31 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz */ else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) { + int mon, mday, year, hour, min; lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */ - sscanf(pszToken, "%d-%d-%d", - &lpfp->tmLastModified.tm_mon, - &lpfp->tmLastModified.tm_mday, - &lpfp->tmLastModified.tm_year); + sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year); + lpfp->tmLastModified.wDay = mday; + lpfp->tmLastModified.wMonth = mon; + lpfp->tmLastModified.wYear = year; /* Hacky and bad Y2K protection :-) */ - if (lpfp->tmLastModified.tm_year < 70) - lpfp->tmLastModified.tm_year += 100; - + if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000; + pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - sscanf(pszToken, "%d:%d", - &lpfp->tmLastModified.tm_hour, - &lpfp->tmLastModified.tm_min); + sscanf(pszToken, "%d:%d", &hour, &min); + lpfp->tmLastModified.wHour = hour; + lpfp->tmLastModified.wMinute = min; if((pszToken[5] == 'P') && (pszToken[6] == 'M')) { - lpfp->tmLastModified.tm_hour += 12; + lpfp->tmLastModified.wHour += 12; } - lpfp->tmLastModified.tm_sec = 0; + lpfp->tmLastModified.wSecond = 0; + + TRACE("Mod time: %02d:%02d:%02d %04d/%02d/%02d\n", + lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond, + lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay); - TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n", - lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec, - (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year, - lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday); - pszToken = strtok(NULL, szSpace); if(!pszToken) continue; if(!strcasecmp(pszToken, "")) { @@ -3546,7 +3743,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT pszToken = strtok(NULL, szSpace); if(!pszToken) continue; - lpfp->lpszName = WININET_strdup_AtoW(pszToken); + lpfp->lpszName = heap_strdupAtoW(pszToken); TRACE("Name: %s\n", debugstr_w(lpfp->lpszName)); } /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */ @@ -3578,7 +3775,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT * TRUE on success * FALSE on failure */ -static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile, +static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW *lpafp, LPDWORD dwfp) { BOOL bSuccess = TRUE; diff --git a/reactos/dll/win32/wininet/http.c b/reactos/dll/win32/wininet/http.c index f0ad6beddc1..5b7459db6f7 100644 --- a/reactos/dll/win32/wininet/http.c +++ b/reactos/dll/win32/wininet/http.c @@ -29,6 +29,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_SYS_SOCKET_H # include @@ -44,6 +48,9 @@ #endif #include #include +#ifdef HAVE_ZLIB +# include +#endif #include "windef.h" #include "winbase.h" @@ -59,6 +66,7 @@ #include "internet.h" #include "wine/debug.h" +#include "wine/exception.h" #include "wine/unicode.h" #include "inet_ntop.c" @@ -67,23 +75,77 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0}; static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0}; -static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0}; -static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0}; -static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0}; -static const WCHAR szHost[] = { 'H','o','s','t',0 }; +static const WCHAR szOK[] = {'O','K',0}; +static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0}; +static const WCHAR hostW[] = { 'H','o','s','t',0 }; static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 }; static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 }; static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0}; static const WCHAR szGET[] = { 'G','E','T', 0 }; +static const WCHAR szHEAD[] = { 'H','E','A','D', 0 }; +static const WCHAR szCrLf[] = {'\r','\n', 0}; + +static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; +static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; +static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; +static const WCHAR szAge[] = { 'A','g','e',0 }; +static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; +static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; +static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; +static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; +static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; +static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; +static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; +static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; +static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; +static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; +static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; +static const WCHAR szDate[] = { 'D','a','t','e',0 }; +static const WCHAR szFrom[] = { 'F','r','o','m',0 }; +static const WCHAR szETag[] = { 'E','T','a','g',0 }; +static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; +static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; +static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; +static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; +static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; +static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; +static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; +static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; +static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; +static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; +static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; +static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; +static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; +static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; +static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; +static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; +static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; +static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; +static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; +static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; +static const WCHAR szURI[] = { 'U','R','I',0 }; +static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; +static const WCHAR szVary[] = { 'V','a','r','y',0 }; +static const WCHAR szVia[] = { 'V','i','a',0 }; +static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; +static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; #define MAXHOSTNAME 100 #define MAX_FIELD_VALUE_LEN 256 #define MAX_FIELD_LEN 256 -#define HTTP_REFERER g_szReferer -#define HTTP_ACCEPT g_szAccept -#define HTTP_USERAGENT g_szUserAgent +#define HTTP_REFERER szReferer +#define HTTP_ACCEPT szAccept +#define HTTP_USERAGENT szUser_Agent #define HTTP_ADDHDR_FLAG_ADD 0x20000000 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000 @@ -108,23 +170,54 @@ struct HttpAuthInfo BOOL finished; /* finished authenticating */ }; -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr); -static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear); -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier); + +struct gzip_stream_t { +#ifdef HAVE_ZLIB + z_stream zstream; +#endif + BYTE buf[8192]; + DWORD buf_size; + DWORD buf_pos; + BOOL end_of_data; +}; + +typedef struct _authorizationData +{ + struct list entry; + + LPWSTR lpszwHost; + LPWSTR lpszwRealm; + LPSTR lpszAuthorization; + UINT AuthorizationLen; +} authorizationData; + +static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache); + +static CRITICAL_SECTION authcache_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &authcache_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") } +}; +static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static DWORD HTTP_OpenConnection(http_request_t *req); +static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); +static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr); -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request); -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index); +static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); +static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request); +static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index); static LPWSTR HTTP_build_req( LPCWSTR *list, int len ); -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD - dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD - lpdwIndex); -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl); +static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD); +static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl); static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin); -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field); -static void HTTP_DrainContent(WININETHTTPREQW *req); +static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field); +static void HTTP_DrainContent(http_request_t *req); +static BOOL HTTP_FinishedReading(http_request_t *req); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) +static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head) { int HeaderIndex = 0; HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE); @@ -134,6 +227,91 @@ LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) return &req->pCustHeaders[HeaderIndex]; } +#ifdef HAVE_ZLIB + +static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size) +{ + return HeapAlloc(GetProcessHeap(), 0, items*size); +} + +static void wininet_zfree(voidpf opaque, voidpf address) +{ + HeapFree(GetProcessHeap(), 0, address); +} + +static void init_gzip_stream(http_request_t *req) +{ + gzip_stream_t *gzip_stream; + int index, zres; + + gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t)); + gzip_stream->zstream.zalloc = wininet_zalloc; + gzip_stream->zstream.zfree = wininet_zfree; + gzip_stream->zstream.opaque = NULL; + gzip_stream->zstream.next_in = NULL; + gzip_stream->zstream.avail_in = 0; + gzip_stream->zstream.next_out = NULL; + gzip_stream->zstream.avail_out = 0; + gzip_stream->buf_pos = 0; + gzip_stream->buf_size = 0; + gzip_stream->end_of_data = FALSE; + + zres = inflateInit2(&gzip_stream->zstream, 0x1f); + if(zres != Z_OK) { + ERR("inflateInit failed: %d\n", zres); + HeapFree(GetProcessHeap(), 0, gzip_stream); + return; + } + + req->gzip_stream = gzip_stream; + + index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE); + if(index != -1) + HTTP_DeleteCustomHeader(req, index); +} + +#else + +static void init_gzip_stream(http_request_t *req) +{ + ERR("gzip stream not supported, missing zlib.\n"); +} + +#endif + +/* set the request content length based on the headers */ +static DWORD set_content_length( http_request_t *lpwhr ) +{ + static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; + WCHAR encoding[20]; + DWORD size; + + size = sizeof(lpwhr->dwContentLength); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, + &lpwhr->dwContentLength, &size, NULL) != ERROR_SUCCESS) + lpwhr->dwContentLength = ~0u; + + size = sizeof(encoding); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS && + !strcmpiW(encoding, szChunked)) + { + lpwhr->dwContentLength = ~0u; + lpwhr->read_chunked = TRUE; + } + + if(lpwhr->decoding) { + int encoding_idx; + + static const WCHAR gzipW[] = {'g','z','i','p',0}; + + encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE); + if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW)) + init_gzip_stream(lpwhr); + } + + return lpwhr->dwContentLength; +} + /*********************************************************************** * HTTP_Tokenize (internal) * @@ -146,21 +324,26 @@ static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) int i; LPCWSTR next_token; - /* empty string has no tokens */ - if (*string) - tokens++; - /* count tokens */ - for (i = 0; string[i]; i++) - if (!strncmpW(string+i, token_string, strlenW(token_string))) - { - DWORD j; + if (string) + { + /* empty string has no tokens */ + if (*string) tokens++; - /* we want to skip over separators, but not the null terminator */ - for (j = 0; j < strlenW(token_string) - 1; j++) - if (!string[i+j]) - break; - i += j; + /* count tokens */ + for (i = 0; string[i]; i++) + { + if (!strncmpW(string+i, token_string, strlenW(token_string))) + { + DWORD j; + tokens++; + /* we want to skip over separators, but not the null terminator */ + for (j = 0; j < strlenW(token_string) - 1; j++) + if (!string[i+j]) + break; + i += j; + } } + } /* add 1 for terminating NULL */ token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array)); @@ -194,33 +377,14 @@ static void HTTP_FreeTokens(LPWSTR * token_array) HeapFree(GetProcessHeap(), 0, token_array); } -/* ********************************************************************** - * - * Helper functions for the HttpSendRequest(Ex) functions - * - */ -static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) -{ - struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr; - - TRACE("%p\n", lpwhr); - - HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, - req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, - req->dwContentLength, req->bEndRequest); - - HeapFree(GetProcessHeap(), 0, req->lpszHeader); -} - -static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) +static void HTTP_FixURL(http_request_t *lpwhr) { static const WCHAR szSlash[] = { '/',0 }; static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 }; /* If we don't have a path we set it to root */ if (NULL == lpwhr->lpszPath) - lpwhr->lpszPath = WININET_strdupW(szSlash); + lpwhr->lpszPath = heap_strdupW(szSlash); else /* remove \r and \n*/ { int nLen = strlenW(lpwhr->lpszPath); @@ -249,7 +413,7 @@ static void HTTP_FixURL( LPWININETHTTPREQW lpwhr) } } -static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) +static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) { LPWSTR requestString; DWORD len, n; @@ -258,7 +422,6 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve LPWSTR p; static const WCHAR szSpace[] = { ' ',0 }; - static const WCHAR szcrlf[] = {'\r','\n', 0}; static const WCHAR szColon[] = { ':',' ',0 }; static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; @@ -279,7 +442,7 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve { if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) { - req[n++] = szcrlf; + req[n++] = szCrLf; req[n++] = lpwhr->pCustHeaders[i].lpszField; req[n++] = szColon; req[n++] = lpwhr->pCustHeaders[i].lpszValue; @@ -309,103 +472,176 @@ static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR ve return requestString; } -static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr ) +static void HTTP_ProcessCookies( http_request_t *lpwhr ) { - static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; int HeaderIndex; + int numCookies = 0; LPHTTPHEADERW setCookieHeader; - HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, 0, FALSE); - if (HeaderIndex == -1) - return; - setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) + while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1) { - int nPosStart = 0, nPosEnd = 0, len; - static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0}; + setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex]; - while (setCookieHeader->lpszValue[nPosEnd] != '\0') + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue) { - LPWSTR buf_cookie, cookie_name, cookie_data; + int len; + static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR buf_url; - LPWSTR domain = NULL; LPHTTPHEADERW Host; - int nEqualPos = 0; - while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' && - setCookieHeader->lpszValue[nPosEnd] != '\0') - { - nPosEnd++; - } - if (setCookieHeader->lpszValue[nPosEnd] == ';') - { - /* fixme: not case sensitive, strcasestr is gnu only */ - int nDomainPosEnd = 0; - int nDomainPosStart = 0, nDomainLength = 0; - static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0}; - LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain); - if (lpszDomain) - { /* they have specified their own domain, lets use it */ - while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' && - lpszDomain[nDomainPosEnd] != '\0') - { - nDomainPosEnd++; - } - nDomainPosStart = strlenW(szDomain); - nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1; - domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR)); - lstrcpynW(domain, &lpszDomain[nDomainPosStart], nDomainLength + 1); - } - } - if (setCookieHeader->lpszValue[nPosEnd] == '\0') break; - buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR)); - lstrcpynW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart) + 1); - TRACE("%s\n", debugstr_w(buf_cookie)); - while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0') - { - nEqualPos++; - } - if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0') - { - HeapFree(GetProcessHeap(), 0, buf_cookie); - break; - } - - cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR)); - lstrcpynW(cookie_name, buf_cookie, nEqualPos + 1); - cookie_data = &buf_cookie[nEqualPos + 1]; - - Host = HTTP_GetHeader(lpwhr,szHost); - len = lstrlenW((domain ? domain : (Host?Host->lpszValue:NULL))) + - strlenW(lpwhr->lpszPath) + 9; + Host = HTTP_GetHeader(lpwhr, hostW); + len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath); buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - sprintfW(buf_url, szFmt, (domain ? domain : (Host?Host->lpszValue:NULL))); /* FIXME PATH!!! */ - InternetSetCookieW(buf_url, cookie_name, cookie_data); + sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath); + InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue); HeapFree(GetProcessHeap(), 0, buf_url); - HeapFree(GetProcessHeap(), 0, buf_cookie); - HeapFree(GetProcessHeap(), 0, cookie_name); - HeapFree(GetProcessHeap(), 0, domain); - nPosStart = nPosEnd; } + numCookies++; + } +} + +static void strip_spaces(LPWSTR start) +{ + LPWSTR str = start; + LPWSTR end; + + while (*str == ' ' && *str != '\0') + str++; + + if (str != start) + memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); + + end = start + strlenW(start) - 1; + while (end >= start && *end == ' ') + { + *end = '\0'; + end--; } } -static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue ) +static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm ) { static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */ - return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && + static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */ + BOOL is_basic; + is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) && ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]); + if (is_basic && pszRealm) + { + LPCWSTR token; + LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)]; + LPCWSTR realm; + ptr++; + *pszRealm=NULL; + token = strchrW(ptr,'='); + if (!token) + return TRUE; + realm = ptr; + while (*realm == ' ' && *realm != '\0') + realm++; + if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) && + (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '=')) + { + token++; + while (*token == ' ' && *token != '\0') + token++; + if (*token == '\0') + return TRUE; + *pszRealm = heap_strdupW(token); + strip_spaces(*pszRealm); + } + } + + return is_basic; +} + +static void destroy_authinfo( struct HttpAuthInfo *authinfo ) +{ + if (!authinfo) return; + + if (SecIsValidHandle(&authinfo->ctx)) + DeleteSecurityContext(&authinfo->ctx); + if (SecIsValidHandle(&authinfo->cred)) + FreeCredentialsHandle(&authinfo->cred); + + HeapFree(GetProcessHeap(), 0, authinfo->auth_data); + HeapFree(GetProcessHeap(), 0, authinfo->scheme); + HeapFree(GetProcessHeap(), 0, authinfo); +} + +static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data) +{ + authorizationData *ad; + UINT rc = 0; + + TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, authorizationData, entry) + { + if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm)) + { + TRACE("Authorization found in cache\n"); + *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen); + memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen); + rc = ad->AuthorizationLen; + break; + } + } + LeaveCriticalSection(&authcache_cs); + return rc; +} + +static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len) +{ + struct list *cursor; + authorizationData* ad = NULL; + + TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len)); + + EnterCriticalSection(&authcache_cs); + LIST_FOR_EACH(cursor, &basicAuthorizationCache) + { + authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry); + if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm)) + { + ad = check; + break; + } + } + + if (ad) + { + TRACE("Found match in cache, replacing\n"); + HeapFree(GetProcessHeap(),0,ad->lpszAuthorization); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + } + else + { + ad = HeapAlloc(GetProcessHeap(),0,sizeof(authorizationData)); + ad->lpszwHost = heap_strdupW(host); + ad->lpszwRealm = heap_strdupW(realm); + ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len); + memcpy(ad->lpszAuthorization, auth_data, auth_data_len); + ad->AuthorizationLen = auth_data_len; + list_add_head(&basicAuthorizationCache,&ad->entry); + TRACE("authorization cached\n"); + } + LeaveCriticalSection(&authcache_cs); } -static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, +static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue, struct HttpAuthInfo **ppAuthInfo, - LPWSTR domain_and_username, LPWSTR password ) + LPWSTR domain_and_username, LPWSTR password, + LPWSTR host ) { SECURITY_STATUS sec_status; struct HttpAuthInfo *pAuthInfo = *ppAuthInfo; BOOL first = FALSE; + LPWSTR szRealm = NULL; TRACE("%s\n", debugstr_w(pszAuthValue)); @@ -426,10 +662,10 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, pAuthInfo->auth_data_len = 0; pAuthInfo->finished = FALSE; - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,NULL)) { static const WCHAR szBasic[] = {'B','a','s','i','c',0}; - pAuthInfo->scheme = WININET_strdupW(szBasic); + pAuthInfo->scheme = heap_strdupW(szBasic); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -441,7 +677,7 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, PVOID pAuthData; SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity; - pAuthInfo->scheme = WININET_strdupW(pszAuthValue); + pAuthInfo->scheme = heap_strdupW(pszAuthValue); if (!pAuthInfo->scheme) { HeapFree(GetProcessHeap(), 0, pAuthInfo); @@ -513,33 +749,50 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, return FALSE; } - if (is_basic_auth_value(pszAuthValue)) + if (is_basic_auth_value(pszAuthValue,&szRealm)) { int userlen; int passlen; - char *auth_data; - - TRACE("basic authentication\n"); + char *auth_data = NULL; + UINT auth_data_len = 0; - /* we don't cache credentials for basic authentication, so we can't - * retrieve them if the application didn't pass us any credentials */ - if (!domain_and_username) return FALSE; + TRACE("basic authentication realm %s\n",debugstr_w(szRealm)); - userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); - passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); + if (!domain_and_username) + { + if (host && szRealm) + auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data); + if (auth_data_len == 0) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } + } + else + { + userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL); + passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL); - /* length includes a nul terminator, which will be re-used for the ':' */ - auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); - if (!auth_data) - return FALSE; + /* length includes a nul terminator, which will be re-used for the ':' */ + auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen); + if (!auth_data) + { + HeapFree(GetProcessHeap(),0,szRealm); + return FALSE; + } - WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); - auth_data[userlen] = ':'; - WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL); + auth_data[userlen] = ':'; + WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL); + auth_data_len = userlen + 1 + passlen; + if (host && szRealm) + cache_basic_authorization(host, szRealm, auth_data, auth_data_len); + } pAuthInfo->auth_data = auth_data; - pAuthInfo->auth_data_len = userlen + 1 + passlen; + pAuthInfo->auth_data_len = auth_data_len; pAuthInfo->finished = TRUE; + HeapFree(GetProcessHeap(),0,szRealm); return TRUE; } @@ -602,8 +855,9 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, else { ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status); - pAuthInfo->finished = TRUE; HeapFree(GetProcessHeap(), 0, out.pvBuffer); + destroy_authinfo(pAuthInfo); + *ppAuthInfo = NULL; return FALSE; } } @@ -614,14 +868,13 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, /*********************************************************************** * HTTP_HttpAddRequestHeadersW (internal) */ -static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, +static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { LPWSTR lpszStart; LPWSTR lpszEnd; LPWSTR buffer; - BOOL bSuccess = FALSE; - DWORD len; + DWORD len, res = ERROR_HTTP_INVALID_HEADER; TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength)); @@ -642,7 +895,7 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, while (*lpszEnd != '\0') { - if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n') + if (*lpszEnd == '\r' || *lpszEnd == '\n') break; lpszEnd++; } @@ -650,28 +903,35 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, if (*lpszStart == '\0') break; - if (*lpszEnd == '\r') + if (*lpszEnd == '\r' || *lpszEnd == '\n') { *lpszEnd = '\0'; - lpszEnd += 2; /* Jump over \r\n */ + lpszEnd++; /* Jump over newline */ } TRACE("interpreting header %s\n", debugstr_w(lpszStart)); + if (*lpszStart == '\0') + { + /* Skip 0-length headers */ + lpszStart = lpszEnd; + res = ERROR_SUCCESS; + continue; + } pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart); if (pFieldAndValue) { - bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); - if (bSuccess) - bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], + res = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]); + if (res == ERROR_SUCCESS) + res = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ); HTTP_FreeTokens(pFieldAndValue); } lpszStart = lpszEnd; - } while (bSuccess); + } while (res == ERROR_SUCCESS); HeapFree(GetProcessHeap(), 0, buffer); - return bSuccess; + return res; } /*********************************************************************** @@ -693,26 +953,23 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier); if (!lpszHeader) return TRUE; - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); -lend: + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (lpwhr && lpwhr->hdr.htype == WH_HHTTPREQ) + res = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier ); if( lpwhr ) WININET_Release( &lpwhr->hdr ); - return bSuccess; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -748,267 +1005,57 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, } /*********************************************************************** - * HttpEndRequestA (WININET.@) + * HttpOpenRequestA (WININET.@) * - * Ends an HTTP request that was started by HttpSendRequestEx + * Open a HTTP request handle * * RETURNS - * TRUE if successful - * FALSE on failure + * HINTERNET a HTTP request handle on success + * NULL on failure * */ -BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, + LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion, + LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext) { - LPINTERNET_BUFFERSA ptr; - LPINTERNET_BUFFERSW lpBuffersOutW,ptrW; - BOOL rc = FALSE; - - TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags, - dwContext); + LPWSTR szVerb = NULL, szObjectName = NULL; + LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; + INT acceptTypesCount; + HINTERNET rc = FALSE; + LPCSTR *types; - ptr = lpBuffersOut; - if (ptr) - lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW)); - else - lpBuffersOutW = NULL; + TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, + debugstr_a(lpszVerb), debugstr_a(lpszObjectName), + debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); - ptrW = lpBuffersOutW; - while (ptr) + if (lpszVerb) { - if (ptr->lpvBuffer && ptr->dwBufferLength) - ptrW->lpvBuffer = HeapAlloc(GetProcessHeap(),0,ptr->dwBufferLength); - ptrW->dwBufferLength = ptr->dwBufferLength; - ptrW->dwBufferTotal= ptr->dwBufferTotal; - - if (ptr->Next) - ptrW->Next = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - sizeof(INTERNET_BUFFERSW)); - - ptr = ptr->Next; - ptrW = ptrW->Next; - } - - rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext); - - if (lpBuffersOutW) - { - ptrW = lpBuffersOutW; - while (ptrW) - { - LPINTERNET_BUFFERSW ptrW2; - - FIXME("Do we need to translate info out of these buffer?\n"); - - HeapFree(GetProcessHeap(),0,ptrW->lpvBuffer); - ptrW2 = ptrW->Next; - HeapFree(GetProcessHeap(),0,ptrW); - ptrW = ptrW2; - } - } - - return rc; -} - -/*********************************************************************** - * HttpEndRequestW (WININET.@) - * - * Ends an HTTP request that was started by HttpSendRequestEx - * - * RETURNS - * TRUE if successful - * FALSE on failure - * - */ -BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) -{ - BOOL rc = FALSE; - LPWININETHTTPREQW lpwhr; - INT responseLen; - DWORD dwBufferSize; - - TRACE("-->\n"); - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); - - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - if (lpwhr) - WININET_Release( &lpwhr->hdr ); - return FALSE; - } - - lpwhr->hdr.dwFlags |= dwFlags; - lpwhr->hdr.dwContext = dwContext; - - /* We appear to do nothing with lpBuffersOut.. is that correct? */ - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - - responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - rc = TRUE; - - SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); - - /* process cookies here. Is this right? */ - HTTP_ProcessCookies(lpwhr); - - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - if(!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) - { - DWORD dwCode,dwCodeLength=sizeof(DWORD); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,NULL) && - (dwCode==302 || dwCode==301)) - { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; - dwBufferSize=sizeof(szNewLocation); - if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) - { - /* redirects are always GETs */ - HeapFree(GetProcessHeap(),0,lpwhr->lpszVerb); - lpwhr->lpszVerb = WININET_strdupW(szGET); - HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - rc = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (rc) - rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); - } - } - } - - WININET_Release( &lpwhr->hdr ); - TRACE("%i <--\n",rc); - return rc; -} - -/*********************************************************************** - * HttpOpenRequestW (WININET.@) - * - * Open a HTTP request handle - * - * RETURNS - * HINTERNET a HTTP request handle on success - * NULL on failure - * - */ -HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) -{ - LPWININETHTTPSESSIONW lpwhs; - HINTERNET handle = NULL; - - TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, - debugstr_w(lpszVerb), debugstr_w(lpszObjectName), - debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, - dwFlags, dwContext); - if(lpszAcceptTypes!=NULL) - { - int i; - for(i=0;lpszAcceptTypes[i]!=NULL;i++) - TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); - } - - lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession ); - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; - } - - /* - * My tests seem to show that the windows version does not - * become asynchronous until after this point. And anyhow - * if this call was asynchronous then how would you get the - * necessary HINTERNET pointer returned by this function. - * - */ - handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, - lpszVersion, lpszReferrer, lpszAcceptTypes, - dwFlags, dwContext); -lend: - if( lpwhs ) - WININET_Release( &lpwhs->hdr ); - TRACE("returning %p\n", handle); - return handle; -} - - -/*********************************************************************** - * HttpOpenRequestA (WININET.@) - * - * Open a HTTP request handle - * - * RETURNS - * HINTERNET a HTTP request handle on success - * NULL on failure - * - */ -HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, - LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion, - LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) -{ - LPWSTR szVerb = NULL, szObjectName = NULL; - LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL; - INT len, acceptTypesCount; - HINTERNET rc = FALSE; - LPCSTR *types; - - TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, - debugstr_a(lpszVerb), debugstr_a(lpszObjectName), - debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes, - dwFlags, dwContext); - - if (lpszVerb) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 ); - szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if ( !szVerb ) - goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len); + szVerb = heap_strdupAtoW(lpszVerb); + if ( !szVerb ) + goto end; } if (lpszObjectName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 ); - szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); + szObjectName = heap_strdupAtoW(lpszObjectName); if ( !szObjectName ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len ); } if (lpszVersion) { - len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 ); - szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szVersion = heap_strdupAtoW(lpszVersion); if ( !szVersion ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len ); } if (lpszReferrer) { - len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 ); - szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + szReferrer = heap_strdupAtoW(lpszReferrer); if ( !szReferrer ) goto end; - MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len ); } if (lpszAcceptTypes) @@ -1017,12 +1064,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - /* find out how many there are */ - if (((ULONG_PTR)*types >> 16) && **types) + __TRY + { + /* find out how many there are */ + if (*types && **types) + { + TRACE("accept type: %s\n", debugstr_a(*types)); + acceptTypesCount++; + } + } + __EXCEPT_PAGE_FAULT { - TRACE("accept type: %s\n", debugstr_a(*types)); - acceptTypesCount++; + WARN("invalid accept type pointer\n"); } + __ENDTRY; types++; } szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1)); @@ -1032,20 +1087,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 ); - szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!szAcceptTypes[acceptTypesCount]) goto end; - - MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len); - acceptTypesCount++; + if (*types && **types) + szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types); + } + __EXCEPT_PAGE_FAULT + { + /* ignore invalid pointer */ } + __ENDTRY; types++; } szAcceptTypes[acceptTypesCount] = NULL; } - else szAcceptTypes = 0; rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer, @@ -1207,7 +1262,7 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin ) * * Insert or delete the authorization field in the request header. */ -static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) +static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header ) { if (pAuthInfo) { @@ -1250,13 +1305,13 @@ static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthIn return TRUE; } -static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) +static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req) { WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url; DWORD size; size = sizeof(new_location); - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL)) + if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS) { if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL; strcpyW( url, new_location ); @@ -1266,7 +1321,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) static const WCHAR slash[] = { '/',0 }; static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 }; static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 }; - WININETHTTPSESSIONW *session = req->lpHttpSession; + http_session_t *session = req->lpHttpSession; size = 16; /* "https://" + sizeof(port#) + ":/\0" */ size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath ); @@ -1287,8 +1342,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req) /*********************************************************************** * HTTP_DealWithProxy */ -static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, - LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr) +static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr) { WCHAR buf[MAXHOSTNAME]; WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */ @@ -1319,38 +1373,52 @@ static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC, UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT; HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName); + lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName); lpwhs->nServerPort = UrlComponents.nPort; TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort); return TRUE; } -static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + +static DWORD HTTP_ResolveName(http_request_t *lpwhr) { - char szaddr[32]; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + char szaddr[INET6_ADDRSTRLEN]; + http_session_t *lpwhs = lpwhr->lpHttpSession; + const void *addr; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESOLVING_NAME, lpwhs->lpszServerName, - strlenW(lpwhs->lpszServerName)+1); + (strlenW(lpwhs->lpszServerName)+1) * sizeof(WCHAR)); + lpwhs->sa_len = sizeof(lpwhs->socketAddress); if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, - &lpwhs->socketAddress)) + (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len)) + return ERROR_INTERNET_NAME_NOT_RESOLVED; + + switch (lpwhs->socketAddress.ss_family) { - INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); - return FALSE; + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; } - - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_NAME_RESOLVED, szaddr, strlen(szaddr)+1); TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr); - return TRUE; + return ERROR_SUCCESS; } @@ -1360,9 +1428,9 @@ static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr) * Deallocate request handle * */ -static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPREQ_Destroy(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; DWORD i; TRACE("\n"); @@ -1370,13 +1438,14 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) if(lpwhr->hCacheFile) CloseHandle(lpwhr->hCacheFile); - if(lpwhr->lpszCacheFile) { - DeleteFileW(lpwhr->lpszCacheFile); /* FIXME */ - HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); - } + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + DeleteCriticalSection( &lpwhr->read_section ); WININET_Release(&lpwhr->lpHttpSession->hdr); + destroy_authinfo(lpwhr->pAuthInfo); + destroy_authinfo(lpwhr->pProxyAuthInfo); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); @@ -1389,44 +1458,27 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue); } +#ifdef HAVE_ZLIB + if(lpwhr->gzip_stream) { + if(!lpwhr->gzip_stream->end_of_data) + inflateEnd(&lpwhr->gzip_stream->zstream); + HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream); + } +#endif + HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders); HeapFree(GetProcessHeap(), 0, lpwhr); } -static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) +static void HTTPREQ_CloseConnection(object_header_t *hdr) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr; + http_request_t *lpwhr = (http_request_t*) hdr; TRACE("%p\n",lpwhr); if (!NETCON_connected(&lpwhr->netConnection)) return; - if (lpwhr->pAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo); - lpwhr->pAuthInfo = NULL; - } - if (lpwhr->pProxyAuthInfo) - { - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->ctx)) - DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx); - if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->cred)) - FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred); - - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme); - HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo); - lpwhr->pProxyAuthInfo = NULL; - } - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); @@ -1436,11 +1488,95 @@ static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); } -static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf) +{ + LPHTTPHEADERW host_header; + + static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; + + host_header = HTTP_GetHeader(req, hostW); + if(!host_header) + return FALSE; + + sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ + return TRUE; +} + +static BOOL HTTP_KeepAlive(http_request_t *lpwhr) +{ + WCHAR szVersion[10]; + WCHAR szConnectionResponse[20]; + DWORD dwBufferSize = sizeof(szVersion); + BOOL keepalive = FALSE; + + /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that + * the connection is keep-alive by default */ + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS + && !strcmpiW(szVersion, g_szHttp1_1)) + { + keepalive = TRUE; + } + + dwBufferSize = sizeof(szConnectionResponse); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS + || HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); + } + + return keepalive; +} + +static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; switch(option) { + case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO: + { + http_session_t *lpwhs = req->lpHttpSession; + INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer; + + FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n"); + + if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO)) + return ERROR_INSUFFICIENT_BUFFER; + *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO); + /* FIXME: can't get a SOCKET from our connection since we don't use + * winsock + */ + info->Socket = 0; + /* FIXME: get source port from req->netConnection */ + info->SourcePort = 0; + info->DestPort = lpwhs->nHostPort; + info->Flags = 0; + if (HTTP_KeepAlive(req)) + info->Flags |= IDSI_FLAG_KEEP_ALIVE; + if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0) + info->Flags |= IDSI_FLAG_PROXY; + if (req->netConnection.useSSL) + info->Flags |= IDSI_FLAG_SECURE; + + return ERROR_SUCCESS; + } + + case INTERNET_OPTION_SECURITY_FLAGS: + { + http_session_t *lpwhs; + lpwhs = req->lpHttpSession; + + if (*size < sizeof(ULONG)) + return ERROR_INSUFFICIENT_BUFFER; + + *size = sizeof(DWORD); + if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE) + *(DWORD*)buffer = SECURITY_FLAG_SECURE; + else + *(DWORD*)buffer = 0; + FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer); + return ERROR_SUCCESS; + } + case INTERNET_OPTION_HANDLE_TYPE: TRACE("INTERNET_OPTION_HANDLE_TYPE\n"); @@ -1458,7 +1594,6 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b WCHAR *pch; static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; - static const WCHAR hostW[] = {'H','o','s','t',0}; TRACE("INTERNET_OPTION_URL\n"); @@ -1489,6 +1624,41 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b } } + case INTERNET_OPTION_CACHE_TIMESTAMPS: { + INTERNET_CACHE_ENTRY_INFOW *info; + INTERNET_CACHE_TIMESTAMPS *ts = buffer; + WCHAR url[INTERNET_MAX_URL_LENGTH]; + DWORD nbytes, error; + BOOL ret; + + TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n"); + + if (*size < sizeof(*ts)) + { + *size = sizeof(*ts); + return ERROR_INSUFFICIENT_BUFFER; + } + nbytes = 0; + HTTP_GetRequestURL(req, url); + ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes); + error = GetLastError(); + if (!ret && error == ERROR_INSUFFICIENT_BUFFER) + { + if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes))) + return ERROR_OUTOFMEMORY; + + GetUrlCacheEntryInfoW(url, info, &nbytes); + + ts->ftExpires = info->ExpireTime; + ts->ftLastModified = info->LastModifiedTime; + + HeapFree(GetProcessHeap(), 0, info); + *size = sizeof(*ts); + return ERROR_SUCCESS; + } + return error; + } + case INTERNET_OPTION_DATAFILE_NAME: { DWORD req_size; @@ -1584,9 +1754,9 @@ static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size) +static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; switch(option) { case INTERNET_OPTION_SEND_TIMEOUT: @@ -1598,151 +1768,365 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT, *(DWORD*)buffer); + + case INTERNET_OPTION_USERNAME: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName); + if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + + case INTERNET_OPTION_PASSWORD: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword); + if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + case INTERNET_OPTION_HTTP_DECODING: + if(size != sizeof(BOOL)) + return ERROR_INVALID_PARAMETER; + req->decoding = *(BOOL*)buffer; + return ERROR_SUCCESS; } return ERROR_INTERNET_INVALID_OPTION; } -static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +/* read some more data into the read buffer (the read section must be held) */ +static DWORD read_more_data( http_request_t *req, int maxlen ) { - int bytes_read; - - if(!NETCON_recv(&req->netConnection, buffer, min(size, req->dwContentLength - req->dwContentRead), - sync ? MSG_WAITALL : 0, &bytes_read)) { - if(req->dwContentLength != -1 && req->dwContentRead != req->dwContentLength) - ERR("not all data received %d/%d\n", req->dwContentRead, req->dwContentLength); + DWORD res; + int len; - /* always return success, even if the network layer returns an error */ - *read = 0; - HTTP_FinishedReading(req); - return ERROR_SUCCESS; + if (req->read_pos) + { + /* move existing data to the start of the buffer */ + if(req->read_size) + memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size ); + req->read_pos = 0; } - req->dwContentRead += bytes_read; - *read = bytes_read; - - if(req->lpszCacheFile) { - BOOL res; - DWORD dwBytesWritten; - - res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL); - if(!res) - WARN("WriteFile failed: %u\n", GetLastError()); - } + if (maxlen == -1) maxlen = sizeof(req->read_buf); - if(!bytes_read && (req->dwContentRead == req->dwContentLength)) - HTTP_FinishedReading(req); + res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size, + maxlen - req->read_size, 0, &len ); + if(res == ERROR_SUCCESS) + req->read_size += len; - return ERROR_SUCCESS; + return res; } -static DWORD get_chunk_size(const char *buffer) +/* remove some amount of data from the read buffer (the read section must be held) */ +static void remove_data( http_request_t *req, int count ) { - const char *p; - DWORD size = 0; - - for (p = buffer; *p; p++) - { - if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0'; - else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10; - else if (*p == ';') break; - } - return size; + if (!(req->read_size -= count)) req->read_pos = 0; + else req->read_pos += count; } -static DWORD HTTP_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) { - char reply[MAX_REPLY_LEN], *p = buffer; - DWORD buflen, to_read, to_write = size; - int bytes_read; + int count, bytes_read, pos = 0; + DWORD res; - *read = 0; + EnterCriticalSection( &req->read_section ); for (;;) { - if (*read == size) break; + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); - if (req->dwContentLength == ~0UL) /* new chunk */ + if (eol) { - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) break; - - if (!(req->dwContentLength = get_chunk_size(reply))) - { - /* zero sized chunk marks end of transfer; read any trailing headers and return */ - HTTP_GetResponseHeaders(req, FALSE); - break; - } + count = eol - (req->read_buf + req->read_pos); + bytes_read = count + 1; } - to_read = min(to_write, req->dwContentLength - req->dwContentRead); + else count = bytes_read = req->read_size; - if (!NETCON_recv(&req->netConnection, p, to_read, sync ? MSG_WAITALL : 0, &bytes_read)) - { - if (bytes_read != to_read) - ERR("Not all data received %d/%d\n", bytes_read, to_read); + count = min( count, *len - pos ); + memcpy( buffer + pos, req->read_buf + req->read_pos, count ); + pos += count; + remove_data( req, bytes_read ); + if (eol) break; - /* always return success, even if the network layer returns an error */ - *read = 0; - break; + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) + { + *len = 0; + TRACE( "returning empty string\n" ); + LeaveCriticalSection( &req->read_section ); + INTERNET_SetLastError(res); + return FALSE; } - if (!bytes_read) break; + } + LeaveCriticalSection( &req->read_section ); - req->dwContentRead += bytes_read; - to_write -= bytes_read; - *read += bytes_read; + if (pos < *len) + { + if (pos && buffer[pos - 1] == '\r') pos--; + *len = pos + 1; + } + buffer[*len - 1] = 0; + TRACE( "returning %s\n", debugstr_a(buffer)); + return TRUE; +} - if (req->lpszCacheFile) - { - DWORD dwBytesWritten; +/* discard data contents until we reach end of line (the read section must be held) */ +static DWORD discard_eol( http_request_t *req ) +{ + DWORD res; - if (!WriteFile(req->hCacheFile, p, bytes_read, &dwBytesWritten, NULL)) - WARN("WriteFile failed: %u\n", GetLastError()); + do + { + BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + if (eol) + { + remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) ); + break; } - p += bytes_read; + req->read_pos = req->read_size = 0; /* discard everything */ + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + } while (req->read_size); + return ERROR_SUCCESS; +} - if (req->dwContentRead == req->dwContentLength) /* chunk complete */ - { - req->dwContentRead = 0; - req->dwContentLength = ~0UL; +/* read the size of the next chunk (the read section must be held) */ +static DWORD start_next_chunk( http_request_t *req ) +{ + DWORD chunk_size = 0, res; - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) + if (!req->dwContentLength) return ERROR_SUCCESS; + if (req->dwContentLength == req->dwContentRead) + { + /* read terminator for the previous chunk */ + if ((res = discard_eol( req )) != ERROR_SUCCESS) return res; + req->dwContentLength = ~0u; + req->dwContentRead = 0; + } + for (;;) + { + while (req->read_size) + { + char ch = req->read_buf[req->read_pos]; + if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0'; + else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10; + else if (ch == ';' || ch == '\r' || ch == '\n') { - ERR("Malformed chunk\n"); - *read = 0; - break; + TRACE( "reading %u byte chunk\n", chunk_size ); + req->dwContentLength = chunk_size; + req->dwContentRead = 0; + return discard_eol( req ); } + remove_data( req, 1 ); + } + if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res; + if (!req->read_size) + { + req->dwContentLength = req->dwContentRead = 0; + return ERROR_SUCCESS; } } - if (!*read) HTTP_FinishedReading(req); +} + +/* check if we have reached the end of the data to read (the read section must be held) */ +static BOOL end_of_read_data( http_request_t *req ) +{ + if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + if (req->read_chunked) return (req->dwContentLength == 0); + if (req->dwContentLength == ~0u) return FALSE; + return (req->dwContentLength == req->dwContentRead); +} + +/* fetch some more data into the read buffer (the read section must be held) */ +static DWORD refill_buffer( http_request_t *req ) +{ + int len = sizeof(req->read_buf); + DWORD res; + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res; + } + + if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead ); + if (len <= req->read_size) return ERROR_SUCCESS; + + if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res; + if (!req->read_size) req->dwContentLength = req->dwContentRead = 0; return ERROR_SUCCESS; } -static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret) { - WCHAR encoding[20]; - DWORD buflen = sizeof(encoding); - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; + DWORD ret = ERROR_SUCCESS; + int read = 0; - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) && - !strcmpiW(encoding, szChunked)) +#ifdef HAVE_ZLIB + z_stream *zstream = &req->gzip_stream->zstream; + DWORD buf_avail; + int zres; + + while(read < size && !req->gzip_stream->end_of_data) { + if(!req->read_size) { + if(!sync || refill_buffer(req) != ERROR_SUCCESS) + break; + } + + buf_avail = req->dwContentLength == ~0 ? req->read_size : min(req->read_size, req->dwContentLength-req->dwContentRead); + + zstream->next_in = req->read_buf+req->read_pos; + zstream->avail_in = buf_avail; + zstream->next_out = buf+read; + zstream->avail_out = size-read; + zres = inflate(zstream, Z_FULL_FLUSH); + read = size - zstream->avail_out; + req->dwContentRead += buf_avail-zstream->avail_in; + remove_data(req, buf_avail-zstream->avail_in); + if(zres == Z_STREAM_END) { + TRACE("end of data\n"); + req->gzip_stream->end_of_data = TRUE; + inflateEnd(&req->gzip_stream->zstream); + }else if(zres != Z_OK) { + WARN("inflate failed %d\n", zres); + if(!read) + ret = ERROR_INTERNET_DECODING_FAILED; + break; + } + } +#endif + + *read_ret = read; + return ret; +} + +static void refill_gzip_buffer(http_request_t *req) +{ + DWORD res; + int len; + + if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf)) + return; + + if(req->gzip_stream->buf_pos) { + if(req->gzip_stream->buf_size) + memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size); + req->gzip_stream->buf_pos = 0; + } + + res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size, + sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len); + if(res == ERROR_SUCCESS) + req->gzip_stream->buf_size += len; +} + +/* return the size of data available to be read immediately (the read section must be held) */ +static DWORD get_avail_data( http_request_t *req ) +{ + if (req->gzip_stream) { + refill_gzip_buffer(req); + return req->gzip_stream->buf_size; + } + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + return 0; + return min( req->read_size, req->dwContentLength - req->dwContentRead ); +} + +static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + DWORD res; + + TRACE("%p\n", req); + + EnterCriticalSection( &req->read_section ); + if ((res = refill_buffer( req )) == ERROR_SUCCESS) { + iar.dwResult = (DWORD_PTR)req->hdr.hInternet; + iar.dwError = first_notif ? 0 : get_avail_data(req); + }else { + iar.dwResult = 0; + iar.dwError = res; + } + LeaveCriticalSection( &req->read_section ); + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +/* read data from the http connection (the read section must be held) */ +static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +{ + BOOL finished_reading = FALSE; + int len, bytes_read = 0; + DWORD ret = ERROR_SUCCESS; + + EnterCriticalSection( &req->read_section ); + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) { - return HTTP_ReadChunked(req, buffer, size, read, sync); + if (start_next_chunk( req ) != ERROR_SUCCESS) goto done; } - else - return HTTP_Read(req, buffer, size, read, sync); + + if(req->gzip_stream) { + if(req->gzip_stream->buf_size) { + bytes_read = min(req->gzip_stream->buf_size, size); + memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read); + req->gzip_stream->buf_pos += bytes_read; + req->gzip_stream->buf_size -= bytes_read; + }else if(!req->read_size && !req->gzip_stream->end_of_data) { + refill_buffer(req); + } + + if(size > bytes_read) { + ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len); + if(ret == ERROR_SUCCESS) + bytes_read += len; + } + + finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size; + }else { + if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead ); + + if (req->read_size) { + bytes_read = min( req->read_size, size ); + memcpy( buffer, req->read_buf + req->read_pos, bytes_read ); + remove_data( req, bytes_read ); + } + + if (size > bytes_read && (!bytes_read || sync)) { + if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read, + sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS) + bytes_read += len; + /* always return success, even if the network layer returns an error */ + } + + finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength; + req->dwContentRead += bytes_read; + } +done: + *read = bytes_read; + + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength ); + LeaveCriticalSection( &req->read_section ); + + if(ret == ERROR_SUCCESS && req->lpszCacheFile) { + BOOL res; + DWORD dwBytesWritten; + + res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL); + if(!res) + WARN("WriteFile failed: %u\n", GetLastError()); + } + + if(finished_reading) + HTTP_FinishedReading(req); + + return ret; } -static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) + +static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; return HTTPREQ_Read(req, buffer, size, read, TRUE); } -static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) +static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA; - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; + http_request_t *req = (http_request_t*)workRequest->hdr; INTERNET_ASYNC_RESULT iar; DWORD res; @@ -1759,11 +2143,10 @@ static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest) sizeof(INTERNET_ASYNC_RESULT)); } -static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *buffers, +static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers, DWORD flags, DWORD_PTR context) { - - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + http_request_t *req = (http_request_t*)hdr; DWORD res; if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) @@ -1774,27 +2157,35 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (hdr->dwFlags & INTERNET_FLAG_ASYNC) { - DWORD available = 0; + if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req)) + { + WORKREQUEST workRequest; - NETCON_query_data_available(&req->netConnection, &available); - if (!available) + if (TryEnterCriticalSection( &req->read_section )) { - WORKREQUEST workRequest; + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); + } - workRequest.asyncproc = HTTPREQ_AsyncReadFileExProc; - workRequest.hdr = WININET_AddRef(&req->hdr); - workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; + workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; - INTERNET_AsyncCall(&workRequest); + INTERNET_AsyncCall(&workRequest); - return ERROR_IO_PENDING; - } + return ERROR_IO_PENDING; } res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, !(flags & IRF_NO_WAIT)); +done: if (res == ERROR_SUCCESS) { DWORD size = buffers->dwBufferLength; INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, @@ -1804,52 +2195,120 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu return res; } -static BOOL HTTPREQ_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) +static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest) { - LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)hdr; + struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; + http_request_t *req = (http_request_t*)workRequest->hdr; + INTERNET_ASYNC_RESULT iar; + DWORD res; + + TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr); + + res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer, + data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE); + + iar.dwResult = res == ERROR_SUCCESS; + iar.dwError = res; - return NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); } -static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) +static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) { - WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; - char buffer[4048]; - TRACE("%p\n", workRequest->hdr); + http_request_t *req = (http_request_t*)hdr; + DWORD res; - iar.dwResult = NETCON_recv(&req->netConnection, buffer, - min(sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)&iar.dwError); + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + if (buffers->dwStructSize != sizeof(*buffers)) + return ERROR_INVALID_PARAMETER; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + if (hdr->dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + + if (TryEnterCriticalSection( &req->read_section )) + { + if (get_avail_data(req)) + { + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, + &buffers->dwBufferLength, FALSE); + LeaveCriticalSection( &req->read_section ); + goto done; + } + LeaveCriticalSection( &req->read_section ); + } + + workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExW.lpBuffersOut = buffers; + + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + + res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength, + !(flags & IRF_NO_WAIT)); + +done: + if (res == ERROR_SUCCESS) { + DWORD size = buffers->dwBufferLength; + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, + &size, sizeof(size)); + } + + return res; } -static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) { - WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; - BYTE buffer[4048]; - BOOL async; + DWORD res; + http_request_t *lpwhr = (http_request_t*)hdr; - TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); - if(!NETCON_query_data_available(&req->netConnection, available) || *available) - return ERROR_SUCCESS; + *written = 0; + res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + if (res == ERROR_SUCCESS) + lpwhr->dwBytesWritten += *written; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD)); + return res; +} - /* Even if we are in async mode, we need to determine whether - * there is actually more data available. We do this by trying - * to peek only a single byte in async mode. */ - async = (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) != 0; +static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) +{ + http_request_t *req = (http_request_t*)workRequest->hdr; + + HTTP_ReceiveRequestData(req, FALSE); +} + +static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +{ + http_request_t *req = (http_request_t*)hdr; + + TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); - if (NETCON_recv(&req->netConnection, buffer, - min(async ? 1 : sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)available) && async && *available) + if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) { WORKREQUEST workRequest; - *available = 0; + /* never wait, if we can't enter the section we queue an async request right away */ + if (TryEnterCriticalSection( &req->read_section )) + { + if ((*available = get_avail_data( req ))) goto done; + if (end_of_read_data( req )) goto done; + LeaveCriticalSection( &req->read_section ); + } + workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; workRequest.hdr = WININET_AddRef( &req->hdr ); @@ -1858,16 +2317,35 @@ static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *availab return ERROR_IO_PENDING; } + EnterCriticalSection( &req->read_section ); + + if (!(*available = get_avail_data( req )) && !end_of_read_data( req )) + { + refill_buffer( req ); + *available = get_avail_data( req ); + } + +done: + if (*available == sizeof(req->read_buf) && !req->gzip_stream) /* check if we have even more pending in the socket */ + { + DWORD extra; + if (NETCON_query_data_available(&req->netConnection, &extra)) + *available = min( *available + extra, req->dwContentLength - req->dwContentRead ); + } + LeaveCriticalSection( &req->read_section ); + + TRACE( "returning %u\n", *available ); return ERROR_SUCCESS; } -static const HANDLEHEADERVtbl HTTPREQVtbl = { +static const object_vtbl_t HTTPREQVtbl = { HTTPREQ_Destroy, HTTPREQ_CloseConnection, HTTPREQ_QueryOption, HTTPREQ_SetOption, HTTPREQ_ReadFile, HTTPREQ_ReadFileExA, + HTTPREQ_ReadFileExW, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, NULL @@ -1883,27 +2361,27 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = { * NULL on failure * */ -HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext) +static DWORD HTTP_HttpOpenRequestW(http_session_t *lpwhs, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret) { - LPWININETAPPINFOW hIC = NULL; - LPWININETHTTPREQW lpwhr; + appinfo_t *hIC = NULL; + http_request_t *lpwhr; LPWSTR lpszHostName = NULL; HINTERNET handle = NULL; static const WCHAR szHostForm[] = {'%','s',':','%','u',0}; - DWORD len; + DWORD len, res; TRACE("-->\n"); assert( lpwhs->hdr.htype == WH_HHTTPSESSION ); hIC = lpwhs->lpAppInfo; - lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW)); + lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t)); if (NULL == lpwhr) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } lpwhr->hdr.htype = WH_HHTTPREQ; @@ -1913,6 +2391,8 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->hdr.refs = 1; lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB; lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW; + lpwhr->dwContentLength = ~0u; + InitializeCriticalSection( &lpwhr->read_section ); WININET_AddRef( &lpwhs->hdr ); lpwhr->lpHttpSession = lpwhs; @@ -1922,18 +2402,18 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */)); if (NULL == lpszHostName) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } handle = WININET_AllocHandle( &lpwhr->hdr ); if (NULL == handle) { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto lend; } - if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) + if ((res = NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) != ERROR_SUCCESS) { InternetCloseHandle( handle ); handle = NULL; @@ -1950,11 +2430,15 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc); strcpyW(lpwhr->lpszPath,lpszObjectName); } + }else { + static const WCHAR slashW[] = {'/',0}; + + lpwhr->lpszPath = heap_strdupW(slashW); } if (lpszReferrer && *lpszReferrer) @@ -1973,23 +2457,19 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, } } - lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); - - if (lpszVersion) - lpwhr->lpszVersion = WININET_strdupW(lpszVersion); - else - lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1); + lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET); + lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1); if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER && lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT && lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT) { sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort); - HTTP_ProcessHeader(lpwhr, szHost, lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); } else - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ); if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER) @@ -2015,80 +2495,88 @@ lend: WININET_Release( &lpwhr->hdr ); TRACE("<-- %p (%p)\n", handle, lpwhr); - return handle; + *ret = handle; + return res; } -/* read any content returned by the server so that the connection can be - * reused */ -static void HTTP_DrainContent(WININETHTTPREQW *req) +/*********************************************************************** + * HttpOpenRequestW (WININET.@) + * + * Open a HTTP request handle + * + * RETURNS + * HINTERNET a HTTP request handle on success + * NULL on failure + * + */ +HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, + LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, + LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, + DWORD dwFlags, DWORD_PTR dwContext) { - DWORD bytes_read; - - if (!NETCON_connected(&req->netConnection)) return; + http_session_t *lpwhs; + HINTERNET handle = NULL; + DWORD res; - if (req->dwContentLength == -1) - NETCON_close(&req->netConnection); + TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession, + debugstr_w(lpszVerb), debugstr_w(lpszObjectName), + debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); + if(lpszAcceptTypes!=NULL) + { + int i; + for(i=0;lpszAcceptTypes[i]!=NULL;i++) + TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i])); + } - do + lpwhs = (http_session_t*) WININET_GetObject( hHttpSession ); + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) { - char buffer[2048]; - if (HTTP_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) - return; - } while (bytes_read); -} + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } -static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 }; -static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 }; -static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 }; -static const WCHAR szAge[] = { 'A','g','e',0 }; -static const WCHAR szAllow[] = { 'A','l','l','o','w',0 }; -static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 }; -static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 }; -static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 }; -static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 }; -static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 }; -static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 }; -static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 }; -static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 }; -static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 }; -static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 }; -static const WCHAR szDate[] = { 'D','a','t','e',0 }; -static const WCHAR szFrom[] = { 'F','r','o','m',0 }; -static const WCHAR szETag[] = { 'E','T','a','g',0 }; -static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 }; -static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 }; -static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 }; -static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 }; -static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 }; -static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 }; -static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 }; -static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 }; -static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 }; -static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; -static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 }; -static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 }; -static const WCHAR szRange[] = { 'R','a','n','g','e',0 }; -static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 }; -static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 }; -static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 }; -static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 }; -static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 }; -static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 }; -static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 }; -static const WCHAR szURI[] = { 'U','R','I',0 }; -static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 }; -static const WCHAR szVary[] = { 'V','a','r','y',0 }; -static const WCHAR szVia[] = { 'V','i','a',0 }; -static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; -static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; + /* + * My tests seem to show that the windows version does not + * become asynchronous until after this point. And anyhow + * if this call was asynchronous then how would you get the + * necessary HINTERNET pointer returned by this function. + * + */ + res = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName, + lpszVersion, lpszReferrer, lpszAcceptTypes, + dwFlags, dwContext, &handle); +lend: + if( lpwhs ) + WININET_Release( &lpwhs->hdr ); + TRACE("returning %p\n", handle); + if(res != ERROR_SUCCESS) + SetLastError(res); + return handle; +} + +/* read any content returned by the server so that the connection can be + * reused */ +static void HTTP_DrainContent(http_request_t *req) +{ + DWORD bytes_read; + + if (!NETCON_connected(&req->netConnection)) return; + + if (req->dwContentLength == -1) + { + NETCON_close(&req->netConnection); + return; + } + if (!strcmpW(req->lpszVerb, szHEAD)) return; + + do + { + char buffer[2048]; + if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) + return; + } while (bytes_read); +} static const LPCWSTR header_lookup[] = { szMime_Version, /* HTTP_QUERY_MIME_VERSION = 0 */ @@ -2146,7 +2634,7 @@ static const LPCWSTR header_lookup[] = { szContent_MD5, /* HTTP_QUERY_CONTENT_MD5 = 52 */ szContent_Range, /* HTTP_QUERY_CONTENT_RANGE = 53 */ szETag, /* HTTP_QUERY_ETAG = 54 */ - szHost, /* HTTP_QUERY_HOST = 55 */ + hostW, /* HTTP_QUERY_HOST = 55 */ szIf_Match, /* HTTP_QUERY_IF_MATCH = 56 */ szIf_None_Match, /* HTTP_QUERY_IF_NONE_MATCH = 57 */ szIf_Range, /* HTTP_QUERY_IF_RANGE = 58 */ @@ -2169,58 +2657,64 @@ static const LPCWSTR header_lookup[] = { /*********************************************************************** * HTTP_HttpQueryInfoW (internal) */ -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) +static DWORD HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel, + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS; INT requested_index = lpdwIndex ? *lpdwIndex : 0; - INT level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); + DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK); INT index = -1; /* Find requested header structure */ switch (level) { case HTTP_QUERY_CUSTOM: + if (!lpBuffer) return ERROR_INVALID_PARAMETER; index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only); break; - case HTTP_QUERY_RAW_HEADERS_CRLF: { LPWSTR headers; - DWORD len; - BOOL ret = FALSE; + DWORD len = 0; + DWORD res = ERROR_INVALID_PARAMETER; if (request_only) headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion); else headers = lpwhr->lpszRawHeaders; - len = (strlenW(headers) + 1) * sizeof(WCHAR); - if (len > *lpdwBufferLength) + if (headers) + len = strlenW(headers) * sizeof(WCHAR); + + if (len + sizeof(WCHAR) > *lpdwBufferLength) { - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - ret = FALSE; + len += sizeof(WCHAR); + res = ERROR_INSUFFICIENT_BUFFER; } else if (lpBuffer) { - memcpy(lpBuffer, headers, len); + if (headers) + memcpy(lpBuffer, headers, len + sizeof(WCHAR)); + else + { + len = strlenW(szCrLf) * sizeof(WCHAR); + memcpy(lpBuffer, szCrLf, sizeof(szCrLf)); + } TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); - ret = TRUE; + res = ERROR_SUCCESS; } *lpdwBufferLength = len; if (request_only) HeapFree(GetProcessHeap(), 0, headers); - return ret; + return res; } case HTTP_QUERY_RAW_HEADERS: { - static const WCHAR szCrLf[] = {'\r','\n',0}; LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf); DWORD i, size = 0; - LPWSTR pszString = (WCHAR*)lpBuffer; + LPWSTR pszString = lpBuffer; for (i = 0; ppszRawHeaderLines[i]; i++) size += strlenW(ppszRawHeaderLines[i]) + 1; @@ -2229,24 +2723,23 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev { HTTP_FreeTokens(ppszRawHeaderLines); *lpdwBufferLength = (size + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; } - - for (i = 0; ppszRawHeaderLines[i]; i++) + if (pszString) { - DWORD len = strlenW(ppszRawHeaderLines[i]); - memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); - pszString += len+1; + for (i = 0; ppszRawHeaderLines[i]; i++) + { + DWORD len = strlenW(ppszRawHeaderLines[i]); + memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR)); + pszString += len+1; + } + *pszString = '\0'; + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size)); } - *pszString = '\0'; - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size)); - *lpdwBufferLength = size * sizeof(WCHAR); HTTP_FreeTokens(ppszRawHeaderLines); - return TRUE; + return ERROR_SUCCESS; } case HTTP_QUERY_STATUS_TEXT: if (lpwhr->lpszStatusText) @@ -2255,15 +2748,15 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszStatusText, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; case HTTP_QUERY_VERSION: @@ -2273,21 +2766,25 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len + 1 > *lpdwBufferLength/sizeof(WCHAR)) { *lpdwBufferLength = (len + 1) * sizeof(WCHAR); - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return FALSE; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); } - memcpy(lpBuffer, lpwhr->lpszVersion, (len+1)*sizeof(WCHAR)); *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - - return TRUE; + return ERROR_SUCCESS; } break; + case HTTP_QUERY_CONTENT_ENCODING: + index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level], + requested_index,request_only); + break; default: assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1)); - if (level >= 0 && level < LAST_TABLE_HEADER && header_lookup[level]) + if (level < LAST_TABLE_HEADER && header_lookup[level]) index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level], requested_index,request_only); } @@ -2300,22 +2797,18 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) && (~lphttpHdr->wFlags & HDR_ISREQUEST))) { - INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND); - return bSuccess; + return ERROR_HTTP_HEADER_NOT_FOUND; } - if (lpdwIndex) - (*lpdwIndex)++; + if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++; /* coalesce value to requested type */ - if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) + if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer) { - *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); - bSuccess = TRUE; - - TRACE(" returning number : %d\n", *(int *)lpBuffer); - } - else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME) + *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); + TRACE(" returning number: %d\n", *(int *)lpBuffer); + } + else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) { time_t tmpTime; struct tm tmpTM; @@ -2324,24 +2817,19 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev tmpTime = ConvertTimeString(lphttpHdr->lpszValue); tmpTM = *gmtime(&tmpTime); - STHook = (SYSTEMTIME *) lpBuffer; - if(STHook==NULL) - return bSuccess; - - STHook->wDay = tmpTM.tm_mday; - STHook->wHour = tmpTM.tm_hour; - STHook->wMilliseconds = 0; - STHook->wMinute = tmpTM.tm_min; - STHook->wDayOfWeek = tmpTM.tm_wday; - STHook->wMonth = tmpTM.tm_mon + 1; - STHook->wSecond = tmpTM.tm_sec; - STHook->wYear = tmpTM.tm_year; - - bSuccess = TRUE; - - TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", - STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, - STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); + STHook = (SYSTEMTIME *)lpBuffer; + STHook->wDay = tmpTM.tm_mday; + STHook->wHour = tmpTM.tm_hour; + STHook->wMilliseconds = 0; + STHook->wMinute = tmpTM.tm_min; + STHook->wDayOfWeek = tmpTM.tm_wday; + STHook->wMonth = tmpTM.tm_mon + 1; + STHook->wSecond = tmpTM.tm_sec; + STHook->wYear = tmpTM.tm_year; + + TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", + STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, + STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds); } else if (lphttpHdr->lpszValue) { @@ -2350,17 +2838,16 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev if (len > *lpdwBufferLength) { *lpdwBufferLength = len; - INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); - return bSuccess; + return ERROR_INSUFFICIENT_BUFFER; + } + if (lpBuffer) + { + memcpy(lpBuffer, lphttpHdr->lpszValue, len); + TRACE("! returning string: %s\n", debugstr_w(lpBuffer)); } - - memcpy(lpBuffer, lphttpHdr->lpszValue, len); *lpdwBufferLength = len - sizeof(WCHAR); - bSuccess = TRUE; - - TRACE(" returning string : %s\n", debugstr_w(lpBuffer)); } - return bSuccess; + return ERROR_SUCCESS; } /*********************************************************************** @@ -2374,10 +2861,10 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev * */ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) + LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) { - BOOL bSuccess = FALSE; - LPWININETHTTPREQW lpwhr; + http_request_t *lpwhr; + DWORD res; if (TRACE_ON(wininet)) { #define FE(x) { x, #x } @@ -2463,7 +2950,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK; DWORD i; - TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel); + TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info); TRACE(" Attribute:"); for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) { if (query_flags[i].val == info) { @@ -2489,24 +2976,26 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel, TRACE("\n"); } - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; } if (lpBuffer == NULL) *lpdwBufferLength = 0; - bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, - lpBuffer, lpdwBufferLength, lpdwIndex); + res = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel, + lpBuffer, lpdwBufferLength, lpdwIndex); lend: if( lpwhr ) WININET_Release( &lpwhr->hdr ); - TRACE("%d <--\n", bSuccess); - return bSuccess; + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } /*********************************************************************** @@ -2577,379 +3066,112 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, } /*********************************************************************** - * HttpSendRequestExA (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers. - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. + * HTTP_GetRedirectURL (internal) */ -BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, - LPINTERNET_BUFFERSA lpBuffersIn, - LPINTERNET_BUFFERSA lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) +static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl) { - INTERNET_BUFFERSW BuffersInW; - BOOL rc = FALSE; - DWORD headerlen; - LPWSTR header = NULL; + static WCHAR szHttp[] = {'h','t','t','p',0}; + static WCHAR szHttps[] = {'h','t','t','p','s',0}; + http_session_t *lpwhs = lpwhr->lpHttpSession; + URL_COMPONENTSW urlComponents; + DWORD url_length = 0; + LPWSTR orig_url; + LPWSTR combined_url; + + urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); + urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; + urlComponents.dwSchemeLength = 0; + urlComponents.lpszHostName = lpwhs->lpszHostName; + urlComponents.dwHostNameLength = 0; + urlComponents.nPort = lpwhs->nHostPort; + urlComponents.lpszUserName = lpwhs->lpszUserName; + urlComponents.dwUserNameLength = 0; + urlComponents.lpszPassword = NULL; + urlComponents.dwPasswordLength = 0; + urlComponents.lpszUrlPath = lpwhr->lpszPath; + urlComponents.dwUrlPathLength = 0; + urlComponents.lpszExtraInfo = NULL; + urlComponents.dwExtraInfoLength = 0; + + if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + return NULL; - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); + orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); - if (lpBuffersIn) + /* convert from bytes to characters */ + url_length = url_length / sizeof(WCHAR) - 1; + if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) { - BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); - if (lpBuffersIn->lpcszHeader) - { - headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, - lpBuffersIn->dwHeadersLength,0,0); - header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); - if (!(BuffersInW.lpcszHeader = header)) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, - lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - header, headerlen); - } - else - BuffersInW.lpcszHeader = NULL; - BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; - BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; - BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; - BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; - BuffersInW.Next = NULL; + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; } - rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); - - HeapFree(GetProcessHeap(),0,header); + url_length = 0; + if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + return NULL; + } + combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - return rc; + if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) + { + HeapFree(GetProcessHeap(), 0, orig_url); + HeapFree(GetProcessHeap(), 0, combined_url); + return NULL; + } + HeapFree(GetProcessHeap(), 0, orig_url); + return combined_url; } + /*********************************************************************** - * HttpSendRequestExW (WININET.@) - * - * Sends the specified request to the HTTP server and allows chunked - * transfers - * - * RETURNS - * Success: TRUE - * Failure: FALSE, call GetLastError() for more information. + * HTTP_HandleRedirect (internal) */ -BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, - LPINTERNET_BUFFERSW lpBuffersIn, - LPINTERNET_BUFFERSW lpBuffersOut, - DWORD dwFlags, DWORD_PTR dwContext) +static DWORD HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl) { - BOOL ret = FALSE; - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC; - - TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, - lpBuffersOut, dwFlags, dwContext); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); + http_session_t *lpwhs = lpwhr->lpHttpSession; + appinfo_t *hIC = lpwhs->lpAppInfo; + BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0]; + WCHAR path[INTERNET_MAX_URL_LENGTH]; + int index; - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + if(lpszUrl[0]=='/') { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - goto lend; + /* if it's an absolute path, keep the same session info */ + lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH); } + else + { + URL_COMPONENTSW urlComponents; + WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; + static WCHAR szHttp[] = {'h','t','t','p',0}; + static WCHAR szHttps[] = {'h','t','t','p','s',0}; - lpwhs = lpwhr->lpHttpSession; - assert(lpwhs->hdr.htype == WH_HHTTPSESSION); - hIC = lpwhs->lpAppInfo; - assert(hIC->hdr.htype == WH_HINIT); + userName[0] = 0; + hostName[0] = 0; + protocol[0] = 0; - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; + urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); + urlComponents.lpszScheme = protocol; + urlComponents.dwSchemeLength = 32; + urlComponents.lpszHostName = hostName; + urlComponents.dwHostNameLength = MAXHOSTNAME; + urlComponents.lpszUserName = userName; + urlComponents.dwUserNameLength = 1024; + urlComponents.lpszPassword = NULL; + urlComponents.dwPasswordLength = 0; + urlComponents.lpszUrlPath = path; + urlComponents.dwUrlPathLength = 2048; + urlComponents.lpszExtraInfo = NULL; + urlComponents.dwExtraInfoLength = 0; + if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) + return INTERNET_GetLastError(); - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpBuffersIn) - { - if (lpBuffersIn->lpcszHeader) - /* FIXME: this should use dwHeadersLength or may not be necessary at all */ - req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader); - else - req->lpszHeader = NULL; - req->dwHeaderLength = lpBuffersIn->dwHeadersLength; - req->lpOptional = lpBuffersIn->lpvBuffer; - req->dwOptionalLength = lpBuffersIn->dwBufferLength; - req->dwContentLength = lpBuffersIn->dwBufferTotal; - } - else - { - req->lpszHeader = NULL; - req->dwHeaderLength = 0; - req->lpOptional = NULL; - req->dwOptionalLength = 0; - req->dwContentLength = 0; - } - - req->bEndRequest = FALSE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - } - else - { - if (lpBuffersIn) - ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, - lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, - lpBuffersIn->dwBufferTotal, FALSE); - else - ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); - } - -lend: - if ( lpwhr ) - WININET_Release( &lpwhr->hdr ); - - TRACE("<---\n"); - return ret; -} - -/*********************************************************************** - * HttpSendRequestW (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - LPWININETHTTPREQW lpwhr; - LPWININETHTTPSESSIONW lpwhs = NULL; - LPWININETAPPINFOW hIC = NULL; - BOOL r; - - TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, - debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); - - lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest ); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - lpwhs = lpwhr->lpHttpSession; - if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - hIC = lpwhs->lpAppInfo; - if (NULL == hIC || hIC->hdr.htype != WH_HINIT) - { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); - r = FALSE; - goto lend; - } - - if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - WORKREQUEST workRequest; - struct WORKREQ_HTTPSENDREQUESTW *req; - - workRequest.asyncproc = AsyncHttpSendRequestProc; - workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); - req = &workRequest.u.HttpSendRequestW; - if (lpszHeaders) - { - req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR)); - memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR)); - } - else - req->lpszHeader = 0; - req->dwHeaderLength = dwHeaderLength; - req->lpOptional = lpOptional; - req->dwOptionalLength = dwOptionalLength; - req->dwContentLength = dwOptionalLength; - req->bEndRequest = TRUE; - - INTERNET_AsyncCall(&workRequest); - /* - * This is from windows. - */ - INTERNET_SetLastError(ERROR_IO_PENDING); - r = FALSE; - } - else - { - r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, - dwHeaderLength, lpOptional, dwOptionalLength, - dwOptionalLength, TRUE); - } -lend: - if( lpwhr ) - WININET_Release( &lpwhr->hdr ); - return r; -} - -/*********************************************************************** - * HttpSendRequestA (WININET.@) - * - * Sends the specified request to the HTTP server - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) -{ - BOOL result; - LPWSTR szHeaders=NULL; - DWORD nLen=dwHeaderLength; - if(lpszHeaders!=NULL) - { - nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); - szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); - } - result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); - HeapFree(GetProcessHeap(),0,szHeaders); - return result; -} - -static BOOL HTTP_GetRequestURL(WININETHTTPREQW *req, LPWSTR buf) -{ - LPHTTPHEADERW host_header; - - static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; - - host_header = HTTP_GetHeader(req, szHost); - if(!host_header) - return FALSE; - - sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */ - return TRUE; -} - -/*********************************************************************** - * HTTP_HandleRedirect (internal) - */ -static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) -{ - static const WCHAR szContentType[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0}; - static const WCHAR szContentLength[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; - LPWININETAPPINFOW hIC = lpwhs->lpAppInfo; - BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0]; - WCHAR path[INTERNET_MAX_URL_LENGTH]; - int index; - - if(lpszUrl[0]=='/') - { - /* if it's an absolute path, keep the same session info */ - lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH); - } - else - { - URL_COMPONENTSW urlComponents; - WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; - static WCHAR szHttp[] = {'h','t','t','p',0}; - static WCHAR szHttps[] = {'h','t','t','p','s',0}; - DWORD url_length = 0; - LPWSTR orig_url; - LPWSTR combined_url; - - urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); - urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp; - urlComponents.dwSchemeLength = 0; - urlComponents.lpszHostName = lpwhs->lpszHostName; - urlComponents.dwHostNameLength = 0; - urlComponents.nPort = lpwhs->nHostPort; - urlComponents.lpszUserName = lpwhs->lpszUserName; - urlComponents.dwUserNameLength = 0; - urlComponents.lpszPassword = NULL; - urlComponents.dwPasswordLength = 0; - urlComponents.lpszUrlPath = lpwhr->lpszPath; - urlComponents.dwUrlPathLength = 0; - urlComponents.lpszExtraInfo = NULL; - urlComponents.dwExtraInfoLength = 0; - - if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - return FALSE; - - orig_url = HeapAlloc(GetProcessHeap(), 0, url_length); - - /* convert from bytes to characters */ - url_length = url_length / sizeof(WCHAR) - 1; - if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - - url_length = 0; - if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) && - (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - return FALSE; - } - combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR)); - - if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY)) - { - HeapFree(GetProcessHeap(), 0, orig_url); - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - HeapFree(GetProcessHeap(), 0, orig_url); - - userName[0] = 0; - hostName[0] = 0; - protocol[0] = 0; - - urlComponents.dwStructSize = sizeof(URL_COMPONENTSW); - urlComponents.lpszScheme = protocol; - urlComponents.dwSchemeLength = 32; - urlComponents.lpszHostName = hostName; - urlComponents.dwHostNameLength = MAXHOSTNAME; - urlComponents.lpszUserName = userName; - urlComponents.dwUserNameLength = 1024; - urlComponents.lpszPassword = NULL; - urlComponents.dwPasswordLength = 0; - urlComponents.lpszUrlPath = path; - urlComponents.dwUrlPathLength = 2048; - urlComponents.lpszExtraInfo = NULL; - urlComponents.dwExtraInfoLength = 0; - if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents)) - { - HeapFree(GetProcessHeap(), 0, combined_url); - return FALSE; - } - - HeapFree(GetProcessHeap(), 0, combined_url); - - if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && - (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) + if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && + (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) { TRACE("redirect from secure page to non-secure page\n"); /* FIXME: warn about from secure redirect to non-secure page */ @@ -3000,26 +3222,35 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort); } else - lpwhs->lpszHostName = WININET_strdupW(hostName); + lpwhs->lpszHostName = heap_strdupW(hostName); - HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); + HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ); HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName); lpwhs->lpszUserName = NULL; if (userName[0]) - lpwhs->lpszUserName = WININET_strdupW(userName); + lpwhs->lpszUserName = heap_strdupW(userName); if (!using_proxy) { if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort) { + DWORD res; + HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName); - lpwhs->lpszServerName = WININET_strdupW(hostName); + lpwhs->lpszServerName = heap_strdupW(hostName); lpwhs->nServerPort = urlComponents.nPort; NETCON_close(&lpwhr->netConnection); - if (!HTTP_ResolveName(lpwhr)) return FALSE; - if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) + return res; + + res = NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE); + if (res != ERROR_SUCCESS) + return res; + + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; } } else @@ -3039,7 +3270,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR)); rc = UrlEscapeW(path, lpwhr->lpszPath, &needed, URL_ESCAPE_SPACES_ONLY); - if (rc) + if (rc != S_OK) { ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc); strcpyW(lpwhr->lpszPath,path); @@ -3047,14 +3278,14 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) } /* Remove custom content-type/length headers on redirects. */ - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentType, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - index = HTTP_GetCustomHeaderIndex(lpwhr, szContentLength, 0, TRUE); + index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE); if (0 <= index) HTTP_DeleteCustomHeader(lpwhr, index); - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** @@ -3080,7 +3311,7 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len ) return str; } -static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr) { LPWSTR lpszPath; LPWSTR requestString; @@ -3088,10 +3319,10 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) INT cnt; INT responseLen; char *ascii_req; - BOOL ret; + DWORD res; static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0}; static const WCHAR szFormat[] = {'%','s',':','%','d',0}; - LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + http_session_t *lpwhs = lpwhr->lpHttpSession; TRACE("\n"); @@ -3110,43 +3341,42 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) ); - ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); + res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt ); HeapFree( GetProcessHeap(), 0, ascii_req ); - if (!ret || cnt < 0) - return FALSE; + if (res != ERROR_SUCCESS) + return res; responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE ); if (!responseLen) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } -static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) +static void HTTP_InsertCookies(http_request_t *lpwhr) { - static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0}; + static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0}; LPWSTR lpszCookies, lpszUrl = NULL; DWORD nCookieSize, size; - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); - size = (strlenW(Host->lpszValue) + strlenW(szUrlForm)) * sizeof(WCHAR); + size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR); if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return; - sprintfW( lpszUrl, szUrlForm, Host->lpszValue ); + sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath); if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize)) { int cnt = 0; static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0}; - static const WCHAR szcrlf[] = {'\r','\n',0}; - size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szcrlf); + size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf); if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size))) { cnt += sprintfW(lpszCookies, szCookie); InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize); - strcatW(lpszCookies, szcrlf); + strcatW(lpszCookies, szCrLf); - HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_ADD); + HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE); HeapFree(GetProcessHeap(), 0, lpszCookies); } } @@ -3163,12 +3393,12 @@ static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr) * FALSE on failure * */ -BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, +static DWORD HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders, DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwContentLength, BOOL bEndRequest) { INT cnt; - BOOL bSuccess = FALSE; + BOOL redirected = FALSE; LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; @@ -3177,6 +3407,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, static const WCHAR szContentLength[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; + DWORD res; TRACE("--> %p\n", lpwhr); @@ -3184,12 +3415,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, /* if the verb is NULL default to GET */ if (!lpwhr->lpszVerb) - lpwhr->lpszVerb = WININET_strdupW(szGET); + lpwhr->lpszVerb = heap_strdupW(szGET); - if (dwContentLength || !strcmpW(lpwhr->lpszVerb, szPost)) + if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET)) { sprintfW(contentLengthStr, szContentLength, dwContentLength); - HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE); + lpwhr->dwBytesToWrite = dwContentLength; } if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent) { @@ -3230,7 +3462,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (TRACE_ON(wininet)) { - LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost); + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath)); } @@ -3265,11 +3497,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, TRACE("Request header -> %s\n", debugstr_w(requestString) ); /* Send the request and store the results */ - if (!HTTP_OpenConnection(lpwhr)) + if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS) goto lend; /* send the request as ASCII, tack on the optional data */ - if( !lpOptional ) + if (!lpOptional || redirected) dwOptionalLength = 0; len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, NULL, 0, NULL, NULL ); @@ -3285,9 +3517,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); - NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); + res = NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt); HeapFree( GetProcessHeap(), 0, ascii_req ); + lpwhr->dwBytesWritten = dwOptionalLength; + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, &len, sizeof(DWORD)); @@ -3296,18 +3530,14 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, { DWORD dwBufferSize; DWORD dwStatusCode; - WCHAR encoding[20]; - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - if (cnt < 0) + if (res != ERROR_SUCCESS) goto lend; responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); - if (responseLen) - bSuccess = TRUE; INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, @@ -3315,61 +3545,58 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, HTTP_ProcessCookies(lpwhr); - dwBufferSize = sizeof(lpwhr->dwContentLength); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, - &lpwhr->dwContentLength,&dwBufferSize,NULL)) - lpwhr->dwContentLength = -1; - - if (lpwhr->dwContentLength == 0) - HTTP_FinishedReading(lpwhr); - - /* Correct the case where both a Content-Length and Transfer-encoding = chunked are set */ - - dwBufferSize = sizeof(encoding); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &dwBufferSize, NULL) && - !strcmpiW(encoding, szChunked)) - { - lpwhr->dwContentLength = -1; - } + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); dwBufferSize = sizeof(dwStatusCode); - if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, - &dwStatusCode,&dwBufferSize,NULL)) + if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, + &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS) dwStatusCode = 0; - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen) { - WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH]; + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; dwBufferSize=sizeof(szNewLocation); if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) && - HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL)) + HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS) { + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) + { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); + } HTTP_DrainContent(lpwhr); - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REDIRECT, szNewLocation, - dwBufferSize); - bSuccess = HTTP_HandleRedirect(lpwhr, szNewLocation); - if (bSuccess) + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) { - HeapFree(GetProcessHeap(), 0, requestString); - loop_next = TRUE; + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, requestString); + loop_next = TRUE; + } + HeapFree( GetProcessHeap(), 0, new_url ); } + redirected = TRUE; } } - if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS) { WCHAR szAuthValue[2048]; dwBufferSize=2048; if (dwStatusCode == HTTP_STATUS_DENIED) { + LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW); DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pAuthInfo, lpwhr->lpHttpSession->lpszUserName, - lpwhr->lpHttpSession->lpszPassword)) + lpwhr->lpHttpSession->lpszPassword, + Host->lpszValue)) { + HeapFree(GetProcessHeap(), 0, requestString); loop_next = TRUE; break; } @@ -3378,12 +3605,13 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) { DWORD dwIndex = 0; - while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex)) + while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS) { if (HTTP_DoAuthorization(lpwhr, szAuthValue, &lpwhr->pProxyAuthInfo, lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername, - lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword)) + lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword, + NULL)) { loop_next = TRUE; break; @@ -3393,52 +3621,507 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, } } else - bSuccess = TRUE; + res = ERROR_SUCCESS; + } + while (loop_next); + + if(res == ERROR_SUCCESS) { + WCHAR url[INTERNET_MAX_URL_LENGTH]; + WCHAR cacheFileName[MAX_PATH+1]; + BOOL b; + + b = HTTP_GetRequestURL(lpwhr, url); + if(!b) { + WARN("Could not get URL\n"); + goto lend; + } + + b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0); + if(b) { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile); + CloseHandle(lpwhr->hCacheFile); + + lpwhr->lpszCacheFile = heap_strdupW(cacheFileName); + lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) { + WARN("Could not create file: %u\n", GetLastError()); + lpwhr->hCacheFile = NULL; + } + }else { + WARN("Could not create cache entry: %08x\n", GetLastError()); + } + } + +lend: + + HeapFree(GetProcessHeap(), 0, requestString); + + /* TODO: send notification for P3P header */ + + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + if (res == ERROR_SUCCESS && lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) + HTTP_ReceiveRequestData(lpwhr, TRUE); + else + { + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = res; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + } + } + + TRACE("<--\n"); + return res; +} + +/*********************************************************************** + * + * Helper functions for the HttpSendRequest(Ex) functions + * + */ +static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest) +{ + struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW; + http_request_t *lpwhr = (http_request_t*) workRequest->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpSendRequestW(lpwhr, req->lpszHeader, + req->dwHeaderLength, req->lpOptional, req->dwOptionalLength, + req->dwContentLength, req->bEndRequest); + + HeapFree(GetProcessHeap(), 0, req->lpszHeader); +} + + +static DWORD HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext) +{ + INT responseLen; + DWORD dwBufferSize; + INTERNET_ASYNC_RESULT iar; + DWORD res = ERROR_SUCCESS; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); + if (!responseLen) + res = ERROR_HTTP_HEADER_NOT_FOUND; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD)); + + /* process cookies here. Is this right? */ + HTTP_ProcessCookies(lpwhr); + + if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr); + + if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT)) + { + DWORD dwCode,dwCodeLength = sizeof(DWORD); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) == ERROR_SUCCESS + && (dwCode == 302 || dwCode == 301 || dwCode == 303)) + { + WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH]; + dwBufferSize=sizeof(szNewLocation); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS) + { + if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD)) + { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); + lpwhr->lpszVerb = heap_strdupW(szGET); + } + HTTP_DrainContent(lpwhr); + if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation ))) + { + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT, + new_url, (strlenW(new_url) + 1) * sizeof(WCHAR)); + res = HTTP_HandleRedirect(lpwhr, new_url); + if (res == ERROR_SUCCESS) + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); + HeapFree( GetProcessHeap(), 0, new_url ); + } + } + } + } + + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = res; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + return res; +} + +/*********************************************************************** + * HttpEndRequestA (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext); +} + +static void AsyncHttpEndRequestProc(WORKREQUEST *work) +{ + struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW; + http_request_t *lpwhr = (http_request_t*)work->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext); +} + +/*********************************************************************** + * HttpEndRequestW (WININET.@) + * + * Ends an HTTP request that was started by HttpSendRequestEx + * + * RETURNS + * TRUE if successful + * FALSE on failure + * + */ +BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + DWORD res; + + TRACE("-->\n"); + + if (lpBuffersOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + if (lpwhr) + WININET_Release( &lpwhr->hdr ); + return FALSE; + } + lpwhr->hdr.dwFlags |= dwFlags; + + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST work; + struct WORKREQ_HTTPENDREQUESTW *request; + + work.asyncproc = AsyncHttpEndRequestProc; + work.hdr = WININET_AddRef( &lpwhr->hdr ); + + request = &work.u.HttpEndRequestW; + request->dwFlags = dwFlags; + request->dwContext = dwContext; + + INTERNET_AsyncCall(&work); + res = ERROR_IO_PENDING; + } + else + res = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext); + + WININET_Release( &lpwhr->hdr ); + TRACE("%u <--\n", res); + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestExA (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers. + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest, + LPINTERNET_BUFFERSA lpBuffersIn, + LPINTERNET_BUFFERSA lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + INTERNET_BUFFERSW BuffersInW; + BOOL rc = FALSE; + DWORD headerlen; + LPWSTR header = NULL; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + if (lpBuffersIn) + { + BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW); + if (lpBuffersIn->lpcszHeader) + { + headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader, + lpBuffersIn->dwHeadersLength,0,0); + header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR)); + if (!(BuffersInW.lpcszHeader = header)) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0, + lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + header, headerlen); + } + else + BuffersInW.lpcszHeader = NULL; + BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal; + BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer; + BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength; + BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal; + BuffersInW.Next = NULL; + } + + rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext); + + HeapFree(GetProcessHeap(),0,header); + + return rc; +} + +/*********************************************************************** + * HttpSendRequestExW (WININET.@) + * + * Sends the specified request to the HTTP server and allows chunked + * transfers + * + * RETURNS + * Success: TRUE + * Failure: FALSE, call GetLastError() for more information. + */ +BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest, + LPINTERNET_BUFFERSW lpBuffersIn, + LPINTERNET_BUFFERSW lpBuffersOut, + DWORD dwFlags, DWORD_PTR dwContext) +{ + http_request_t *lpwhr; + http_session_t *lpwhs; + appinfo_t *hIC; + DWORD res; + + TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn, + lpBuffersOut, dwFlags, dwContext); + + lpwhr = (http_request_t*) WININET_GetObject( hRequest ); + + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } + + lpwhs = lpwhr->lpHttpSession; + assert(lpwhs->hdr.htype == WH_HHTTPSESSION); + hIC = lpwhs->lpAppInfo; + assert(hIC->hdr.htype == WH_HINIT); + + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; + + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpBuffersIn) + { + DWORD size = 0; + + if (lpBuffersIn->lpcszHeader) + { + if (lpBuffersIn->dwHeadersLength == ~0u) + size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR); + else + size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size ); + memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size ); + } + else req->lpszHeader = NULL; + + req->dwHeaderLength = size / sizeof(WCHAR); + req->lpOptional = lpBuffersIn->lpvBuffer; + req->dwOptionalLength = lpBuffersIn->dwBufferLength; + req->dwContentLength = lpBuffersIn->dwBufferTotal; + } + else + { + req->lpszHeader = NULL; + req->dwHeaderLength = 0; + req->lpOptional = NULL; + req->dwOptionalLength = 0; + req->dwContentLength = 0; + } + + req->bEndRequest = FALSE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + if (lpBuffersIn) + res = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength, + lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength, + lpBuffersIn->dwBufferTotal, FALSE); + else + res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE); } - while (loop_next); - /* FIXME: Better check, when we have to create the cache file */ - if(bSuccess && (lpwhr->hdr.dwFlags & INTERNET_FLAG_NEED_FILE)) { - WCHAR url[INTERNET_MAX_URL_LENGTH]; - WCHAR cacheFileName[MAX_PATH+1]; - BOOL b; +lend: + if ( lpwhr ) + WININET_Release( &lpwhr->hdr ); - b = HTTP_GetRequestURL(lpwhr, url); - if(!b) { - WARN("Could not get URL\n"); - goto lend; - } + TRACE("<---\n"); + SetLastError(res); + return res == ERROR_SUCCESS; +} - b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0); - if(b) { - lpwhr->lpszCacheFile = WININET_strdupW(cacheFileName); - lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) { - WARN("Could not create file: %u\n", GetLastError()); - lpwhr->hCacheFile = NULL; - } - }else { - WARN("Could not create cache entry: %08x\n", GetLastError()); - } +/*********************************************************************** + * HttpSendRequestW (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + http_request_t *lpwhr; + http_session_t *lpwhs = NULL; + appinfo_t *hIC = NULL; + DWORD res = ERROR_SUCCESS; + + TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest, + debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength); + + lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest ); + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; } -lend: + lpwhs = lpwhr->lpHttpSession; + if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } - HeapFree(GetProcessHeap(), 0, requestString); + hIC = lpwhs->lpAppInfo; + if (NULL == hIC || hIC->hdr.htype != WH_HINIT) + { + res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + goto lend; + } - /* TODO: send notification for P3P header */ + if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; + struct WORKREQ_HTTPSENDREQUESTW *req; - iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); + workRequest.asyncproc = AsyncHttpSendRequestProc; + workRequest.hdr = WININET_AddRef( &lpwhr->hdr ); + req = &workRequest.u.HttpSendRequestW; + if (lpszHeaders) + { + DWORD size; - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR); + else size = dwHeaderLength * sizeof(WCHAR); - TRACE("<--\n"); - if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS); - return bSuccess; + req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(req->lpszHeader, lpszHeaders, size); + } + else + req->lpszHeader = 0; + req->dwHeaderLength = dwHeaderLength; + req->lpOptional = lpOptional; + req->dwOptionalLength = dwOptionalLength; + req->dwContentLength = dwOptionalLength; + req->bEndRequest = TRUE; + + INTERNET_AsyncCall(&workRequest); + /* + * This is from windows. + */ + res = ERROR_IO_PENDING; + } + else + { + res = HTTP_HttpSendRequestW(lpwhr, lpszHeaders, + dwHeaderLength, lpOptional, dwOptionalLength, + dwOptionalLength, TRUE); + } +lend: + if( lpwhr ) + WININET_Release( &lpwhr->hdr ); + + SetLastError(res); + return res == ERROR_SUCCESS; +} + +/*********************************************************************** + * HttpSendRequestA (WININET.@) + * + * Sends the specified request to the HTTP server + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, + DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength) +{ + BOOL result; + LPWSTR szHeaders=NULL; + DWORD nLen=dwHeaderLength; + if(lpszHeaders!=NULL) + { + nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0); + szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen); + } + result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength); + HeapFree(GetProcessHeap(),0,szHeaders); + return result; } /*********************************************************************** @@ -3447,9 +4130,9 @@ lend: * Deallocate session handle * */ -static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) +static void HTTPSESSION_Destroy(object_header_t *hdr) { - LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr; + http_session_t *lpwhs = (http_session_t*) hdr; TRACE("%p\n", lpwhs); @@ -3462,7 +4145,7 @@ static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwhs); } -static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -3479,11 +4162,34 @@ static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { +static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size) +{ + http_session_t *ses = (http_session_t*)hdr; + + switch(option) { + case INTERNET_OPTION_USERNAME: + { + HeapFree(GetProcessHeap(), 0, ses->lpszUserName); + if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_PASSWORD: + { + HeapFree(GetProcessHeap(), 0, ses->lpszPassword); + if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + default: break; + } + + return ERROR_INTERNET_INVALID_OPTION; +} + +static const object_vtbl_t HTTPSESSIONVtbl = { HTTPSESSION_Destroy, NULL, HTTPSESSION_QueryOption, - NULL, + HTTPSESSION_SetOption, NULL, NULL, NULL, @@ -3502,30 +4208,25 @@ static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { * NULL on failure * */ -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags) +DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET *ret) { - LPWININETHTTPSESSIONW lpwhs = NULL; + http_session_t *lpwhs = NULL; HINTERNET handle = NULL; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); if (!lpszServerName || !lpszServerName[0]) - { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); - goto lerror; - } + return ERROR_INVALID_PARAMETER; assert( hIC->hdr.htype == WH_HINIT ); - lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW)); - if (NULL == lpwhs) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; - } + lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t)); + if (!lpwhs) + return ERROR_OUTOFMEMORY; /* * According to my tests. The name is not resolved until a request is sent @@ -3547,8 +4248,8 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, if (NULL == handle) { ERR("Failed to alloc handle\n"); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lerror; + res = ERROR_OUTOFMEMORY; + goto lerror; } if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) { @@ -3559,13 +4260,13 @@ HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, } if (lpszServerName && lpszServerName[0]) { - lpwhs->lpszServerName = WININET_strdupW(lpszServerName); - lpwhs->lpszHostName = WININET_strdupW(lpszServerName); + lpwhs->lpszServerName = heap_strdupW(lpszServerName); + lpwhs->lpszHostName = heap_strdupW(lpszServerName); } if (lpszUserName && lpszUserName[0]) - lpwhs->lpszUserName = WININET_strdupW(lpszUserName); + lpwhs->lpszUserName = heap_strdupW(lpszUserName); if (lpszPassword && lpszPassword[0]) - lpwhs->lpszPassword = WININET_strdupW(lpszPassword); + lpwhs->lpszPassword = heap_strdupW(lpszPassword); lpwhs->nServerPort = nServerPort; lpwhs->nHostPort = nServerPort; @@ -3587,7 +4288,10 @@ lerror: */ TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs); - return handle; + + if(res == ERROR_SUCCESS) + *ret = handle; + return res; } @@ -3601,48 +4305,58 @@ lerror: * TRUE on success * FALSE on failure */ -static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) +static DWORD HTTP_OpenConnection(http_request_t *lpwhr) { - BOOL bSuccess = FALSE; - LPWININETHTTPSESSIONW lpwhs; - LPWININETAPPINFOW hIC = NULL; - char szaddr[32]; + http_session_t *lpwhs; + appinfo_t *hIC = NULL; + char szaddr[INET6_ADDRSTRLEN]; + const void *addr; + DWORD res = ERROR_SUCCESS; TRACE("-->\n"); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + if (lpwhr->hdr.htype != WH_HHTTPREQ) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + res = ERROR_INVALID_PARAMETER; goto lend; } if (NETCON_connected(&lpwhr->netConnection)) - { - bSuccess = TRUE; goto lend; - } - if (!HTTP_ResolveName(lpwhr)) goto lend; + if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend; lpwhs = lpwhr->lpHttpSession; hIC = lpwhs->lpAppInfo; - inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr, - szaddr, sizeof(szaddr)); + switch (lpwhs->socketAddress.ss_family) + { + case AF_INET: + addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr; + break; + case AF_INET6: + addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr; + break; + default: + WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family); + return ERROR_INTERNET_NAME_NOT_RESOLVED; + } + inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr)); INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, szaddr, strlen(szaddr)+1); - if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.sin_family, - SOCK_STREAM, 0)) + res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0); + if (res != ERROR_SUCCESS) { - WARN("Socket creation failed: %u\n", INTERNET_GetLastError()); + WARN("Socket creation failed: %u\n", res); goto lend; } - if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, - sizeof(lpwhs->socketAddress))) + res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, + lpwhs->sa_len); + if(res != ERROR_SUCCESS) goto lend; if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) @@ -3653,10 +4367,11 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) * behaviour to be more correct and to not cause any incompatibilities * because using a secure connection through a proxy server is a rare * case that would be hard for anyone to depend on */ - if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr)) + if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS) goto lend; - if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName)) + res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName); + if(res != ERROR_SUCCESS) { WARN("Couldn't connect securely to host\n"); goto lend; @@ -3667,11 +4382,12 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) INTERNET_STATUS_CONNECTED_TO_SERVER, szaddr, strlen(szaddr)+1); - bSuccess = TRUE; - lend: - TRACE("%d <--\n", bSuccess); - return bSuccess; + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; + + TRACE("%d <--\n", res); + return res; } @@ -3680,7 +4396,7 @@ lend: * * clear out any old response headers */ -static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) +static void HTTP_clear_response_headers( http_request_t *lpwhr ) { DWORD i; @@ -3707,20 +4423,20 @@ static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr ) * TRUE on success * FALSE on error */ -static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) +static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear) { INT cbreaks = 0; WCHAR buffer[MAX_REPLY_LEN]; DWORD buflen = MAX_REPLY_LEN; BOOL bSuccess = FALSE; INT rc = 0; - static const WCHAR szCrLf[] = {'\r','\n',0}; - static const WCHAR szHundred[] = {'1','0','0',0}; char bufferA[MAX_REPLY_LEN]; - LPWSTR status_code, status_text; + LPWSTR status_code = NULL, status_text = NULL; DWORD cchMaxRawHeaders = 1024; - LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + LPWSTR lpszRawHeaders = NULL; + LPWSTR temp; DWORD cchRawHeaders = 0; + BOOL codeHundred = FALSE; TRACE("-->\n"); @@ -3731,36 +4447,52 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) goto lend; do { - /* - * HACK peek at the buffer - */ - buflen = MAX_REPLY_LEN; - NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc); - + static const WCHAR szHundred[] = {'1','0','0',0}; /* * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. */ - memset(buffer, 0, MAX_REPLY_LEN); - if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + buflen = MAX_REPLY_LEN; + if (!read_line(lpwhr, bufferA, &buflen)) goto lend; + rc += buflen; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); + /* check is this a status code line? */ + if (!strncmpW(buffer, g_szHttp1_0, 4)) + { + /* split the version from the status code */ + status_code = strchrW( buffer, ' ' ); + if( !status_code ) + goto lend; + *status_code++=0; - /* split the version from the status code */ - status_code = strchrW( buffer, ' ' ); - if( !status_code ) - goto lend; - *status_code++=0; + /* split the status code from the status text */ + status_text = strchrW( status_code, ' ' ); + if( !status_text ) + goto lend; + *status_text++=0; - /* split the status code from the status text */ - status_text = strchrW( status_code, ' ' ); - if( !status_text ) - goto lend; - *status_text++=0; + TRACE("version [%s] status code [%s] status text [%s]\n", + debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); + + codeHundred = (!strcmpW(status_code, szHundred)); + } + else if (!codeHundred) + { + WARN("No status line at head of response (%s)\n", debugstr_w(buffer)); - TRACE("version [%s] status code [%s] status text [%s]\n", - debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) ); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText); - } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */ + lpwhr->lpszVersion = heap_strdupW(g_szHttp1_0); + lpwhr->lpszStatusText = heap_strdupW(szOK); + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); + lpwhr->lpszRawHeaders = heap_strdupW(szDefaultHeader); + + bSuccess = TRUE; + goto lend; + } + } while (codeHundred); /* Add status code */ HTTP_ProcessHeader(lpwhr, szStatus, status_code, @@ -3769,19 +4501,22 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion); HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText); - lpwhr->lpszVersion= WININET_strdupW(buffer); - lpwhr->lpszStatusText = WININET_strdupW(status_text); + lpwhr->lpszVersion = heap_strdupW(buffer); + lpwhr->lpszStatusText = heap_strdupW(status_text); /* Restore the spaces */ *(status_code-1) = ' '; *(status_text-1) = ' '; /* regenerate raw headers */ + lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (!lpszRawHeaders) goto lend; + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - { cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - } + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); cchRawHeaders += (buflen-1); memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); @@ -3792,33 +4527,35 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) do { buflen = MAX_REPLY_LEN; - if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen)) + if (read_line(lpwhr, bufferA, &buflen)) { LPWSTR * pFieldAndValue; TRACE("got line %s, now interpreting\n", debugstr_a(bufferA)); + + if (!bufferA[0]) break; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); - while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) + pFieldAndValue = HTTP_InterpretHttpHeader(buffer); + if (pFieldAndValue) { - cchMaxRawHeaders *= 2; - lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) + cchMaxRawHeaders *= 2; + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); + cchRawHeaders += (buflen-1); + memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); + cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; + lpszRawHeaders[cchRawHeaders] = '\0'; + + HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], + HTTP_ADDREQ_FLAG_ADD ); + + HTTP_FreeTokens(pFieldAndValue); } - memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); - cchRawHeaders += (buflen-1); - memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); - cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; - lpszRawHeaders[cchRawHeaders] = '\0'; - - pFieldAndValue = HTTP_InterpretHttpHeader(buffer); - if (!pFieldAndValue) - break; - - HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1], - HTTP_ADDREQ_FLAG_ADD ); - - HTTP_FreeTokens(pFieldAndValue); - } + } else { cbreaks++; @@ -3827,6 +4564,19 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) } }while(1); + /* make sure the response header is terminated with an empty line. Some apps really + truly care about that empty line being there for some reason. Just add it to the + header. */ + if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders) + { + cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf); + temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); + if (temp == NULL) goto lend; + lpszRawHeaders = temp; + } + + memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); + HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); lpwhr->lpszRawHeaders = lpszRawHeaders; TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); @@ -3844,27 +4594,6 @@ lend: } } - -static void strip_spaces(LPWSTR start) -{ - LPWSTR str = start; - LPWSTR end; - - while (*str == ' ' && *str != '\0') - str++; - - if (str != start) - memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1)); - - end = start + strlenW(start) - 1; - while (end >= start && *end == ' ') - { - *end = '\0'; - end--; - } -} - - /*********************************************************************** * HTTP_InterpretHttpHeader (internal) * @@ -3929,12 +4658,12 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) -static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) +static DWORD HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier) { LPHTTPHEADERW lphttpHdr = NULL; - BOOL bSuccess = FALSE; INT index = -1; BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ; + DWORD res = ERROR_HTTP_INVALID_HEADER; TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); @@ -3950,9 +4679,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v if (index >= 0) { if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) - { - return FALSE; - } + return ERROR_HTTP_INVALID_HEADER; lphttpHdr = &lpwhr->pCustHeaders[index]; } else if (value) @@ -3969,7 +4696,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } /* no value to delete */ - else return TRUE; + else return ERROR_SUCCESS; if (dwModifier & HTTP_ADDHDR_FLAG_REQ) lphttpHdr->wFlags |= HDR_ISREQUEST; @@ -3994,7 +4721,7 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v return HTTP_InsertCustomHeader(lpwhr, &hdr); } - return TRUE; + return ERROR_SUCCESS; } else if (dwModifier & COALESCEFLAGS) { @@ -4032,16 +4759,16 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); lphttpHdr->lpszValue[len] = '\0'; - bSuccess = TRUE; + res = ERROR_SUCCESS; } else { WARN("HeapReAlloc (%d bytes) failed\n",len+1); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; } } - TRACE("<-- %d\n",bSuccess); - return bSuccess; + TRACE("<-- %d\n", res); + return res; } @@ -4051,30 +4778,12 @@ static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR v * Called when all content from server has been read by client. * */ -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) +static BOOL HTTP_FinishedReading(http_request_t *lpwhr) { - WCHAR szVersion[10]; - WCHAR szConnectionResponse[20]; - DWORD dwBufferSize = sizeof(szVersion); - BOOL keepalive = FALSE; + BOOL keepalive = HTTP_KeepAlive(lpwhr); TRACE("\n"); - /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that - * the connection is keep-alive by default */ - if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, - &dwBufferSize, NULL) || - strcmpiW(szVersion, g_szHttp1_1)) - { - keepalive = TRUE; - } - - dwBufferSize = sizeof(szConnectionResponse); - if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) || - HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL)) - { - keepalive = !strcmpiW(szConnectionResponse, szKeepAlive); - } if (!keepalive) { @@ -4093,12 +4802,12 @@ BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) * Return index of custom header from header array * */ -static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, +static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField, int requested_index, BOOL request_only) { DWORD index; - TRACE("%s\n", debugstr_w(lpszField)); + TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only); for (index = 0; index < lpwhr->nCustHeaders; index++) { @@ -4130,11 +4839,10 @@ static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, * Insert header into array * */ -static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr) +static DWORD HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr) { INT count; LPHTTPHEADERW lph = NULL; - BOOL r = FALSE; TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue)); count = lpwhr->nCustHeaders + 1; @@ -4143,22 +4851,17 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr else lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count); - if (NULL != lph) - { - lpwhr->pCustHeaders = lph; - lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField); - lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue); - lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; - lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; - lpwhr->nCustHeaders++; - r = TRUE; - } - else - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - } + if (!lph) + return ERROR_OUTOFMEMORY; - return r; + lpwhr->pCustHeaders = lph; + lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField); + lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue); + lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags; + lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount; + lpwhr->nCustHeaders++; + + return ERROR_SUCCESS; } @@ -4168,7 +4871,7 @@ static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr * Delete header from array * If this function is called, the indexs may change. */ -static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) +static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index) { if( lpwhr->nCustHeaders <= 0 ) return FALSE; @@ -4193,13 +4896,13 @@ static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index) * Verify the given header is not invalid for the given http request * */ -static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field) +static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field) { /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */ if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding)) - return FALSE; + return ERROR_HTTP_INVALID_HEADER; - return TRUE; + return ERROR_SUCCESS; } /*********************************************************************** diff --git a/reactos/dll/win32/wininet/internet.c b/reactos/dll/win32/wininet/internet.c index bad795ddbd4..45b6aa791f3 100644 --- a/reactos/dll/win32/wininet/internet.c +++ b/reactos/dll/win32/wininet/internet.c @@ -31,6 +31,10 @@ #define MAXHOSTNAME 100 /* from http.c */ +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -97,13 +101,27 @@ static CRITICAL_SECTION_DEBUG WININET_cs_debug = }; static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 }; -static LPWININETHANDLEHEADER *WININET_Handles; +static object_header_t **WININET_Handles; static UINT WININET_dwNextHandle; static UINT WININET_dwMaxHandles; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) +typedef struct { - LPWININETHANDLEHEADER *p; + DWORD dwProxyEnabled; + LPWSTR lpszProxyServer; + LPWSTR lpszProxyBypass; +} proxyinfo_t; + +static const WCHAR szInternetSettings[] = + { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; +static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; +static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + +HINTERNET WININET_AllocHandle( object_header_t *info ) +{ + object_header_t **p; UINT handle = 0, num; list_init( &info->children ); @@ -113,7 +131,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = HANDLE_CHUNK_SIZE; p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof (UINT)* num); + sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -123,7 +141,7 @@ HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ) { num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE; p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - WININET_Handles, sizeof (UINT)* num); + WININET_Handles, sizeof (*WININET_Handles)* num); if( !p ) goto end; WININET_Handles = p; @@ -145,16 +163,16 @@ end: return info->hInternet = (HINTERNET) (handle+1); } -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ) +object_header_t *WININET_AddRef( object_header_t *info ) { ULONG refs = InterlockedIncrement(&info->refs); TRACE("%p -> refcount = %d\n", info, refs ); return info; } -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) +object_header_t *WININET_GetObject( HINTERNET hinternet ) { - LPWININETHANDLEHEADER info = NULL; + object_header_t *info = NULL; UINT handle = (UINT) hinternet; EnterCriticalSection( &WININET_cs ); @@ -170,7 +188,7 @@ LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ) return info; } -BOOL WININET_Release( LPWININETHANDLEHEADER info ) +BOOL WININET_Release( object_header_t *info ) { ULONG refs = InterlockedDecrement(&info->refs); TRACE( "object %p refcount = %d\n", info, refs ); @@ -182,7 +200,8 @@ BOOL WININET_Release( LPWININETHANDLEHEADER info ) info->vtbl->CloseConnection( info ); } /* Don't send a callback if this is a session handle created with InternetOpenUrl */ - if (info->htype != WH_HHTTPSESSION || !(info->dwInternalFlags & INET_OPENURL)) + if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION) + || !(info->dwInternalFlags & INET_OPENURL)) { INTERNET_SendCallback(info, info->dwContext, INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet, @@ -200,7 +219,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) { BOOL ret = FALSE; UINT handle = (UINT) hinternet; - LPWININETHANDLEHEADER info = NULL, child, next; + object_header_t *info = NULL, *child, *next; EnterCriticalSection( &WININET_cs ); @@ -224,7 +243,7 @@ BOOL WININET_FreeHandle( HINTERNET hinternet ) if( info ) { /* Free all children as native does */ - LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry ) + LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry ) { TRACE( "freeing child handle %d for parent handle %d\n", (UINT)child->hInternet, handle+1); @@ -285,6 +304,8 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: + NETCON_unload(); + URLCacheContainers_DeleteAll(); if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) @@ -298,6 +319,48 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } +/*********************************************************************** + * INTERNET_SaveProxySettings + * + * Stores the proxy settings given by lpwai into the registry + * + * RETURNS + * ERROR_SUCCESS if no error, or error code on fail + */ +static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi ) +{ + HKEY key; + LONG ret; + + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; + + if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD)))) + { + RegCloseKey( key ); + return ret; + } + + if (lpwpi->lpszProxyServer) + { + if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1)))) + { + RegCloseKey( key ); + return ret; + } + } + else + { + if ((ret = RegDeleteValueW( key, szProxyServer ))) + { + RegCloseKey( key ); + return ret; + } + } + + RegCloseKey(key); + return ERROR_SUCCESS; +} /*********************************************************************** * InternetInitializeAutoProxyDll (WININET.@) @@ -314,7 +377,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } @@ -331,37 +394,49 @@ BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl, DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags) { FIXME("STUB\n"); - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +static void FreeProxyInfo( proxyinfo_t *lpwpi ) +{ + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer); + HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass); +} /*********************************************************************** - * INTERNET_ConfigureProxy + * INTERNET_LoadProxySettings + * + * Loads proxy information from the registry or environment into lpwpi. + * + * The caller should call FreeProxyInfo when done with lpwpi. * * FIXME: * The proxy may be specified in the form 'http=proxy.my.org' * Presumably that means there can be ftp=ftpproxy.my.org too. */ -static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) +static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi ) { HKEY key; - DWORD type, len, enabled = 0; + DWORD type, len; LPCSTR envproxy; - static const WCHAR szInternetSettings[] = - { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; - static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; - static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; + LONG ret; - if (RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )) return FALSE; + if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key ))) + return ret; - len = sizeof enabled; - if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&enabled, &len ) || type != REG_DWORD) - RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&enabled, sizeof(REG_DWORD) ); + len = sizeof(DWORD); + if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD) + { + lpwpi->dwProxyEnabled = 0; + if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) ))) + { + RegCloseKey( key ); + return ret; + } + } - if (enabled) + if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled) { TRACE("Proxy is enabled.\n"); @@ -374,7 +449,7 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len ))) { RegCloseKey( key ); - return FALSE; + return ERROR_OUTOFMEMORY; } RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len ); @@ -388,32 +463,56 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) p = strchrW( szProxy, ' ' ); if (p) *p = 0; - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = szProxy; + lpwpi->lpszProxyServer = szProxy; - TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy)); + TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } else - ERR("Couldn't read proxy server settings from registry.\n"); + { + TRACE("No proxy server settings in registry.\n"); + lpwpi->lpszProxyServer = NULL; + } } - else if ((envproxy = getenv( "http_proxy" ))) + else if (envproxy) { WCHAR *envproxyW; len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 ); - if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE; + if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len ); - lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; - lpwai->lpszProxy = envproxyW; + lpwpi->dwProxyEnabled = 1; + lpwpi->lpszProxyServer = envproxyW; - TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy)); - enabled = 1; + TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer)); } - if (!enabled) TRACE("Proxy is not enabled.\n"); - RegCloseKey( key ); - return (enabled > 0); + + lpwpi->lpszProxyBypass = NULL; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * INTERNET_ConfigureProxy + */ +static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) +{ + proxyinfo_t wpi; + + if (INTERNET_LoadProxySettings( &wpi )) + return FALSE; + + if (wpi.dwProxyEnabled) + { + lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY; + lpwai->lpszProxy = wpi.lpszProxyServer; + return TRUE; + } + + lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT; + return FALSE; } /*********************************************************************** @@ -459,8 +558,8 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) FE(INTERNET_FLAG_TRANSFER_BINARY) }; #undef FE - int i; - + unsigned int i; + for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) { if (flag[i].val & dwFlags) { TRACE(" %s", flag[i].name); @@ -479,9 +578,9 @@ static void dump_INTERNET_FLAGS(DWORD dwFlags) * Close internet handle * */ -static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) +static VOID APPINFO_Destroy(object_header_t *hdr) { - LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr; + appinfo_t *lpwai = (appinfo_t*)hdr; TRACE("%p\n",lpwai); @@ -493,9 +592,9 @@ static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr) HeapFree(GetProcessHeap(), 0, lpwai); } -static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) +static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { - LPWININETAPPINFOW ai = (LPWININETAPPINFOW)hdr; + appinfo_t *ai = (appinfo_t*)hdr; switch(option) { case INTERNET_OPTION_HANDLE_TYPE: @@ -516,17 +615,36 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b bufsize = *size; if (unicode) { - *size = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR); + DWORD len = ai->lpszAgent ? strlenW(ai->lpszAgent) : 0; + + *size = (len + 1) * sizeof(WCHAR); if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - strcpyW(buffer, ai->lpszAgent); + if (ai->lpszAgent) + strcpyW(buffer, ai->lpszAgent); + else + *(WCHAR *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size = len * sizeof(WCHAR); }else { - *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + if (ai->lpszAgent) + *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL); + else + *size = 1; if(!buffer || bufsize < *size) return ERROR_INSUFFICIENT_BUFFER; - WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + if (ai->lpszAgent) + WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL); + else + *(char *)buffer = 0; + /* If the buffer is copied, the returned length doesn't include + * the NULL terminator. + */ + *size -= 1; } return ERROR_SUCCESS; @@ -543,8 +661,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b if (ai->lpszProxyBypass) proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR); if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired) - return ERROR_INSUFFICIENT_BUFFER; - + { + *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired; + return ERROR_INSUFFICIENT_BUFFER; + } proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW)); proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired); @@ -574,8 +694,10 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1, NULL, 0, NULL, NULL); if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired) + { + *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired; return ERROR_INSUFFICIENT_BUFFER; - + } proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA)); proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired); @@ -601,7 +723,7 @@ static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b return INET_QueryOption(option, buffer, size, unicode); } -static const HANDLEHEADERVtbl APPINFOVtbl = { +static const object_vtbl_t APPINFOVtbl = { APPINFO_Destroy, NULL, APPINFO_QueryOption, @@ -627,7 +749,7 @@ static const HANDLEHEADERVtbl APPINFOVtbl = { HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags) { - LPWININETAPPINFOW lpwai = NULL; + appinfo_t *lpwai = NULL; HINTERNET handle = NULL; if (TRACE_ON(wininet)) { @@ -658,7 +780,7 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, /* Clear any error information */ INTERNET_SetLastError(0); - lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW)); + lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(appinfo_t)); if (NULL == lpwai) { INTERNET_SetLastError(ERROR_OUTOFMEMORY); @@ -681,30 +803,12 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, goto lend; } - if (NULL != lpszAgent) - { - lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0, - (strlenW(lpszAgent)+1)*sizeof(WCHAR)); - if (lpwai->lpszAgent) - lstrcpyW( lpwai->lpszAgent, lpszAgent ); - } + lpwai->lpszAgent = heap_strdupW(lpszAgent); if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) INTERNET_ConfigureProxy( lpwai ); - else if (NULL != lpszProxy) - { - lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxy)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxy) - lstrcpyW( lpwai->lpszProxy, lpszProxy ); - } - - if (NULL != lpszProxyBypass) - { - lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0, - (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR)); - if (lpwai->lpszProxyBypass) - lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass ); - } + else + lpwai->lpszProxy = heap_strdupW(lpszProxy); + lpwai->lpszProxyBypass = heap_strdupW(lpszProxyBypass); lend: if( lpwai ) @@ -729,33 +833,15 @@ lend: HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags) { - HINTERNET rc = NULL; - INT len; - WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL; + WCHAR *szAgent, *szProxy, *szBypass; + HINTERNET rc; TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent), dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags); - if( lpszAgent ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0); - szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len); - } - - if( lpszProxy ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0); - szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len); - } - - if( lpszProxyBypass ) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0); - szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len); - } + szAgent = heap_strdupAtoW(lpszAgent); + szProxy = heap_strdupAtoW(lpszProxy); + szBypass = heap_strdupAtoW(lpszProxyBypass); rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags); @@ -779,7 +865,7 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, LPSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -816,7 +902,7 @@ BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError, BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError, LPWSTR lpszBuffer, LPDWORD lpdwBufferLength) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); TRACE("\n"); @@ -856,7 +942,7 @@ BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved) TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved); if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return TRUE; @@ -900,7 +986,7 @@ BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnecti return FALSE; if (lpdwStatus) { - FIXME("always returning LAN connection.\n"); + WARN("always returning LAN connection.\n"); *lpdwStatus = INTERNET_CONNECTION_LAN; } return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen); @@ -950,8 +1036,9 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETAPPINFOW hIC; + appinfo_t *hIC; HINTERNET rc = NULL; + DWORD res = ERROR_SUCCESS; TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName), nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword), @@ -959,16 +1046,14 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, if (!lpszServerName) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return NULL; } - /* Clear any error information */ - INTERNET_SetLastError(0); - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) ) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + res = ERROR_INVALID_HANDLE; goto lend; } @@ -977,11 +1062,13 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, case INTERNET_SERVICE_FTP: rc = FTP_Connect(hIC, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwFlags, dwContext, 0); + if(!rc) + res = INTERNET_GetLastError(); break; case INTERNET_SERVICE_HTTP: - rc = HTTP_Connect(hIC, lpszServerName, nServerPort, - lpszUserName, lpszPassword, dwFlags, dwContext, 0); + res = HTTP_Connect(hIC, lpszServerName, nServerPort, + lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc); break; case INTERNET_SERVICE_GOPHER: @@ -993,6 +1080,7 @@ lend: WININET_Release( &hIC->hdr ); TRACE("returning %p\n", rc); + SetLastError(res); return rc; } @@ -1013,30 +1101,13 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - INT len = 0; - LPWSTR szServerName = NULL; - LPWSTR szUserName = NULL; - LPWSTR szPassword = NULL; - - if (lpszServerName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0); - szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len); - } - if (lpszUserName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); - szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len); - } - if (lpszPassword) - { - len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0); - szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len); - } + LPWSTR szServerName; + LPWSTR szUserName; + LPWSTR szPassword; + szServerName = heap_strdupAtoW(lpszServerName); + szUserName = heap_strdupAtoW(lpszUserName); + szPassword = heap_strdupAtoW(lpszPassword); rc = InternetConnectW(hInternet, szServerName, nServerPort, szUserName, szPassword, dwService, dwFlags, dwContext); @@ -1081,7 +1152,7 @@ BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("\n"); @@ -1119,7 +1190,7 @@ BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData) */ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet) { - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; TRACE("%p\n",hInternet); @@ -1153,11 +1224,14 @@ static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentL DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL); if (*lppszComponent == NULL) { - int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL); if (lpwszComponent) - *lppszComponent = (LPSTR)lpszStart+nASCIIOffset; + { + int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL); + *lppszComponent = (LPSTR)lpszStart + offset; + } else *lppszComponent = NULL; + *dwComponentLen = nASCIILength; } else @@ -1204,7 +1278,7 @@ BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, InternetCrackUrlW should not include it */ if (dwUrlLength == -1) nLength--; - lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength); + lpwszUrl = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength); memset(&UCW,0,sizeof(UCW)); @@ -1443,7 +1517,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR /* Determine if the URI is absolute. */ while (lpszap - lpszUrl < dwUrlLength) { - if (isalnumW(*lpszap)) + if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-') { lpszap++; continue; @@ -1465,8 +1539,11 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR lpUC->nPort = INTERNET_INVALID_PORT_NUMBER; /* Parse */ - if (!(lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)))) + lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl)); + if(!lpszParam) + lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl)); SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength, lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0); @@ -1564,7 +1641,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR } /* If the scheme is "file" and the host is just one letter, it's not a host */ - if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1) + if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1) { lpszcp=lpszHost; SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, @@ -1617,7 +1694,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR * :[//][/path][;][?][#] * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ - if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp < lpszParam)) + if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam)) { INT len; @@ -1783,7 +1860,7 @@ BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer, /* #################################################### */ static INTERNET_STATUS_CALLBACK set_status_callback( - LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) + object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode) { INTERNET_STATUS_CALLBACK ret; @@ -1811,10 +1888,10 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; + + TRACE("%p\n", hInternet); - TRACE("0x%08x\n", (ULONG)hInternet); - if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1839,9 +1916,9 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW( HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB) { INTERNET_STATUS_CALLBACK retVal; - LPWININETHANDLEHEADER lpwh; + object_header_t *lpwh; - TRACE("0x%08x\n", (ULONG)hInternet); + TRACE("%p\n", hInternet); if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1875,8 +1952,8 @@ DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove, BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten) { - LPWININETHANDLEHEADER lpwh; - BOOL retval = FALSE; + object_header_t *lpwh; + BOOL res; TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); @@ -1888,16 +1965,17 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, } if(lpwh->vtbl->WriteFile) { - retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); + res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten); }else { WARN("No Writefile method.\n"); - SetLastError(ERROR_INVALID_HANDLE); - retval = FALSE; + res = ERROR_INVALID_HANDLE; } WININET_Release( lpwh ); - return retval; + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } @@ -1914,7 +1992,7 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer, BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead); @@ -1968,7 +2046,7 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext); @@ -1994,33 +2072,40 @@ BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOu /*********************************************************************** * InternetReadFileExW (WININET.@) - * - * Read data from an open internet file. - * - * PARAMS - * hFile [I] Handle returned by InternetOpenUrl() or HttpOpenRequest(). - * lpBuffersOut [I/O] Buffer. - * dwFlags [I] Flags. - * dwContext [I] Context for callbacks. - * - * RETURNS - * FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED - * - * NOTES - * Not implemented in Wine or native either (as of IE6 SP2). - * + * SEE + * InternetReadFileExA() */ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer, DWORD dwFlags, DWORD_PTR dwContext) { - ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext); + object_header_t *hdr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + + TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext); + + hdr = WININET_GetObject(hFile); + if (!hdr) { + INTERNET_SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + if(hdr->vtbl->ReadFileExW) + res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext); + + WININET_Release(hdr); + + TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", + res, lpBuffer->dwBufferLength); + + if(res != ERROR_SUCCESS) + SetLastError(res); + return res == ERROR_SUCCESS; } DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) { + static BOOL warn = TRUE; + switch(option) { case INTERNET_OPTION_REQUEST_FLAGS: TRACE("INTERNET_OPTION_REQUEST_FLAGS\n"); @@ -2047,8 +2132,10 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_CONNECTED_STATE: - FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); - + if (warn) { + FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n"); + warn = FALSE; + } if (*size < sizeof(ULONG)) return ERROR_INSUFFICIENT_BUFFER; @@ -2058,13 +2145,16 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) return ERROR_SUCCESS; case INTERNET_OPTION_PROXY: { - WININETAPPINFOW ai; + appinfo_t ai; + BOOL ret; TRACE("Getting global proxy info\n"); - memset(&ai, 0, sizeof(WININETAPPINFOW)); + memset(&ai, 0, sizeof(appinfo_t)); INTERNET_ConfigureProxy(&ai); - return APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */ + APPINFO_Destroy(&ai.hdr); + return ret; } case INTERNET_OPTION_MAX_CONNS_PER_SERVER: @@ -2109,23 +2199,48 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_OPTION_PER_CONNECTION_OPTION: { INTERNET_PER_CONN_OPTION_LISTW *con = buffer; + INTERNET_PER_CONN_OPTION_LISTA *conA = buffer; DWORD res = ERROR_SUCCESS, i; + proxyinfo_t pi; + LONG ret; + + TRACE("Getting global proxy info\n"); + if((ret = INTERNET_LoadProxySettings(&pi))) + return ret; FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n"); - if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) + if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) { + FreeProxyInfo(&pi); return ERROR_INSUFFICIENT_BUFFER; + } for (i = 0; i < con->dwOptionCount; i++) { INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i; switch (option->dwOption) { case INTERNET_PER_CONN_FLAGS: - option->Value.dwValue = PROXY_TYPE_DIRECT; + if(pi.dwProxyEnabled) + option->Value.dwValue = PROXY_TYPE_PROXY; + else + option->Value.dwValue = PROXY_TYPE_DIRECT; break; case INTERNET_PER_CONN_PROXY_SERVER: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyServer); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer); + break; + case INTERNET_PER_CONN_PROXY_BYPASS: + if (unicode) + option->Value.pszValue = heap_strdupW(pi.lpszProxyBypass); + else + optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass); + break; + case INTERNET_PER_CONN_AUTOCONFIG_URL: case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: @@ -2133,8 +2248,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: FIXME("Unhandled dwOption %d\n", option->dwOption); - option->Value.dwValue = 0; - res = ERROR_INVALID_PARAMETER; + memset(&option->Value, 0, sizeof(option->Value)); break; default: @@ -2143,9 +2257,14 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) break; } } + FreeProxyInfo(&pi); return res; } + case INTERNET_OPTION_USER_AGENT: + return ERROR_INTERNET_INCORRECT_HANDLE_TYPE; + case INTERNET_OPTION_POLICY: + return ERROR_INVALID_PARAMETER; } FIXME("Stub for %d\n", option); @@ -2165,7 +2284,7 @@ DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode) BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2198,7 +2317,7 @@ BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength) { - LPWININETHANDLEHEADER hdr; + object_header_t *hdr; DWORD res = ERROR_INVALID_HANDLE; TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); @@ -2232,12 +2351,12 @@ BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption, BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength) { - LPWININETHANDLEHEADER lpwhh; + object_header_t *lpwhh; BOOL ret = TRUE; TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength); - lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet ); + lpwhh = (object_header_t*) WININET_GetObject( hInternet ); if(lpwhh && lpwhh->vtbl->SetOption) { DWORD res; @@ -2256,9 +2375,14 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; - ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK); - break; + if (!lpwhh) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + WININET_Release(lpwhh); + SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_HTTP_VERSION: { @@ -2342,12 +2466,96 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_DISABLE_AUTODIAL: FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n"); break; - case 86: - FIXME("86\n"); + case INTERNET_OPTION_HTTP_DECODING: + FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_COOKIES_3RD_PARTY: + FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY: + FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_PATH: + FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_EXTRA: + FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_IDN: + FIXME("INTERNET_OPTION_IDN; STUB\n"); + SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_POLICY: + SetLastError(ERROR_INVALID_PARAMETER); + ret = FALSE; + break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer; + LONG res; + int i; + proxyinfo_t pi; + + INTERNET_LoadProxySettings(&pi); + + for (i = 0; i < con->dwOptionCount; i++) { + INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i; + + switch (option->dwOption) { + case INTERNET_PER_CONN_PROXY_SERVER: + HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer); + pi.lpszProxyServer = heap_strdupW(option->Value.pszValue); + break; + + case INTERNET_PER_CONN_FLAGS: + if(option->Value.dwValue & PROXY_TYPE_PROXY) + pi.dwProxyEnabled = 1; + else + { + if(option->Value.dwValue != PROXY_TYPE_DIRECT) + FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue); + pi.dwProxyEnabled = 0; + } + break; + + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + FIXME("Unhandled dwOption %d\n", option->dwOption); + break; + + default: + FIXME("Unknown dwOption %d\n", option->dwOption); + SetLastError(ERROR_INVALID_PARAMETER); + break; + } + } + + if ((res = INTERNET_SaveProxySettings(&pi))) + SetLastError(res); + + FreeProxyInfo(&pi); + + ret = (res == ERROR_SUCCESS); break; + } default: FIXME("Option %d STUB\n",dwOption); - INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + SetLastError(ERROR_INTERNET_INVALID_OPTION); ret = FALSE; break; } @@ -2380,13 +2588,16 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, { case INTERNET_OPTION_CALLBACK: { - LPWININETHANDLEHEADER lpwh; - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; + object_header_t *lpwh; - if (!(lpwh = WININET_GetObject(hInternet))) return FALSE; - r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK); + if (!(lpwh = WININET_GetObject(hInternet))) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } WININET_Release(lpwh); - return r; + INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_PROXY: { @@ -2418,6 +2629,63 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, wbuffer, wlen ); break; + case INTERNET_OPTION_PER_CONNECTION_OPTION: { + int i; + INTERNET_PER_CONN_OPTION_LISTW *listW; + INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer; + wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen ); + listW = wbuffer; + + listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW); + if (listA->pszConnection) + { + wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 ); + listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen ); + } + else + listW->pszConnection = NULL; + listW->dwOptionCount = listA->dwOptionCount; + listW->dwOptionError = listA->dwOptionError; + listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount ); + + for (i = 0; i < listA->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i; + INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i; + + optW->dwOption = optA->dwOption; + + switch (optA->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + if (optA->Value.pszValue) + { + wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 ); + optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen ); + } + else + optW->Value.pszValue = NULL; + break; + case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: + case INTERNET_PER_CONN_FLAGS: + case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: + optW->Value.dwValue = optA->Value.dwValue; + break; + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: + optW->Value.ftValue = optA->Value.ftValue; + default: + WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption); + optW->Value.dwValue = optA->Value.dwValue; + break; + } + } + } + break; default: wbuffer = lpBuffer; wlen = dwBufferLength; @@ -2426,7 +2694,29 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen); if( lpBuffer != wbuffer ) + { + if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION) + { + INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer; + int i; + for (i = 0; i < list->dwOptionCount; ++i) { + INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i; + switch (opt->dwOption) { + case INTERNET_PER_CONN_AUTOCONFIG_URL: + case INTERNET_PER_CONN_PROXY_BYPASS: + case INTERNET_PER_CONN_PROXY_SERVER: + case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: + case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: + HeapFree( GetProcessHeap(), 0, opt->Value.pszValue ); + break; + default: + break; + } + } + HeapFree( GetProcessHeap(), 0, list->pOptions ); + } HeapFree( GetProcessHeap(), 0, wbuffer ); + } return r; } @@ -2451,7 +2741,7 @@ BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption, FIXME("Flags %08x ignored\n", dwFlags); if( dwFlags & ~ISO_VALID_FLAGS ) { - INTERNET_SetLastError( ERROR_INVALID_PARAMETER ); + SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength ); @@ -2475,6 +2765,18 @@ BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) ); if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL ); @@ -2492,10 +2794,17 @@ BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, L TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size ); - if (!time || !string) return FALSE; + if (!time || !string || format != INTERNET_RFC1123_FORMAT) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR)) + if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; + } sprintfW( string, date, WININET_wkday[time->wDayOfWeek], @@ -2516,16 +2825,12 @@ BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD re { BOOL ret = FALSE; WCHAR *stringW; - int len; TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved ); - len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 ); - stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - + stringW = heap_strdupAtoW(string); if (stringW) { - MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len ); ret = InternetTimeToSystemTimeW( stringW, time, reserved ); HeapFree( GetProcessHeap(), 0, stringW ); } @@ -2674,15 +2979,16 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe if (dwFlags & FLAG_ICC_FORCE_CONNECTION) { - struct sockaddr_in sin; + struct sockaddr_storage saddr; + socklen_t sa_len = sizeof(saddr); int fd; - if (!GetAddress(hostW, port, &sin)) + if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len)) goto End; - fd = socket(sin.sin_family, SOCK_STREAM, 0); + fd = socket(saddr.ss_family, SOCK_STREAM, 0); if (fd != -1) { - if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0) + if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0) rc = TRUE; close(fd); } @@ -2731,17 +3037,18 @@ End: */ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved) { - WCHAR *szUrl; - INT len; + WCHAR *url = NULL; BOOL rc; - len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)))) - return FALSE; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len); - rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved); - HeapFree(GetProcessHeap(), 0, szUrl); - + if(lpszUrl) { + url = heap_strdupAtoW(lpszUrl); + if(!url) + return FALSE; + } + + rc = InternetCheckConnectionW(url, dwFlags, dwReserved); + + HeapFree(GetProcessHeap(), 0, url); return rc; } @@ -2754,13 +3061,14 @@ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwRese * RETURNS * handle of connection or NULL on failure */ -static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl, +static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { URL_COMPONENTSW urlComponents; WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024]; WCHAR password[1024], path[2048], extra[1024]; HINTERNET client = NULL, client1 = NULL; + DWORD res; TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), dwHeadersLength, dwFlags, dwContext); @@ -2805,11 +3113,15 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr else urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT; } + if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE; + /* FIXME: should use pointers, not handles, as handles are not thread-safe */ - client = HTTP_Connect(hIC, hostName, urlComponents.nPort, - userName, password, dwFlags, dwContext, INET_OPENURL); - if(client == NULL) + res = HTTP_Connect(hIC, hostName, urlComponents.nPort, + userName, password, dwFlags, dwContext, INET_OPENURL, &client); + if(res != ERROR_SUCCESS) { + INTERNET_SetLastError(res); break; + } if (urlComponents.dwExtraInfoLength) { WCHAR *path_extra; @@ -2844,7 +3156,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr /* gopher doesn't seem to be implemented in wine, but it's supposed * to be supported by InternetOpenUrlA. */ default: - INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); + SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME); break; } @@ -2864,7 +3176,7 @@ static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUr static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest) { struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW; - LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr; + appinfo_t *hIC = (appinfo_t*) workRequest->hdr; TRACE("%p\n", hIC); @@ -2878,7 +3190,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET ret = NULL; - LPWININETAPPINFOW hIC = NULL; + appinfo_t *hIC = NULL; if (TRACE_ON(wininet)) { TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders), @@ -2889,13 +3201,13 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, if (!lpszUrl) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); goto lend; } - hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet ); + hIC = (appinfo_t*)WININET_GetObject( hInternet ); if (NULL == hIC || hIC->hdr.htype != WH_HINIT) { - INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); goto lend; } @@ -2905,12 +3217,9 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, workRequest.asyncproc = AsyncInternetOpenUrlProc; workRequest.hdr = WININET_AddRef( &hIC->hdr ); - req = &workRequest.u.InternetOpenUrlW; - req->lpszUrl = WININET_strdupW(lpszUrl); - if (lpszHeaders) - req->lpszHeaders = WININET_strdupW(lpszHeaders); - else - req->lpszHeaders = 0; + req = &workRequest.u.InternetOpenUrlW; + req->lpszUrl = heap_strdupW(lpszUrl); + req->lpszHeaders = heap_strdupW(lpszHeaders); req->dwHeadersLength = dwHeadersLength; req->dwFlags = dwFlags; req->dwContext = dwContext; @@ -2919,7 +3228,7 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, /* * This is from windows. */ - INTERNET_SetLastError(ERROR_IO_PENDING); + SetLastError(ERROR_IO_PENDING); } else { ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext); } @@ -2944,20 +3253,16 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext) { HINTERNET rc = NULL; - - INT lenUrl; - INT lenHeaders = 0; + DWORD lenHeaders = 0; LPWSTR szUrl = NULL; LPWSTR szHeaders = NULL; TRACE("\n"); if(lpszUrl) { - lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 ); - szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR)); + szUrl = heap_strdupAtoW(lpszUrl); if(!szUrl) return NULL; - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl); } if(lpszHeaders) { @@ -3010,7 +3315,7 @@ static LPWITHREADERROR INTERNET_AllocThreadError(void) */ void INTERNET_SetLastError(DWORD dwError) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); @@ -3031,7 +3336,7 @@ void INTERNET_SetLastError(DWORD dwError) */ DWORD INTERNET_GetLastError(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) return 0; /* TlsGetValue clears last error, so set it again here */ SetLastError(lpwite->dwError); @@ -3058,8 +3363,13 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) HeapFree(GetProcessHeap(), 0, lpRequest); workRequest.asyncproc(&workRequest); - WININET_Release( workRequest.hdr ); + + if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES) + { + HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex)); + TlsSetValue(g_dwTlsErrIndex, NULL); + } return TRUE; } @@ -3072,7 +3382,7 @@ static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam) * RETURNS * */ -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) { BOOL bSuccess; LPWORKREQUEST lpNewRequest; @@ -3081,7 +3391,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST)); if (!lpNewRequest) - return FALSE; + return ERROR_OUTOFMEMORY; *lpNewRequest = *lpWorkRequest; @@ -3089,10 +3399,10 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) if (!bSuccess) { HeapFree(GetProcessHeap(), 0, lpNewRequest); - INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED); + return ERROR_INTERNET_ASYNC_THREAD_FAILED; } - return bSuccess; + return ERROR_SUCCESS; } @@ -3104,7 +3414,7 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest) */ LPSTR INTERNET_GetResponseBuffer(void) { - LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex); + LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex); if (!lpwite) lpwite = INTERNET_AllocThreadError(); TRACE("\n"); @@ -3193,14 +3503,14 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, LPDWORD lpdwNumberOfBytesAvailble, DWORD dwFlags, DWORD_PTR dwContext) { - WININETHANDLEHEADER *hdr; + object_header_t *hdr; DWORD res; TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext); hdr = WININET_GetObject( hFile ); if (!hdr) { - INTERNET_SetLastError(ERROR_INVALID_HANDLE); + SetLastError(ERROR_INVALID_HANDLE); return FALSE; } @@ -3451,6 +3761,9 @@ static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents, if (lpUrlComponents->lpszUrlPath) *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); + if (lpUrlComponents->lpszExtraInfo) + *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + return TRUE; } @@ -3535,7 +3848,7 @@ BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags, if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength) { - INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -3699,7 +4012,6 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, } } - if (lpUrlComponents->lpszUrlPath) { dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); @@ -3707,6 +4019,13 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, lpszUrl += dwLen; } + if (lpUrlComponents->lpszExtraInfo) + { + dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo); + memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR)); + lpszUrl += dwLen; + } + *lpszUrl = '\0'; return TRUE; @@ -3732,6 +4051,31 @@ DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR s return ERROR_SUCCESS; } +static DWORD zone_preference = 3; + +/*********************************************************************** + * PrivacySetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference ) +{ + FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) ); + + zone_preference = template; + return 0; +} + +/*********************************************************************** + * PrivacyGetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template, + LPWSTR preference, LPDWORD length ) +{ + FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length ); + + if (template) *template = zone_preference; + return 0; +} + DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags, DWORD_PTR* lpdwConnection, DWORD dwReserved ) { diff --git a/reactos/dll/win32/wininet/internet.h b/reactos/dll/win32/wininet/internet.h index 0dcf5a22ce6..e45176bb2c0 100644 --- a/reactos/dll/win32/wininet/internet.h +++ b/reactos/dll/win32/wininet/internet.h @@ -42,12 +42,7 @@ # include #endif -#if defined(__MINGW32__) || defined (_MSC_VER) -#include "ws2tcpip.h" -#ifndef MSG_WAITALL -#define MSG_WAITALL 0 -#endif -#else +#if !defined(__MINGW32__) && !defined(_MSC_VER) #define closesocket close #define ioctlsocket ioctl #endif /* __MINGW32__ */ @@ -62,33 +57,51 @@ typedef struct BOOL useSSL; int socketFD; void *ssl_s; - char *peek_msg; - char *peek_msg_mem; - size_t peek_len; } WININET_NETCONNECTION; -static inline LPWSTR WININET_strdupW( LPCWSTR str ) +static inline LPWSTR heap_strdupW(LPCWSTR str) { - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1)*sizeof(WCHAR) ); - if (ret) strcpyW( ret, str ); + LPWSTR ret = NULL; + + if(str) { + DWORD size; + + size = (strlenW(str)+1)*sizeof(WCHAR); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + memcpy(ret, str, size); + } + return ret; } -static inline LPWSTR WININET_strdup_AtoW( LPCSTR str ) +static inline WCHAR *heap_strdupAtoW(const char *str) { - int len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0); - LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if (ret) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len); + LPWSTR ret = NULL; + + if(str) { + DWORD len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + if(ret) + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + } + return ret; } -static inline LPSTR WININET_strdup_WtoA( LPCWSTR str ) +static inline char *heap_strdupWtoA(LPCWSTR str) { - int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); - LPSTR ret = HeapAlloc( GetProcessHeap(), 0, len ); - if (ret) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL); + char *ret = NULL; + + if(str) { + DWORD size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + ret = HeapAlloc(GetProcessHeap(), 0, size); + if(ret) + WideCharToMultiByte(CP_ACP, 0, str, -1, ret, size, NULL, NULL); + } + return ret; } @@ -124,24 +137,25 @@ typedef enum #define INET_OPENURL 0x0001 #define INET_CALLBACKW 0x0002 -typedef struct _WININETHANDLEHEADER WININETHANDLEHEADER, *LPWININETHANDLEHEADER; +typedef struct _object_header_t object_header_t; typedef struct { - void (*Destroy)(WININETHANDLEHEADER*); - void (*CloseConnection)(WININETHANDLEHEADER*); - DWORD (*QueryOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD*,BOOL); - DWORD (*SetOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD); - DWORD (*ReadFile)(WININETHANDLEHEADER*,void*,DWORD,DWORD*); - DWORD (*ReadFileExA)(WININETHANDLEHEADER*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); - BOOL (*WriteFile)(WININETHANDLEHEADER*,const void*,DWORD,DWORD*); - DWORD (*QueryDataAvailable)(WININETHANDLEHEADER*,DWORD*,DWORD,DWORD_PTR); - DWORD (*FindNextFileW)(WININETHANDLEHEADER*,void*); -} HANDLEHEADERVtbl; - -struct _WININETHANDLEHEADER + void (*Destroy)(object_header_t*); + void (*CloseConnection)(object_header_t*); + DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL); + DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD); + DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*); + DWORD (*ReadFileExA)(object_header_t*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); + DWORD (*ReadFileExW)(object_header_t*,INTERNET_BUFFERSW*,DWORD,DWORD_PTR); + DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*); + DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR); + DWORD (*FindNextFileW)(object_header_t*,void*); +} object_vtbl_t; + +struct _object_header_t { WH_TYPE htype; - const HANDLEHEADERVtbl *vtbl; + const object_vtbl_t *vtbl; HINTERNET hInternet; DWORD dwFlags; DWORD_PTR dwContext; @@ -156,28 +170,29 @@ struct _WININETHANDLEHEADER typedef struct { - WININETHANDLEHEADER hdr; + object_header_t hdr; LPWSTR lpszAgent; LPWSTR lpszProxy; LPWSTR lpszProxyBypass; LPWSTR lpszProxyUsername; LPWSTR lpszProxyPassword; DWORD dwAccessType; -} WININETAPPINFOW, *LPWININETAPPINFOW; +} appinfo_t; typedef struct { - WININETHANDLEHEADER hdr; - WININETAPPINFOW *lpAppInfo; + object_header_t hdr; + appinfo_t *lpAppInfo; LPWSTR lpszHostName; /* the final destination of the request */ LPWSTR lpszServerName; /* the name of the server we directly connect to */ LPWSTR lpszUserName; LPWSTR lpszPassword; INTERNET_PORT nHostPort; /* the final destination port of the request */ INTERNET_PORT nServerPort; /* the port of the server we directly connect to */ - struct sockaddr_in socketAddress; -} WININETHTTPSESSIONW, *LPWININETHTTPSESSIONW; + struct sockaddr_storage socketAddress; + socklen_t sa_len; +} http_session_t; #define HDR_ISREQUEST 0x0001 #define HDR_COMMADELIMITED 0x0002 @@ -194,25 +209,38 @@ typedef struct struct HttpAuthInfo; +typedef struct gzip_stream_t gzip_stream_t; + typedef struct { - WININETHANDLEHEADER hdr; - WININETHTTPSESSIONW *lpHttpSession; + object_header_t hdr; + http_session_t *lpHttpSession; LPWSTR lpszPath; LPWSTR lpszVerb; LPWSTR lpszRawHeaders; WININET_NETCONNECTION netConnection; LPWSTR lpszVersion; LPWSTR lpszStatusText; - DWORD dwContentLength; /* total number of bytes to be read */ - DWORD dwContentRead; /* bytes of the content read so far */ + DWORD dwBytesToWrite; + DWORD dwBytesWritten; HTTPHEADERW *pCustHeaders; DWORD nCustHeaders; HANDLE hCacheFile; LPWSTR lpszCacheFile; struct HttpAuthInfo *pAuthInfo; struct HttpAuthInfo *pProxyAuthInfo; -} WININETHTTPREQW, *LPWININETHTTPREQW; + + CRITICAL_SECTION read_section; /* section to protect the following fields */ + DWORD dwContentLength; /* total number of bytes to be read */ + DWORD dwContentRead; /* bytes of the content read so far */ + BOOL read_chunked; /* are we reading in chunked mode? */ + DWORD read_pos; /* current read position in read_buf */ + DWORD read_size; /* valid data size in read_buf */ + BYTE read_buf[4096]; /* buffer for already read but not returned data */ + + BOOL decoding; + gzip_stream_t *gzip_stream; +} http_request_t; @@ -297,6 +325,12 @@ struct WORKREQ_HTTPSENDREQUESTW BOOL bEndRequest; }; +struct WORKREQ_HTTPENDREQUESTW +{ + DWORD dwFlags; + DWORD_PTR dwContext; +}; + struct WORKREQ_SENDCALLBACK { DWORD_PTR dwContext; @@ -320,10 +354,15 @@ struct WORKREQ_INTERNETREADFILEEXA LPINTERNET_BUFFERSA lpBuffersOut; }; +struct WORKREQ_INTERNETREADFILEEXW +{ + LPINTERNET_BUFFERSW lpBuffersOut; +}; + typedef struct WORKREQ { void (*asyncproc)(struct WORKREQ*); - WININETHANDLEHEADER *hdr; + object_header_t *hdr; union { struct WORKREQ_FTPPUTFILEW FtpPutFileW; @@ -338,77 +377,69 @@ typedef struct WORKREQ struct WORKREQ_FTPRENAMEFILEW FtpRenameFileW; struct WORKREQ_FTPFINDNEXTW FtpFindNextW; struct WORKREQ_HTTPSENDREQUESTW HttpSendRequestW; + struct WORKREQ_HTTPENDREQUESTW HttpEndRequestW; struct WORKREQ_SENDCALLBACK SendCallback; - struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; + struct WORKREQ_INTERNETOPENURLW InternetOpenUrlW; struct WORKREQ_INTERNETREADFILEEXA InternetReadFileExA; + struct WORKREQ_INTERNETREADFILEEXW InternetReadFileExW; } u; } WORKREQUEST, *LPWORKREQUEST; -HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info ); -LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet ); -LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info ); -BOOL WININET_Release( LPWININETHANDLEHEADER info ); +HINTERNET WININET_AllocHandle( object_header_t *info ); +object_header_t *WININET_GetObject( HINTERNET hinternet ); +object_header_t *WININET_AddRef( object_header_t *info ); +BOOL WININET_Release( object_header_t *info ); BOOL WININET_FreeHandle( HINTERNET hinternet ); DWORD INET_QueryOption(DWORD,void*,DWORD*,BOOL); time_t ConvertTimeString(LPCWSTR asctime); -HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, +HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCWSTR lpszUserName, LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, DWORD dwInternalFlags); -HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, - INTERNET_PORT nServerPort, LPCWSTR lpszUserName, - LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, - DWORD dwInternalFlags); +DWORD HTTP_Connect(appinfo_t*,LPCWSTR, + INTERNET_PORT nServerPort, LPCWSTR lpszUserName, + LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext, + DWORD dwInternalFlags, HINTERNET*); BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa); + struct sockaddr *psa, socklen_t *sa_len); void INTERNET_SetLastError(DWORD dwError); DWORD INTERNET_GetLastError(void); -BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); +DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest); LPSTR INTERNET_GetResponseBuffer(void); LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen); -BOOLAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, - DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength, - DWORD dwContentLength, BOOL bEndRequest); -INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs, - LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, - LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, - DWORD dwFlags, DWORD_PTR dwContext); -BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr); - -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW lpwhr, LPCWSTR header); - BOOL NETCON_connected(WININET_NETCONNECTION *connection); -BOOL NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); +void NETCON_unload(void); +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol); -BOOL NETCON_close(WININET_NETCONNECTION *connection); -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_close(WININET_NETCONNECTION *connection); +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen); -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname); -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname); +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */); -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */); BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available); -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer); LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection); DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value); +int sock_get_error(int); extern void URLCacheContainers_CreateDefaults(void); extern void URLCacheContainers_DeleteAll(void); diff --git a/reactos/dll/win32/wininet/netconnection.c b/reactos/dll/win32/wininet/netconnection.c index 5d8b4d75534..c2560b5da37 100644 --- a/reactos/dll/win32/wininet/netconnection.c +++ b/reactos/dll/win32/wininet/netconnection.c @@ -23,6 +23,12 @@ #include "config.h" #include "wine/port.h" +#define NONAMELESSUNION + +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_POLL_H #include @@ -33,10 +39,12 @@ #ifdef HAVE_SYS_TIME_H # include #endif -#include #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif @@ -55,9 +63,6 @@ #undef FAR #undef DSA #endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #include #include @@ -81,7 +86,7 @@ #include "winsock2.h" #define RESPONSE_TIMEOUT 30 /* FROM internet.c */ -#define sock_get_error(x) WSAGetLastError() + WINE_DEFAULT_DEBUG_CHANNEL(wininet); @@ -95,11 +100,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); #include +static CRITICAL_SECTION init_ssl_cs; +static CRITICAL_SECTION_DEBUG init_ssl_cs_debug = +{ + 0, 0, &init_ssl_cs, + { &init_ssl_cs_debug.ProcessLocksList, + &init_ssl_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") } +}; +static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 }; + static void *OpenSSL_ssl_handle; static void *OpenSSL_crypto_handle; static SSL_METHOD *meth; static SSL_CTX *ctx; +static int hostname_idx; +static int error_idx; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -107,6 +124,7 @@ static SSL_CTX *ctx; MAKE_FUNCPTR(SSL_library_init); MAKE_FUNCPTR(SSL_load_error_strings); MAKE_FUNCPTR(SSLv23_method); +MAKE_FUNCPTR(SSL_CTX_free); MAKE_FUNCPTR(SSL_CTX_new); MAKE_FUNCPTR(SSL_new); MAKE_FUNCPTR(SSL_free); @@ -115,46 +133,240 @@ MAKE_FUNCPTR(SSL_connect); MAKE_FUNCPTR(SSL_shutdown); MAKE_FUNCPTR(SSL_write); MAKE_FUNCPTR(SSL_read); +MAKE_FUNCPTR(SSL_pending); +MAKE_FUNCPTR(SSL_get_ex_new_index); +MAKE_FUNCPTR(SSL_get_ex_data); +MAKE_FUNCPTR(SSL_set_ex_data); +MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx); MAKE_FUNCPTR(SSL_get_verify_result); MAKE_FUNCPTR(SSL_get_peer_certificate); MAKE_FUNCPTR(SSL_CTX_get_timeout); MAKE_FUNCPTR(SSL_CTX_set_timeout); MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths); -MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(SSL_CTX_set_verify); +MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data); /* OpenSSL's libcrypto functions that we use */ MAKE_FUNCPTR(BIO_new_fp); +MAKE_FUNCPTR(CRYPTO_num_locks); +MAKE_FUNCPTR(CRYPTO_set_id_callback); +MAKE_FUNCPTR(CRYPTO_set_locking_callback); +MAKE_FUNCPTR(ERR_free_strings); MAKE_FUNCPTR(ERR_get_error); MAKE_FUNCPTR(ERR_error_string); +MAKE_FUNCPTR(i2d_X509); +MAKE_FUNCPTR(sk_num); +MAKE_FUNCPTR(sk_value); #undef MAKE_FUNCPTR +static CRITICAL_SECTION *ssl_locks; +static unsigned int num_ssl_locks; + +static unsigned long ssl_thread_id(void) +{ + return GetCurrentThreadId(); +} + +static void ssl_lock_callback(int mode, int type, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + EnterCriticalSection(&ssl_locks[type]); + else + LeaveCriticalSection(&ssl_locks[type]); +} + +static PCCERT_CONTEXT X509_to_cert_context(X509 *cert) +{ + unsigned char* buffer,*p; + INT len; + BOOL malloced = FALSE; + PCCERT_CONTEXT ret; + + p = NULL; + len = pi2d_X509(cert,&p); + /* + * SSL 0.9.7 and above malloc the buffer if it is null. + * however earlier version do not and so we would need to alloc the buffer. + * + * see the i2d_X509 man page for more details. + */ + if (!p) + { + buffer = HeapAlloc(GetProcessHeap(),0,len); + p = buffer; + len = pi2d_X509(cert,&p); + } + else + { + buffer = p; + malloced = TRUE; + } + + ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); + + if (malloced) + free(buffer); + else + HeapFree(GetProcessHeap(),0,buffer); + + return ret; +} + +static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store, + WCHAR *server) +{ + BOOL ret; + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; + char *server_auth[] = { oid_server_auth }; + DWORD err = ERROR_SUCCESS; + + TRACE("verifying %s\n", debugstr_w(server)); + chainPara.RequestedUsage.Usage.cUsageIdentifier = 1; + chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth; + if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0, + NULL, &chain))) + { + if (chain->TrustStatus.dwErrorStatus) + { + if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) + err = ERROR_INTERNET_SEC_CERT_DATE_INVALID; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_UNTRUSTED_ROOT) + err = ERROR_INTERNET_INVALID_CA; + else if ((chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_OFFLINE_REVOCATION) || + (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) + err = ERROR_INTERNET_SEC_CERT_NO_REV; + else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) + err = ERROR_INTERNET_SEC_CERT_REVOKED; + else if (chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE) + err = ERROR_INTERNET_SEC_INVALID_CERT; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + else + { + CERT_CHAIN_POLICY_PARA policyPara; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara; + CERT_CHAIN_POLICY_STATUS policyStatus; + + sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara); + sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER; + sslExtraPolicyPara.pwszServerName = server; + policyPara.cbSize = sizeof(policyPara); + policyPara.dwFlags = 0; + policyPara.pvExtraPolicyPara = &sslExtraPolicyPara; + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, + chain, &policyPara, &policyStatus); + /* Any error in the policy status indicates that the + * policy couldn't be verified. + */ + if (ret && policyStatus.dwError) + { + if (policyStatus.dwError == CERT_E_CN_NO_MATCH) + err = ERROR_INTERNET_SEC_CERT_CN_INVALID; + else + err = ERROR_INTERNET_SEC_INVALID_CERT; + } + } + CertFreeCertificateChain(chain); + } + TRACE("returning %08x\n", err); + return err; +} + +static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx) +{ + SSL *ssl; + WCHAR *server; + BOOL ret = FALSE; + + ssl = pX509_STORE_CTX_get_ex_data(ctx, + pSSL_get_ex_data_X509_STORE_CTX_idx()); + server = pSSL_get_ex_data(ssl, hostname_idx); + if (preverify_ok) + { + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + if (store) + { + X509 *cert; + int i; + PCCERT_CONTEXT endCert = NULL; + + ret = TRUE; + for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++) + { + PCCERT_CONTEXT context; + + cert = (X509 *)psk_value((struct stack_st *)ctx->chain, i); + if ((context = X509_to_cert_context(cert))) + { + if (i == 0) + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, &endCert); + else + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_ALWAYS, NULL); + CertFreeCertificateContext(context); + } + } + if (!endCert) ret = FALSE; + if (ret) + { + DWORD_PTR err = netconn_verify_cert(endCert, store, server); + + if (err) + { + pSSL_set_ex_data(ssl, error_idx, (void *)err); + ret = FALSE; + } + } + CertFreeCertificateContext(endCert); + CertCloseStore(store, 0); + } + } + return ret; +} + #endif -BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) +DWORD NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) { connection->useSSL = FALSE; connection->socketFD = -1; if (useSSL) { #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + int i; + TRACE("using SSL connection\n"); + EnterCriticalSection(&init_ssl_cs); if (OpenSSL_ssl_handle) /* already initialized everything */ - return TRUE; + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_SUCCESS; + } OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); if (!OpenSSL_ssl_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); if (!OpenSSL_crypto_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + LeaveCriticalSection(&init_ssl_cs); + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } /* mmm nice ugly macroness */ @@ -163,13 +375,14 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNSSL(SSL_library_init); DYNSSL(SSL_load_error_strings); DYNSSL(SSLv23_method); + DYNSSL(SSL_CTX_free); DYNSSL(SSL_CTX_new); DYNSSL(SSL_new); DYNSSL(SSL_free); @@ -178,12 +391,18 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) DYNSSL(SSL_shutdown); DYNSSL(SSL_write); DYNSSL(SSL_read); + DYNSSL(SSL_pending); + DYNSSL(SSL_get_ex_new_index); + DYNSSL(SSL_get_ex_data); + DYNSSL(SSL_set_ex_data); + DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx); DYNSSL(SSL_get_verify_result); DYNSSL(SSL_get_peer_certificate); DYNSSL(SSL_CTX_get_timeout); DYNSSL(SSL_CTX_set_timeout); DYNSSL(SSL_CTX_set_default_verify_paths); - DYNSSL(i2d_X509); + DYNSSL(SSL_CTX_set_verify); + DYNSSL(X509_STORE_CTX_get_ex_data); #undef DYNSSL #define DYNCRYPTO(x) \ @@ -191,12 +410,19 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) if (!p##x) \ { \ ERR("failed to load symbol %s\n", #x); \ - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); \ - return FALSE; \ + LeaveCriticalSection(&init_ssl_cs); \ + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNCRYPTO(BIO_new_fp); + DYNCRYPTO(CRYPTO_num_locks); + DYNCRYPTO(CRYPTO_set_id_callback); + DYNCRYPTO(CRYPTO_set_locking_callback); + DYNCRYPTO(ERR_free_strings); DYNCRYPTO(ERR_get_error); DYNCRYPTO(ERR_error_string); + DYNCRYPTO(i2d_X509); + DYNCRYPTO(sk_num); + DYNCRYPTO(sk_value); #undef DYNCRYPTO pSSL_library_init(); @@ -204,15 +430,75 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ meth = pSSLv23_method(); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; + ctx = pSSL_CTX_new(meth); + if (!pSSL_CTX_set_default_verify_paths(ctx)) + { + ERR("SSL_CTX_set_default_verify_paths failed: %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", + NULL, NULL, NULL); + if (hostname_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + error_idx = pSSL_get_ex_new_index(0, (void *)"error index", + NULL, NULL, NULL); + if (error_idx == -1) + { + ERR("SSL_get_ex_new_index failed; %s\n", + pERR_error_string(pERR_get_error(), 0)); + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify); + + pCRYPTO_set_id_callback(ssl_thread_id); + num_ssl_locks = pCRYPTO_num_locks(); + ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION)); + if (!ssl_locks) + { + LeaveCriticalSection(&init_ssl_cs); + return ERROR_OUTOFMEMORY; + } + for (i = 0; i < num_ssl_locks; i++) + InitializeCriticalSection(&ssl_locks[i]); + pCRYPTO_set_locking_callback(ssl_lock_callback); + LeaveCriticalSection(&init_ssl_cs); #else FIXME("can't use SSL, not compiled in.\n"); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); - return FALSE; + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; #endif } - return TRUE; + return ERROR_SUCCESS; +} + +void NETCON_unload(void) +{ +#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) + if (OpenSSL_crypto_handle) + { + pERR_free_strings(); + wine_dlclose(OpenSSL_crypto_handle, NULL, 0); + } + if (OpenSSL_ssl_handle) + { + if (ctx) + pSSL_CTX_free(ctx); + wine_dlclose(OpenSSL_ssl_handle, NULL, 0); + } + if (ssl_locks) + { + int i; + for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]); + HeapFree(GetProcessHeap(), 0, ssl_locks); + } +#endif } BOOL NETCON_connected(WININET_NETCONNECTION *connection) @@ -223,9 +509,8 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection) return TRUE; } -#if 0 /* translate a unix error code into a winsock one */ -static int sock_get_error( int err ) +int sock_get_error( int err ) { #if !defined(__MINGW32__) && !defined (_MSC_VER) switch (err) @@ -290,47 +575,39 @@ static int sock_get_error( int err ) #endif return err; } -#endif /****************************************************************************** * NETCON_create * Basically calls 'socket()' */ -BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, +DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain, int type, int protocol) { #ifdef SONAME_LIBSSL if (connection->useSSL) - return FALSE; + return ERROR_NOT_SUPPORTED; #endif connection->socketFD = socket(domain, type, protocol); if (connection->socketFD == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + + return ERROR_SUCCESS; } /****************************************************************************** * NETCON_close * Basically calls 'close()' unless we should use SSL */ -BOOL NETCON_close(WININET_NETCONNECTION *connection) +DWORD NETCON_close(WININET_NETCONNECTION *connection) { int result; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_SUCCESS; #ifdef SONAME_LIBSSL if (connection->useSSL) { - HeapFree(GetProcessHeap(),0,connection->peek_msg_mem); - connection->peek_msg = NULL; - connection->peek_msg_mem = NULL; - connection->peek_len = 0; - pSSL_shutdown(connection->ssl_s); pSSL_free(connection->ssl_s); connection->ssl_s = NULL; @@ -343,52 +620,34 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection) connection->socketFD = -1; if (result == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; -} -#ifdef SONAME_LIBSSL -static BOOL check_hostname(X509 *cert, char *hostname) -{ - /* FIXME: implement */ - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } -#endif + /****************************************************************************** * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ -BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) +DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname) { + DWORD res = ERROR_NOT_SUPPORTED; #ifdef SONAME_LIBSSL long verify_res; X509 *cert; - int len; - char *hostname_unix; /* can't connect if we are already connected */ if (connection->useSSL) { ERR("already connected\n"); - return FALSE; + return ERROR_INTERNET_CANNOT_CONNECT; } - ctx = pSSL_CTX_new(meth); - if (!pSSL_CTX_set_default_verify_paths(ctx)) - { - ERR("SSL_CTX_set_default_verify_paths failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } connection->ssl_s = pSSL_new(ctx); if (!connection->ssl_s) { ERR("SSL_new failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_OUTOFMEMORY); + res = ERROR_OUTOFMEMORY; goto fail; } @@ -396,23 +655,25 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) { ERR("SSL_set_fd failed: %s\n", pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; goto fail; } if (pSSL_connect(connection->ssl_s) <= 0) { - ERR("SSL_connect failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); + res = (DWORD_PTR)pSSL_get_ex_data(connection->ssl_s, error_idx); + if (!res) + res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + ERR("SSL_connect failed: %d\n", res); goto fail; } + pSSL_set_ex_data(connection->ssl_s, hostname_idx, hostname); cert = pSSL_get_peer_certificate(connection->ssl_s); if (!cert) { ERR("no certificate for server %s\n", debugstr_w(hostname)); /* FIXME: is this the best error? */ - INTERNET_SetLastError(ERROR_INTERNET_INVALID_CA); + res = ERROR_INTERNET_INVALID_CA; goto fail; } verify_res = pSSL_get_verify_result(connection->ssl_s); @@ -423,25 +684,8 @@ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) * the moment */ } - len = WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, NULL, 0, NULL, NULL); - hostname_unix = HeapAlloc(GetProcessHeap(), 0, len); - if (!hostname_unix) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto fail; - } - WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL); - - if (!check_hostname(cert, hostname_unix)) - { - HeapFree(GetProcessHeap(), 0, hostname_unix); - INTERNET_SetLastError(ERROR_INTERNET_SEC_CERT_CN_INVALID); - goto fail; - } - - HeapFree(GetProcessHeap(), 0, hostname_unix); connection->useSSL = TRUE; - return TRUE; + return ERROR_SUCCESS; fail: if (connection->ssl_s) @@ -451,32 +695,29 @@ fail: connection->ssl_s = NULL; } #endif - return FALSE; + return res; } /****************************************************************************** * NETCON_connect * Connects to the specified address. */ -BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, +DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, unsigned int addrlen) { int result; - if (!NETCON_connected(connection)) return FALSE; - result = connect(connection->socketFD, serv_addr, addrlen); if (result == -1) { WARN("Unable to connect to host (%s)\n", strerror(errno)); - INTERNET_SetLastError(sock_get_error(errno)); closesocket(connection->socketFD); connection->socketFD = -1; - return FALSE; + return sock_get_error(errno); } - return TRUE; + return ERROR_SUCCESS; } /****************************************************************************** @@ -484,19 +725,16 @@ BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *se * Basically calls 'send()' unless we should use SSL * number of chars send is put in *sent */ -BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, +DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, int *sent /* out */) { - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!connection->useSSL) { *sent = send(connection->socketFD, msg, len, flags); if (*sent == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return sock_get_error(errno); + return ERROR_SUCCESS; } else { @@ -505,10 +743,10 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, FIXME("SSL_write doesn't support any flags (%08x)\n", flags); *sent = pSSL_write(connection->ssl_s, msg, len); if (*sent < 1 && len) - return FALSE; - return TRUE; + return ERROR_INTERNET_CONNECTION_ABORTED; + return ERROR_SUCCESS; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -518,77 +756,25 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, * Basically calls 'recv()' unless we should use SSL * number of chars received is put in *recvd */ -BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, +DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, int *recvd /* out */) { *recvd = 0; - if (!NETCON_connected(connection)) return FALSE; + if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED; if (!len) - return TRUE; + return ERROR_SUCCESS; if (!connection->useSSL) { *recvd = recv(connection->socketFD, buf, len, flags); - if (*recvd == -1) - { - INTERNET_SetLastError(sock_get_error(errno)); - return FALSE; - } - return TRUE; + return *recvd == -1 ? sock_get_error(errno) : ERROR_SUCCESS; } else { #ifdef SONAME_LIBSSL - if (flags & ~(MSG_PEEK|MSG_WAITALL)) - FIXME("SSL_read does not support the following flag: %08x\n", flags); - - /* this ugly hack is all for MSG_PEEK. eww gross */ - if (flags & MSG_PEEK && !connection->peek_msg) - { - connection->peek_msg = connection->peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1); - } - else if (flags & MSG_PEEK && connection->peek_msg) - { - if (len < connection->peek_len) - FIXME("buffer isn't big enough. Do the expect us to wrap?\n"); - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - return TRUE; - } - else if (connection->peek_msg) - { - *recvd = min(len, connection->peek_len); - memcpy(buf, connection->peek_msg, *recvd); - connection->peek_len -= *recvd; - connection->peek_msg += *recvd; - if (connection->peek_len == 0) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - /* check if we got enough data from the peek buffer */ - if (!(flags & MSG_WAITALL) || (*recvd == len)) - return TRUE; - /* otherwise, fall through */ - } - *recvd += pSSL_read(connection->ssl_s, (char*)buf + *recvd, len - *recvd); - if (flags & MSG_PEEK) /* must copy stuff into buffer */ - { - connection->peek_len = *recvd; - if (!*recvd) - { - HeapFree(GetProcessHeap(), 0, connection->peek_msg_mem); - connection->peek_msg_mem = NULL; - connection->peek_msg = NULL; - } - else - memcpy(connection->peek_msg, buf, *recvd); - } - if (*recvd < 1 && len) - return FALSE; - return TRUE; + *recvd = pSSL_read(connection->ssl_s, buf, len); + return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED; #else - return FALSE; + return ERROR_NOT_SUPPORTED; #endif } } @@ -604,13 +790,9 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail if (!NETCON_connected(connection)) return FALSE; -#ifdef SONAME_LIBSSL - if (connection->peek_msg) *available = connection->peek_len; -#endif - -#ifdef FIONREAD if (!connection->useSSL) { +#ifdef FIONREAD int unread; int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread); if (!retval) @@ -618,155 +800,28 @@ BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *avail TRACE("%d bytes of queued, but unread data\n", unread); *available += unread; } - } #endif - return TRUE; -} - -/****************************************************************************** - * NETCON_getNextLine - */ -BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer) -{ - - TRACE("\n"); - - if (!NETCON_connected(connection)) return FALSE; - - if (!connection->useSSL) - { - struct timeval tv; - fd_set infd; - BOOL bSuccess = FALSE; - DWORD nRecv = 0; - - FD_ZERO(&infd); - FD_SET(connection->socketFD, &infd); - tv.tv_sec=RESPONSE_TIMEOUT; - tv.tv_usec=0; - - while (nRecv < *dwBuffer) - { - if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0) - { - if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0) - { - INTERNET_SetLastError(sock_get_error(errno)); - goto lend; - } - - if (lpszBuffer[nRecv] == '\n') - { - bSuccess = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - else - { - INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT); - goto lend; - } - } - - lend: /* FIXME: don't use labels */ - if (bSuccess) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE(":%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - else - { - return FALSE; - } } else { #ifdef SONAME_LIBSSL - long prev_timeout; - DWORD nRecv = 0; - BOOL success = TRUE; - - prev_timeout = pSSL_CTX_get_timeout(ctx); - pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT); - - while (nRecv < *dwBuffer) - { - int recv = 1; - if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv)) - { - INTERNET_SetLastError(ERROR_CONNECTION_ABORTED); - success = FALSE; - } - - if (lpszBuffer[nRecv] == '\n') - { - success = TRUE; - break; - } - if (lpszBuffer[nRecv] != '\r') - nRecv++; - } - - pSSL_CTX_set_timeout(ctx, prev_timeout); - if (success) - { - lpszBuffer[nRecv++] = '\0'; - *dwBuffer = nRecv; - TRACE("_SSL:%u %s\n", nRecv, lpszBuffer); - return TRUE; - } - return FALSE; -#else - return FALSE; + *available = pSSL_pending(connection->ssl_s); #endif } + return TRUE; } - LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection) { #ifdef SONAME_LIBSSL X509* cert; - unsigned char* buffer,*p; - INT len; - BOOL malloced = FALSE; LPCVOID r = NULL; if (!connection->useSSL) return NULL; cert = pSSL_get_peer_certificate(connection->ssl_s); - p = NULL; - len = pi2d_X509(cert,&p); - /* - * SSL 0.9.7 and above malloc the buffer if it is null. - * however earlier version do not and so we would need to alloc the buffer. - * - * see the i2d_X509 man page for more details. - */ - if (!p) - { - buffer = HeapAlloc(GetProcessHeap(),0,len); - p = buffer; - len = pi2d_X509(cert,&p); - } - else - { - buffer = p; - malloced = TRUE; - } - - r = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); - - if (malloced) - free(buffer); - else - HeapFree(GetProcessHeap(),0,buffer); - + r = X509_to_cert_context(cert); return r; #else return NULL; @@ -788,7 +843,7 @@ DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value tv.tv_usec = (value % 1000) * 1000; result = setsockopt(connection->socketFD, SOL_SOCKET, - send ? SO_SNDTIMEO : SO_RCVTIMEO, &tv, + send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv, sizeof(tv)); if (result == -1) diff --git a/reactos/dll/win32/wininet/resource.h b/reactos/dll/win32/wininet/resource.h index 8a6e4d152e2..279c1123db8 100644 --- a/reactos/dll/win32/wininet/resource.h +++ b/reactos/dll/win32/wininet/resource.h @@ -18,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include + +#define IDD_AUTHDLG 0x399 #define IDD_PROXYDLG 0x400 #define IDC_PROXY 0x401 @@ -25,5 +29,6 @@ #define IDC_USERNAME 0x403 #define IDC_PASSWORD 0x404 #define IDC_SAVEPASSWORD 0x405 +#define IDC_SERVER 0x406 #define IDS_LANCONNECTION 0x500 diff --git a/reactos/dll/win32/wininet/rsrc.rc b/reactos/dll/win32/wininet/rsrc.rc index 5a815116b03..52ea8d4e8d2 100644 --- a/reactos/dll/win32/wininet/rsrc.rc +++ b/reactos/dll/win32/wininet/rsrc.rc @@ -43,24 +43,28 @@ #include "wininet_Bg.rc" #include "wininet_Cs.rc" #include "wininet_Da.rc" -#include "wininet_De.rc" #include "wininet_En.rc" #include "wininet_Eo.rc" #include "wininet_Es.rc" #include "wininet_Fi.rc" -#include "wininet_Fr.rc" #include "wininet_Hu.rc" #include "wininet_It.rc" -#include "wininet_Ja.rc" #include "wininet_Ko.rc" #include "wininet_Nl.rc" -#include "wininet_No.rc" #include "wininet_Pl.rc" +#include "wininet_Sv.rc" +#include "wininet_Uk.rc" +#include "wininet_Tr.rc" + +/* UTF-8 */ +#include "wininet_De.rc" +#include "wininet_Fr.rc" +#include "wininet_Ja.rc" +#include "wininet_Lt.rc" +#include "wininet_No.rc" #include "wininet_Pt.rc" #include "wininet_Ro.rc" #include "wininet_Ru.rc" #include "wininet_Si.rc" -#include "wininet_Sv.rc" -#include "wininet_Uk.rc" -#include "wininet_Tr.rc" #include "wininet_Zh.rc" + diff --git a/reactos/dll/win32/wininet/urlcache.c b/reactos/dll/win32/wininet/urlcache.c index c839419f136..29d26ab0b6b 100644 --- a/reactos/dll/win32/wininet/urlcache.c +++ b/reactos/dll/win32/wininet/urlcache.c @@ -465,7 +465,6 @@ static void URLCacheContainer_CloseIndex(URLCACHECONTAINER * pContainer) static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, LPWSTR mutex_name) { URLCACHECONTAINER * pContainer = HeapAlloc(GetProcessHeap(), 0, sizeof(URLCACHECONTAINER)); - int path_len = strlenW(path); int cache_prefix_len = strlenW(cache_prefix); if (!pContainer) @@ -476,15 +475,13 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, LPCWSTR path, pContainer->hMapping = NULL; pContainer->file_size = 0; - pContainer->path = HeapAlloc(GetProcessHeap(), 0, (path_len + 1) * sizeof(WCHAR)); + pContainer->path = heap_strdupW(path); if (!pContainer->path) { HeapFree(GetProcessHeap(), 0, pContainer); return FALSE; } - memcpy(pContainer->path, path, (path_len + 1) * sizeof(WCHAR)); - pContainer->cache_prefix = HeapAlloc(GetProcessHeap(), 0, (cache_prefix_len + 1) * sizeof(WCHAR)); if (!pContainer->cache_prefix) { @@ -593,6 +590,9 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl)); + if(!lpwszUrl) + return ERROR_INVALID_PARAMETER; + LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) { int prefix_len = strlenW(pContainer->cache_prefix); @@ -609,17 +609,15 @@ static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAIN static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer) { + LPWSTR url = NULL; DWORD ret; - LPWSTR lpwszUrl; - int url_len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0); - if (url_len && (lpwszUrl = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(WCHAR)))) - { - MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, lpwszUrl, url_len); - ret = URLCacheContainers_FindContainerW(lpwszUrl, ppContainer); - HeapFree(GetProcessHeap(), 0, lpwszUrl); - return ret; - } - return GetLastError(); + + if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl))) + return ERROR_OUTOFMEMORY; + + ret = URLCacheContainers_FindContainerW(url, ppContainer); + HeapFree(GetProcessHeap(), 0, url); + return ret; } static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer) @@ -692,6 +690,7 @@ static LPURLCACHE_HEADER URLCacheContainer_LockIndex(URLCACHECONTAINER * pContai * of the memory mapped file */ if (pHeader->dwFileSize != pContainer->file_size) { + UnmapViewOfFile( pHeader ); URLCacheContainer_CloseIndex(pContainer); error = URLCacheContainer_OpenIndex(pContainer); if (error != ERROR_SUCCESS) @@ -1240,17 +1239,15 @@ static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) { LPSTR urlA; - int url_len; BOOL ret; - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrl); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, urlA, url_len, NULL, NULL); + ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); HeapFree(GetProcessHeap(), 0, urlA); return ret; @@ -1451,6 +1448,28 @@ static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH return FALSE; } +/*********************************************************************** + * FreeUrlCacheSpaceA (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + + /*********************************************************************** + * FreeUrlCacheSpaceW (WININET.@) + * + */ +BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR lpszCachePath, DWORD dwSize, DWORD dwFilter) +{ + FIXME("stub!\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + /*********************************************************************** * GetUrlCacheEntryInfoExA (WININET.@) * @@ -1482,7 +1501,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExA( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoA(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1682,7 +1705,11 @@ BOOL WINAPI GetUrlCacheEntryInfoExW( return FALSE; } if (dwFlags != 0) + { FIXME("Undocumented flag(s): %x\n", dwFlags); + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } return GetUrlCacheEntryInfoW(lpszUrl, lpCacheEntryInfo, lpdwCacheEntryInfoBufSize); } @@ -1869,6 +1896,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileA( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -1958,6 +1992,13 @@ BOOL WINAPI RetrieveUrlCacheEntryFileW( } pUrlEntry = (URL_CACHEFILE_ENTRY *)pEntry; + if (!pUrlEntry->dwOffsetLocalName) + { + URLCacheContainer_UnlockIndex(pContainer, pHeader); + SetLastError(ERROR_INVALID_DATA); + return FALSE; + } + TRACE("Found URL: %s\n", (LPSTR)pUrlEntry + pUrlEntry->dwOffsetUrl); TRACE("Header info: %s\n", (LPBYTE)pUrlEntry + pUrlEntry->dwOffsetHeaderInfo); @@ -2142,21 +2183,16 @@ BOOL WINAPI CreateUrlCacheEntryA( IN DWORD dwReserved ) { - DWORD len; WCHAR *url_name; WCHAR *file_extension; WCHAR file_name[MAX_PATH]; BOOL bSuccess = FALSE; DWORD dwError = 0; - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0)) != 0 && - (url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) { - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); - if ((len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0)) != 0 && - (file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))) != 0) + if (lpszFileExtension && (file_extension = heap_strdupAtoW(lpszFileExtension))) { - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) { if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) @@ -2211,7 +2247,11 @@ BOOL WINAPI CreateUrlCacheEntryW( BOOL bFound = FALSE; int count; DWORD error; + HANDLE hFile; + FILETIME ft; + static const WCHAR szWWW[] = {'w','w','w',0}; + static const WCHAR fmt[] = {'%','0','8','X','%','s',0}; TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n", debugstr_w(lpszUrlName), @@ -2221,11 +2261,7 @@ BOOL WINAPI CreateUrlCacheEntryW( dwReserved); if (dwReserved) - { - ERR("dwReserved != 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + FIXME("dwReserved 0x%08x\n", dwReserved); lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName); @@ -2318,7 +2354,6 @@ BOOL WINAPI CreateUrlCacheEntryW( for (i = 0; i < 255; i++) { static const WCHAR szFormat[] = {'[','%','u',']','%','s',0}; - HANDLE hFile; WCHAR *p; wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension); @@ -2346,6 +2381,18 @@ BOOL WINAPI CreateUrlCacheEntryW( } } + GetSystemTimeAsFileTime(&ft); + wsprintfW(lpszFileNameNoPath + countnoextension, fmt, ft.dwLowDateTime, szExtension); + + TRACE("Trying: %s\n", debugstr_w(lpszFileName)); + hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return TRUE; + } + + WARN("Could not find a unique filename\n"); return FALSE; } @@ -2447,25 +2494,17 @@ static BOOL CommitUrlCacheEntryInternal( if (!(pHeader = URLCacheContainer_LockIndex(pContainer))) return FALSE; - len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - lpszUrlNameA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); + lpszUrlNameA = heap_strdupWtoA(lpszUrlName); if (!lpszUrlNameA) { error = GetLastError(); goto cleanup; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, lpszUrlNameA, len, NULL, NULL); - if (lpszFileExtension) + if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension))) { - len = WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, NULL, 0, NULL, NULL); - lpszFileExtensionA = HeapAlloc(GetProcessHeap(), 0, len * sizeof(char)); - if (!lpszFileExtensionA) - { - error = GetLastError(); - goto cleanup; - } - WideCharToMultiByte(CP_ACP, 0, lpszFileExtension, -1, lpszFileExtensionA, len, NULL, NULL); + error = GetLastError(); + goto cleanup; } if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) @@ -2622,7 +2661,6 @@ BOOL WINAPI CommitUrlCacheEntryA( IN LPCSTR lpszOriginalUrl ) { - DWORD len; WCHAR *url_name = NULL; WCHAR *local_file_name = NULL; WCHAR *original_url = NULL; @@ -2638,35 +2676,27 @@ BOOL WINAPI CommitUrlCacheEntryA( debugstr_a(lpszFileExtension), debugstr_a(lpszOriginalUrl)); - len = MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, NULL, 0); - url_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + url_name = heap_strdupAtoW(lpszUrlName); if (!url_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszUrlName, -1, url_name, len); if (lpszLocalFileName) { - len = MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, NULL, 0); - local_file_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + local_file_name = heap_strdupAtoW(lpszLocalFileName); if (!local_file_name) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszLocalFileName, -1, local_file_name, len); } if (lpszFileExtension) { - len = MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, NULL, 0); - file_extension = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + file_extension = heap_strdupAtoW(lpszFileExtension); if (!file_extension) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszFileExtension, -1, file_extension, len); } if (lpszOriginalUrl) { - len = MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, NULL, 0); - original_url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + original_url = heap_strdupAtoW(lpszOriginalUrl); if (!original_url) goto cleanup; - MultiByteToWideChar(CP_ACP, 0, lpszOriginalUrl, -1, original_url, len); } bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime, @@ -2712,12 +2742,8 @@ BOOL WINAPI CommitUrlCacheEntryW( debugstr_w(lpszFileExtension), debugstr_w(lpszOriginalUrl)); - if (!lpHeaderInfo || - ((len = WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, NULL, 0, NULL, NULL)) != 0 && - (header_info = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR) * len)) != 0)) + if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo))) { - if (header_info) - WideCharToMultiByte(CP_ACP, 0, lpHeaderInfo, -1, header_info, len, NULL, NULL); if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime, CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl)) { @@ -2940,19 +2966,16 @@ BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName) struct _HASH_ENTRY * pHashEntry; CACHEFILE_ENTRY * pEntry; LPSTR urlA; - int url_len; DWORD error; TRACE("(%s)\n", debugstr_w(lpszUrlName)); - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - urlA = HeapAlloc(GetProcessHeap(), 0, url_len * sizeof(CHAR)); + urlA = heap_strdupWtoA(lpszUrlName); if (!urlA) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, urlA, url_len, NULL, NULL); error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) @@ -3133,14 +3156,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, NULL, 0); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - MultiByteToWideChar(CP_ACP, 0, lpszUrlSearchPattern, -1, pEntryHandle->lpszUrlSearchPattern, len); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3174,14 +3195,12 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - int len = strlenW(lpszUrlSearchPattern); - pEntryHandle->lpszUrlSearchPattern = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); if (!pEntryHandle->lpszUrlSearchPattern) { HeapFree(GetProcessHeap(), 0, pEntryHandle); return NULL; } - memcpy(pEntryHandle->lpszUrlSearchPattern, lpszUrlSearchPattern, (len + 1) * sizeof(WCHAR)); } else pEntryHandle->lpszUrlSearchPattern = NULL; @@ -3623,10 +3642,26 @@ BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLa /*********************************************************************** * GetDiskInfoA (WININET.@) */ -BOOL WINAPI GetDiskInfoA(PCSTR p0, PDWORD p1, PDWORDLONG p2, PDWORDLONG p3) +BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total) { - FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3); - return FALSE; + BOOL ret; + ULARGE_INTEGER bytes_free, bytes_total; + + TRACE("(%s, %p, %p, %p)\n", debugstr_a(path), cluster_size, free, total); + + if (!path) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if ((ret = GetDiskFreeSpaceExA(path, NULL, &bytes_total, &bytes_free))) + { + if (cluster_size) *cluster_size = 1; + if (free) *free = bytes_free.QuadPart; + if (total) *total = bytes_total.QuadPart; + } + return ret; } /*********************************************************************** @@ -3637,3 +3672,12 @@ DWORD WINAPI RegisterUrlCacheNotification(LPVOID a, DWORD b, DWORD c, DWORD d, D FIXME("(%p %x %x %x %x %x)\n", a, b, c, d, e, f); return 0; } + +/*********************************************************************** + * IncrementUrlCacheHeaderData (WININET.@) + */ +BOOL WINAPI IncrementUrlCacheHeaderData(DWORD index, LPDWORD data) +{ + FIXME("(%u, %p)\n", index, data); + return FALSE; +} diff --git a/reactos/dll/win32/wininet/utility.c b/reactos/dll/win32/wininet/utility.c index b0d9c9c91c6..66fbecdd653 100644 --- a/reactos/dll/win32/wininet/utility.c +++ b/reactos/dll/win32/wininet/utility.c @@ -25,6 +25,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #include #include @@ -40,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); +#ifndef HAVE_GETADDRINFO + /* critical section to protect non-reentrant gethostbyname() */ static CRITICAL_SECTION cs_gethostbyname; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -50,6 +56,8 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 }; +#endif + #define TIME_STRING_LEN 30 time_t ConvertTimeString(LPCWSTR asctime) @@ -137,12 +145,18 @@ time_t ConvertTimeString(LPCWSTR asctime) BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, - struct sockaddr_in *psa) + struct sockaddr *psa, socklen_t *sa_len) { WCHAR *found; char *name; int len, sz; +#ifdef HAVE_GETADDRINFO + struct addrinfo *res, hints; + int ret; +#else struct hostent *phe; + struct sockaddr_in *sin = (struct sockaddr_in *)psa; +#endif TRACE("%s\n", debugstr_w(lpszServerName)); @@ -158,27 +172,75 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, len = strlenW(lpszServerName); sz = WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, NULL, 0, NULL, NULL ); - name = HeapAlloc(GetProcessHeap(), 0, sz+1); + if (!(name = HeapAlloc( GetProcessHeap(), 0, sz + 1 ))) return FALSE; WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL ); name[sz] = 0; +#ifdef HAVE_GETADDRINFO + memset( &hints, 0, sizeof(struct addrinfo) ); + /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on + * their IPv6 addresses even though they have IPv6 addresses in the DNS. + */ + hints.ai_family = AF_INET; + + ret = getaddrinfo( name, NULL, &hints, &res ); + HeapFree( GetProcessHeap(), 0, name ); + if (ret != 0) + { + TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(lpszServerName), gai_strerror(ret)); + hints.ai_family = AF_INET6; + ret = getaddrinfo( name, NULL, &hints, &res ); + if (ret != 0) + { + TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); + return FALSE; + } + } + if (*sa_len < res->ai_addrlen) + { + WARN("address too small\n"); + freeaddrinfo( res ); + return FALSE; + } + *sa_len = res->ai_addrlen; + memcpy( psa, res->ai_addr, res->ai_addrlen ); + /* Copy port */ + switch (res->ai_family) + { + case AF_INET: + ((struct sockaddr_in *)psa)->sin_port = htons(nServerPort); + break; + case AF_INET6: + ((struct sockaddr_in6 *)psa)->sin6_port = htons(nServerPort); + break; + } + + freeaddrinfo( res ); +#else EnterCriticalSection( &cs_gethostbyname ); phe = gethostbyname(name); HeapFree( GetProcessHeap(), 0, name ); if (NULL == phe) { - TRACE("Failed to get hostname: (%s)\n", debugstr_w(lpszServerName) ); + TRACE("failed to get address of %s (%d)\n", debugstr_w(lpszServerName), h_errno); LeaveCriticalSection( &cs_gethostbyname ); return FALSE; } - - memset(psa,0,sizeof(struct sockaddr_in)); - memcpy((char *)&psa->sin_addr, phe->h_addr, phe->h_length); - psa->sin_family = phe->h_addrtype; - psa->sin_port = htons(nServerPort); + if (*sa_len < sizeof(struct sockaddr_in)) + { + WARN("address too small\n"); + LeaveCriticalSection( &cs_gethostbyname ); + return FALSE; + } + *sa_len = sizeof(struct sockaddr_in); + memset(sin,0,sizeof(struct sockaddr_in)); + memcpy((char *)&sin->sin_addr, phe->h_addr, phe->h_length); + sin->sin_family = phe->h_addrtype; + sin->sin_port = htons(nServerPort); LeaveCriticalSection( &cs_gethostbyname ); +#endif return TRUE; } @@ -224,7 +286,7 @@ static const char *get_callback_name(DWORD dwInternetStatus) { return "Unknown"; } -VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { @@ -244,11 +306,11 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, case INTERNET_STATUS_NAME_RESOLVED: case INTERNET_STATUS_CONNECTING_TO_SERVER: case INTERNET_STATUS_CONNECTED_TO_SERVER: - lpvNewInfo = WININET_strdup_AtoW(lpvStatusInfo); + lpvNewInfo = heap_strdupAtoW(lpvStatusInfo); break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdupW(lpvStatusInfo); + lpvNewInfo = heap_strdupW(lpvStatusInfo); break; } }else { @@ -262,7 +324,7 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, break; case INTERNET_STATUS_RESOLVING_NAME: case INTERNET_STATUS_REDIRECT: - lpvNewInfo = WININET_strdup_WtoA(lpvStatusInfo); + lpvNewInfo = heap_strdupWtoA(lpvStatusInfo); break; } } @@ -294,7 +356,7 @@ static void SendAsyncCallbackProc(WORKREQUEST *workRequest) HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo); } -VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext, +void SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInfo, DWORD dwStatusInfoLength) { diff --git a/reactos/dll/win32/wininet/wininet.rbuild b/reactos/dll/win32/wininet/wininet.rbuild index 4a83d0b0ac4..45b87b18665 100644 --- a/reactos/dll/win32/wininet/wininet.rbuild +++ b/reactos/dll/win32/wininet/wininet.rbuild @@ -22,6 +22,7 @@ secur32 crypt32 ws2_32 + pseh cookie.c dialogs.c ftp.c diff --git a/reactos/dll/win32/wininet/wininet.spec b/reactos/dll/win32/wininet/wininet.spec index dfbc38c02fc..46dd04334e6 100644 --- a/reactos/dll/win32/wininet/wininet.spec +++ b/reactos/dll/win32/wininet/wininet.spec @@ -1,5 +1,5 @@ 101 stub -noname DoConnectoidsExist -102 stub -noname GetDiskInfoA +102 stdcall -noname GetDiskInfoA(str ptr ptr ptr) 103 stub -noname PerformOperationOverUrlCacheA 104 stub -noname HttpCheckDavComplianceA 105 stub -noname HttpCheckDavComplianceW @@ -9,7 +9,7 @@ 111 stub -noname ExportCookieFileW 112 stub -noname IsProfilesEnabled 116 stub -noname IsDomainlegalCookieDomainA -117 stub -noname IsDomainLegalCookieDomainW +117 stdcall -noname IsDomainLegalCookieDomainW(wstr wstr) 118 stub -noname FindP3PPolicySymbol 120 stub -noname MapResourceToPolicy 121 stub -noname GetP3PPolicy @@ -50,8 +50,8 @@ @ stdcall FindNextUrlCacheGroup(long ptr ptr) @ stub ForceNexusLookup @ stub ForceNexusLookupExW -@ stub FreeUrlCacheSpaceA -@ stub FreeUrlCacheSpaceW +@ stdcall FreeUrlCacheSpaceA(str long long) +@ stdcall FreeUrlCacheSpaceW(wstr long long) @ stdcall FtpCommandA(long long long str ptr ptr) @ stdcall FtpCommandW(long long long wstr ptr ptr) @ stdcall FtpCreateDirectoryA(ptr str) @@ -109,7 +109,7 @@ @ stdcall HttpSendRequestExA(long ptr ptr long long) @ stdcall HttpSendRequestExW(long ptr ptr long long) @ stdcall HttpSendRequestW(ptr wstr long ptr long) -@ stub IncrementUrlCacheHeaderData +@ stdcall IncrementUrlCacheHeaderData(long ptr) @ stub InternetAlgIdToStringA @ stub InternetAlgIdToStringW @ stdcall InternetAttemptConnect(long) @@ -213,10 +213,10 @@ @ stdcall IsUrlCacheEntryExpiredW(wstr long ptr) @ stub LoadUrlCacheContent @ stub ParseX509EncodedCertificateForListBoxEntry -@ stub PrivacyGetZonePreferenceW # (long long ptr ptr ptr) -@ stub PrivacySetZonePreferenceW # (long long long wstr) +@ stdcall PrivacyGetZonePreferenceW(long long ptr ptr ptr) +@ stdcall PrivacySetZonePreferenceW(long long long wstr) @ stdcall ReadUrlCacheEntryStream(ptr long ptr ptr long) -@ stub RegisterUrlCacheNotification +@ stdcall RegisterUrlCacheNotification(ptr long long long long long) @ stdcall ResumeSuspendedDownload(long long) @ stdcall RetrieveUrlCacheEntryFileA(str ptr ptr long) @ stdcall RetrieveUrlCacheEntryFileW(wstr ptr ptr long) diff --git a/reactos/dll/win32/wininet/wininet_Bg.rc b/reactos/dll/win32/wininet/wininet_Bg.rc index 52d797ed751..b25356e074e 100644 --- a/reactos/dll/win32/wininet/wininet_Bg.rc +++ b/reactos/dll/win32/wininet/wininet_Bg.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Cs.rc b/reactos/dll/win32/wininet/wininet_Cs.rc index 9ca75397c4f..443c0175190 100644 --- a/reactos/dll/win32/wininet/wininet_Cs.rc +++ b/reactos/dll/win32/wininet/wininet_Cs.rc @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_CZECH, SUBLANG_DEFAULT /* Czech strings in CP1250 */ diff --git a/reactos/dll/win32/wininet/wininet_Da.rc b/reactos/dll/win32/wininet/wininet_Da.rc index 515dcabd8b3..6b37857ed54 100644 --- a/reactos/dll/win32/wininet/wininet_Da.rc +++ b/reactos/dll/win32/wininet/wininet_Da.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DANISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_De.rc b/reactos/dll/win32/wininet/wininet_De.rc index 9fb6be58c8d..f602a97a97d 100644 --- a/reactos/dll/win32/wininet/wininet_De.rc +++ b/reactos/dll/win32/wininet/wininet_De.rc @@ -1,5 +1,6 @@ /* * Copyright 2004 Henning Gerhardt + * Copyright 2009 André Hentschel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,8 +30,8 @@ FONT 8, "MS Shell Dlg" { LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Ben&utzername", -1, 40, 66, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Ben&utzer", -1, 40, 66, 50, 10 LTEXT "Kenn&wort", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -38,6 +43,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Benutzeranmeldung" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Geben Sie Benutzernamen und Kennwort ein:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Bereich", -1, 40, 46, 50, 10 + LTEXT "Benutzer", -1, 40, 66, 50, 10 + LTEXT "Kennwort", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Dieses &Kennwort speichern (unsicher)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Abbrechen", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbindung" diff --git a/reactos/dll/win32/wininet/wininet_En.rc b/reactos/dll/win32/wininet/wininet_En.rc index 66837dabc8e..d22d249f1cd 100644 --- a/reactos/dll/win32/wininet/wininet_En.rc +++ b/reactos/dll/win32/wininet/wininet_En.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -38,6 +40,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentication Required" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Please enter your username and password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "User", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Save this password (insecure)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancel", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Connection" diff --git a/reactos/dll/win32/wininet/wininet_Eo.rc b/reactos/dll/win32/wininet/wininet_Eo.rc index a145e263621..3fa19f37897 100644 --- a/reactos/dll/win32/wininet/wininet_Eo.rc +++ b/reactos/dll/win32/wininet/wininet_Eo.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Es.rc b/reactos/dll/win32/wininet/wininet_Es.rc index bbf08aeb2f6..c9ce2cebbe2 100644 --- a/reactos/dll/win32/wininet/wininet_Es.rc +++ b/reactos/dll/win32/wininet/wininet_Es.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Fi.rc b/reactos/dll/win32/wininet/wininet_Fi.rc index 176a00337ce..df5ca723044 100644 --- a/reactos/dll/win32/wininet/wininet_Fi.rc +++ b/reactos/dll/win32/wininet/wininet_Fi.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Fr.rc b/reactos/dll/win32/wininet/wininet_Fr.rc index 0435b8eb711..74ee208a7ee 100644 --- a/reactos/dll/win32/wininet/wininet_Fr.rc +++ b/reactos/dll/win32/wininet/wininet_Fr.rc @@ -3,8 +3,9 @@ * French language support * * Copyright 2003 Mike McCormack for CodeWeavers - * Copyright 2003 Vincent Béron + * Copyright 2003 Vincent Béron * Copyright 2005 Jonathan Ernst + * Copyright 2009 Frédéric Delanoy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,29 +22,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL -IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Entrez le mot de passe réseau" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur mandataire", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_PROXY, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 218, 150 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Entrez le mot de passe réseau" +CAPTION "Authentification requise" FONT 8, "MS Shell Dlg" { - LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 40, 6, 150, 15 - LTEXT "Mandataire", -1, 40, 26, 50, 10 - LTEXT "Domaine", -1, 40, 46, 50, 10 - LTEXT "Utilisateur", -1, 40, 66, 50, 10 - LTEXT "Mot de passe", -1, 40, 86, 50, 10 - LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 - LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 - EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP - EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, - 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP - PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "Annuler", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + LTEXT "Entrez votre nom d'utilisateur et votre mot de passe :", -1, 10, 8, 173, 12 + LTEXT "Serveur", -1, 10, 28, 50, 17 + LTEXT "Domaine", -1, 10, 50, 50, 10 + LTEXT "Utilisateur", -1, 10, 71, 50, 10 + LTEXT "Mot de passe", -1, 10, 90, 50, 10 + LTEXT "" IDC_SERVER, 58, 28, 150, 14, 0 + LTEXT "" IDC_REALM, 58, 48, 150, 14, 0 + EDITTEXT IDC_USERNAME, 58, 68, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 58, 88, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Enregistrer ce mot de passe (risqué)", IDC_SAVEPASSWORD, + 58, 108, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 87, 128, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuler", IDCANCEL, 147, 128, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Connexion LAN" + IDS_LANCONNECTION "Connexion réseau local (LAN)" } diff --git a/reactos/dll/win32/wininet/wininet_Hu.rc b/reactos/dll/win32/wininet/wininet_Hu.rc index c9704f9080b..b19e03dc007 100644 --- a/reactos/dll/win32/wininet/wininet_Hu.rc +++ b/reactos/dll/win32/wininet/wininet_Hu.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_It.rc b/reactos/dll/win32/wininet/wininet_It.rc index 45045460c33..04f71c5f177 100644 --- a/reactos/dll/win32/wininet/wininet_It.rc +++ b/reactos/dll/win32/wininet/wininet_It.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticazione richiesta" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Inserire il nome utente e la password:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Utente", -1, 40, 66, 50, 10 + LTEXT "Password", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Memorizza la password (RISCHIOSO)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annulla", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Connessione LAN" diff --git a/reactos/dll/win32/wininet/wininet_Ja.rc b/reactos/dll/win32/wininet/wininet_Ja.rc index 615d7be1c86..e179b849254 100644 --- a/reactos/dll/win32/wininet/wininet_Ja.rc +++ b/reactos/dll/win32/wininet/wininet_Ja.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* UTF-8 */ #pragma code_page(65001) @@ -45,5 +47,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN 接続" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Ko.rc b/reactos/dll/win32/wininet/wininet_Ko.rc index 26ed4a2fad2..5c2595a9b37 100644 --- a/reactos/dll/win32/wininet/wininet_Ko.rc +++ b/reactos/dll/win32/wininet/wininet_Ko.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Lt.rc b/reactos/dll/win32/wininet/wininet_Lt.rc new file mode 100644 index 00000000000..cd4bf482e35 --- /dev/null +++ b/reactos/dll/win32/wininet/wininet_Lt.rc @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Aurimas FiÅ¡eras + * + * 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 "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + +LANGUAGE LANG_LITHUANIAN, SUBLANG_NEUTRAL + +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Ä®veskite tinklo slaptažodį" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ä®veskite savo naudotojo vardą ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Ä®galiot. serv.", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Ä®&raÅ¡yti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Reikalingas tapatumo nustatymas" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ä®veskite savo naudotojo vardą ir slaptažodį:", -1, 40, 6, 150, 15 + LTEXT "Serveris", -1, 40, 26, 50, 10 + LTEXT "Sritis", -1, 40, 46, 50, 10 + LTEXT "Naudotojas", -1, 40, 66, 50, 10 + LTEXT "Slaptažodis", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Ä®&raÅ¡yti šį slaptažodį (nesaugu)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Gerai", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Atsisakyti", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +STRINGTABLE DISCARDABLE +{ + IDS_LANCONNECTION "Vietinio tinklo ryÅ¡ys" +} diff --git a/reactos/dll/win32/wininet/wininet_Nl.rc b/reactos/dll/win32/wininet/wininet_Nl.rc index 16c80ccaad8..f0e891c7e19 100644 --- a/reactos/dll/win32/wininet/wininet_Nl.rc +++ b/reactos/dll/win32/wininet/wininet_Nl.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -40,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authenticatie vereist" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Voer uw gebruikersnaam en wachtwoord in:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Gebruikersnaam", -1, 40, 66, 50, 10 + LTEXT "Wachtwoord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Wachtwoord opslaan (onveilig)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Annuleren", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN Verbinding" diff --git a/reactos/dll/win32/wininet/wininet_No.rc b/reactos/dll/win32/wininet/wininet_No.rc index fb885e9030d..1dfa544e4aa 100644 --- a/reactos/dll/win32/wininet/wininet_No.rc +++ b/reactos/dll/win32/wininet/wininet_No.rc @@ -1,5 +1,5 @@ /* - * Copyright 2005 Alexander N. Sørnes + * Copyright 2005-2009 Alexander N. Sørnes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +16,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -25,7 +29,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "Skriv inn brukernavnet og passordet ditt:", -1, 40, 6, 150, 15 LTEXT "Mellomtjener", -1, 40, 26, 50, 10 - LTEXT "Område", -1, 40, 46, 50, 10 + LTEXT "OmrÃ¥de", -1, 40, 46, 50, 10 LTEXT "Bruker", -1, 40, 66, 50, 10 LTEXT "Passord", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -38,6 +42,26 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "PÃ¥logging" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Oppgi brukernavn og passord:", -1, 40, 6, 150, 15 + LTEXT "Tjener", -1, 40, 26, 50, 10 + LTEXT "OmrÃ¥de", -1, 40, 46, 50, 10 + LTEXT "Bruker", -1, 40, 66, 50, 10 + LTEXT "Passord", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "Lagre pa&ssordet (sikkerhetsrisiko)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Avbryt", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Lokal nettverksforbindelse" diff --git a/reactos/dll/win32/wininet/wininet_Pl.rc b/reactos/dll/win32/wininet/wininet_Pl.rc index 7ddb399a584..0c76d5335aa 100644 --- a/reactos/dll/win32/wininet/wininet_Pl.rc +++ b/reactos/dll/win32/wininet/wininet_Pl.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_POLISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Pt.rc b/reactos/dll/win32/wininet/wininet_Pt.rc index 57dd625a740..95e06e6d6e8 100644 --- a/reactos/dll/win32/wininet/wininet_Pt.rc +++ b/reactos/dll/win32/wininet/wininet_Pt.rc @@ -1,6 +1,7 @@ /* * Copyright 2003 Marcelo Duarte - * Copyright 2006-2007 Américo José Melo + * Copyright 2006-2007 Américo José Melo + * Copyright 2009 Ricardo Filipe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +18,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +#pragma code_page(65001) + LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 @@ -24,10 +29,10 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Entrar Senha da Rede" FONT 8, "MS Shell Dlg" { - LTEXT "Por favor, entre com o nome de usuário e a senha:", -1, 40, 6, 150, 15 + LTEXT "Por favor, entre com o nome de usuário e a senha:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 LTEXT "Realm", -1, 40, 46, 50, 10 - LTEXT "Usuário", -1, 40, 66, 50, 10 + LTEXT "Usuário", -1, 40, 66, 50, 10 LTEXT "Senha", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 @@ -61,17 +66,36 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autenticação necessária" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Por favor insira o seu nome de utilizador e palavra-passe:", -1, 40, 6, 150, 15 + LTEXT "Servidor", -1, 40, 26, 50, 10 + LTEXT "Reino", -1, 40, 46, 50, 10 + LTEXT "Utilizador", -1, 40, 66, 50, 10 + LTEXT "Palavra-passe", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Guardar esta palavra-passe (inseguro)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Cancelar", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Conexão LAN" + IDS_LANCONNECTION "Conexão LAN" } LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Ligação LAN" + IDS_LANCONNECTION "Ligação LAN" } diff --git a/reactos/dll/win32/wininet/wininet_Ro.rc b/reactos/dll/win32/wininet/wininet_Ro.rc index 367bbb5955a..13403eec1a6 100644 --- a/reactos/dll/win32/wininet/wininet_Ro.rc +++ b/reactos/dll/win32/wininet/wininet_Ro.rc @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL #pragma code_page(65001) @@ -28,7 +30,7 @@ FONT 8, "MS Shell Dlg" { LTEXT "Introduceți numele de utilizator și parola:", -1, 40, 6, 150, 15 LTEXT "Proxy", -1, 40, 26, 50, 10 - LTEXT "Realm", -1, 40, 46, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 LTEXT "Utilizator", -1, 40, 66, 50, 10 LTEXT "Parolă", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 @@ -41,9 +43,27 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Autentificare necesară" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Introduceți numele de utilizator și parola:", -1, 40, 6, 150, 15 + LTEXT "Server", -1, 40, 26, 50, 10 + LTEXT "Domeniu", -1, 40, 46, 50, 10 + LTEXT "Utilizator", -1, 40, 66, 50, 10 + LTEXT "Parolă", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Salvează această parolă (nesigur)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Renunță", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "Conexiune LAN" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Ru.rc b/reactos/dll/win32/wininet/wininet_Ru.rc index d75985ba1b7..8d35fe40aab 100644 --- a/reactos/dll/win32/wininet/wininet_Ru.rc +++ b/reactos/dll/win32/wininet/wininet_Ru.rc @@ -18,29 +18,54 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + +/* UTF-8 */ +#pragma code_page(65001) + LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Ââîä ñåòåâîãî ïàðîëÿ" +CAPTION "Ввод сетевого пароля" FONT 8, "MS Shell Dlg" { - LTEXT "Ââåäèòå èìÿ ïîëüçîâàòåëÿ è ïàðîëü:", -1, 40, 6, 150, 15 - LTEXT "Ïðîêñè", -1, 40, 26, 50, 10 - LTEXT "Äîìåí", -1, 40, 46, 50, 10 - LTEXT "Ïîëüçîâàòåëü", -1, 40, 66, 50, 10 - LTEXT "Ïàðîëü", -1, 40, 86, 50, 10 + LTEXT "Введите имя пользователя и пароль:", -1, 40, 6, 150, 15 + LTEXT "Прокси", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD - CHECKBOX "&Ñîõðàíèòü ýòîò ïàðîëü (íåáåçîïàñíî)", IDC_SAVEPASSWORD, + CHECKBOX "&Сохранить этот пароль (небезопасно)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} + +IDD_AUTHDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Требуется идентификация" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Введите имя пользователя и пароль:", -1, 40, 6, 150, 15 + LTEXT "Сервер", -1, 40, 26, 50, 10 + LTEXT "Домен", -1, 40, 46, 50, 10 + LTEXT "Пользователь", -1, 40, 66, 50, 10 + LTEXT "Пароль", -1, 40, 86, 50, 10 + LTEXT "" IDC_SERVER, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Сохранить этот пароль (небезопасно)", IDC_SAVEPASSWORD, 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON - PUSHBUTTON "Îòìåíà", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP + PUSHBUTTON "Отмена", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP } STRINGTABLE DISCARDABLE { - IDS_LANCONNECTION "Ñåòåâîå ïîäêëþ÷åíèå" + IDS_LANCONNECTION "Сетевое подключение" } diff --git a/reactos/dll/win32/wininet/wininet_Si.rc b/reactos/dll/win32/wininet/wininet_Si.rc index 93ac9e1f33b..b5bf2914328 100644 --- a/reactos/dll/win32/wininet/wininet_Si.rc +++ b/reactos/dll/win32/wininet/wininet_Si.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + #pragma code_page(65001) LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT @@ -44,5 +46,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "LAN povezava" } - -#pragma code_page(default) diff --git a/reactos/dll/win32/wininet/wininet_Sv.rc b/reactos/dll/win32/wininet/wininet_Sv.rc index 6d71f2ef842..8d3291ec750 100644 --- a/reactos/dll/win32/wininet/wininet_Sv.rc +++ b/reactos/dll/win32/wininet/wininet_Sv.rc @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Tr.rc b/reactos/dll/win32/wininet/wininet_Tr.rc index dd796777236..8d26cf21694 100644 --- a/reactos/dll/win32/wininet/wininet_Tr.rc +++ b/reactos/dll/win32/wininet/wininet_Tr.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Uk.rc b/reactos/dll/win32/wininet/wininet_Uk.rc index be58bb621f2..94a9611888b 100644 --- a/reactos/dll/win32/wininet/wininet_Uk.rc +++ b/reactos/dll/win32/wininet/wininet_Uk.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 diff --git a/reactos/dll/win32/wininet/wininet_Zh.rc b/reactos/dll/win32/wininet/wininet_Zh.rc index 4406bd87c1a..e2e36ded277 100644 --- a/reactos/dll/win32/wininet/wininet_Zh.rc +++ b/reactos/dll/win32/wininet/wininet_Zh.rc @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "resource.h" + /* Chinese text is encoded in UTF-8 */ #pragma code_page(65001) @@ -74,5 +76,3 @@ STRINGTABLE DISCARDABLE { IDS_LANCONNECTION "局域網連接" } - -#pragma code_page(default) -- 2.17.1