diff --git a/reactos/dll/win32/wininet/cookie.c b/reactos/dll/win32/wininet/cookie.c index 12d841bc7b9..dc77b17265b 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,13 +87,14 @@ 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; + newCookie->expiry = expiry; if (name) { @@ -177,6 +181,7 @@ static cookie_domain *COOKIE_addDomain(LPCWSTR domain, LPCWSTR path) static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostNameLen, LPWSTR path, int pathLen) { URL_COMPONENTSW UrlComponents; + BOOL rc; UrlComponents.lpszExtraInfo = NULL; UrlComponents.lpszPassword = NULL; @@ -191,7 +196,22 @@ static BOOL COOKIE_crackUrlSimple(LPCWSTR lpszUrl, LPWSTR hostName, int hostName UrlComponents.dwHostNameLength = hostNameLen; UrlComponents.dwUrlPathLength = pathLen; - return InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents); + rc = InternetCrackUrlW(lpszUrl, 0, 0, &UrlComponents); + + /* discard the webpage off the end of the path */ + if (pathLen > 0 && path[pathLen-1] != '/') + { + LPWSTR ptr; + ptr = strrchrW(path,'/'); + if (ptr) + *(++ptr) = 0; + else + { + path[0] = '/'; + path[1] = 0; + } + } + return rc; } /* match a domain. domain must match if the domain is not NULL. path must match if the path is not NULL */ @@ -215,11 +235,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 +293,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 +308,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 +322,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; @@ -405,27 +447,116 @@ 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 = HeapAlloc(GetProcessHeap(), 0, (strlenW(cookie_data) + 1) * sizeof(WCHAR)); + strcpyW(data,cookie_data); + 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; + + value = HeapAlloc(GetProcessHeap(), 0, (ptr - data) * sizeof(WCHAR)); + 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; } @@ -475,7 +606,7 @@ BOOL WINAPI InternetSetCookieW(LPCWSTR lpszUrl, LPCWSTR lpszCookieName, * the cookie data in the form of name[=data]. */ if (!(data = strchrW(cookie, '='))) data = cookie + len; - else data++; + else *data++ = 0; ret = set_cookie(hostName, path, cookie, data); @@ -692,3 +823,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..41494a67509 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" diff --git a/reactos/dll/win32/wininet/ftp.c b/reactos/dll/win32/wininet/ftp.c index cb24782fa4b..db0bf569ebc 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 @@ -42,6 +46,9 @@ #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #include #include @@ -90,7 +97,7 @@ typedef struct BOOL bIsDirectory; LPWSTR lpszName; DWORD nSize; - struct tm tmLastModified; + SYSTEMTIME tmLastModified; unsigned short permissions; } FILEPROPERTIESW, *LPFILEPROPERTIESW; @@ -199,8 +206,6 @@ static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszC 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, BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, DWORD_PTR dwContext); @@ -854,13 +859,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)); @@ -1071,118 +1076,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) @@ -1199,8 +1092,6 @@ static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr) TRACE("\n"); - WININET_Release(&lpwh->lpFtpSession->hdr); - if (!lpwh->session_deleted) lpwfs->download_in_progress = NULL; @@ -1210,6 +1101,8 @@ 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); } @@ -1245,6 +1138,18 @@ static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size return res>=0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME*/ } +static DWORD FTPFILE_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *buffers, + DWORD flags, DWORD_PTR context) +{ + return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength); +} + +static DWORD FTPFILE_ReadFileExW(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSW *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) { LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr; @@ -1256,15 +1161,85 @@ static BOOL FTPFILE_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWOR return res >= 0; } +static void FTP_ReceiveRequestData(WININETFTPFILE *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) +{ + WININETFTPFILE *file = (WININETFTPFILE*)workRequest->hdr; + + FTP_ReceiveRequestData(file, FALSE); +} + +static DWORD FTPFILE_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) +{ + LPWININETFTPFILE file = (LPWININETFTPFILE) 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 = { FTPFILE_Destroy, NULL, FTPFILE_QueryOption, NULL, FTPFILE_ReadFile, - NULL, + FTPFILE_ReadFileExA, + FTPFILE_ReadFileExW, FTPFILE_WriteFile, - NULL, + FTPFILE_QueryDataAvailable, NULL }; @@ -1339,16 +1314,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 +1338,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 = 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; +} + + /*********************************************************************** * FtpGetFileA (WININET.@) * @@ -2256,7 +2348,7 @@ 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; @@ -2302,7 +2394,7 @@ 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); @@ -2336,7 +2428,7 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName, { INTERNET_ASYNC_RESULT iar; - iar.dwResult = (DWORD)handle; + iar.dwResult = (DWORD_PTR)handle; iar.dwError = ERROR_SUCCESS; SendAsyncCallback(&hIC->hdr, dwContext, @@ -2397,16 +2489,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; } @@ -2737,7 +2819,7 @@ 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) { @@ -3220,7 +3302,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; @@ -3308,6 +3390,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = { NULL, NULL, NULL, + NULL, FTPFINDNEXT_FindNextFileW }; @@ -3382,9 +3465,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 +3533,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,34 +3546,31 @@ 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; @@ -3505,32 +3583,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, "")) { diff --git a/reactos/dll/win32/wininet/http.c b/reactos/dll/win32/wininet/http.c index f0ad6beddc1..6e699ff3437 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 @@ -59,6 +63,7 @@ #include "internet.h" #include "wine/debug.h" +#include "wine/exception.h" #include "wine/unicode.h" #include "inet_ntop.c" @@ -76,6 +81,7 @@ static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u',' 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 szCrLf[] = {'\r','\n', 0}; #define MAXHOSTNAME 100 #define MAX_FIELD_VALUE_LEN 256 @@ -116,15 +122,15 @@ 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 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_HttpQueryInfoW(LPWININETHTTPREQW, DWORD, LPVOID, LPDWORD, LPDWORD); +static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl); static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, 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_FinishedReading(LPWININETHTTPREQW lpwhr); -LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) +static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) { int HeaderIndex = 0; HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE); @@ -134,6 +140,29 @@ LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head) return &req->pCustHeaders[HeaderIndex]; } +/* set the request content length based on the headers */ +static DWORD set_content_length( LPWININETHTTPREQW 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)) + lpwhr->dwContentLength = ~0u; + + size = sizeof(encoding); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) && + !strcmpiW(encoding, szChunked)) + { + lpwhr->dwContentLength = ~0u; + lpwhr->read_chunked = TRUE; + } + + return lpwhr->dwContentLength; +} + /*********************************************************************** * HTTP_Tokenize (internal) * @@ -146,21 +175,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)); @@ -258,7 +292,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 +312,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; @@ -313,82 +346,29 @@ static void HTTP_ProcessCookies( LPWININETHTTPREQW 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; + 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++; } } @@ -614,7 +594,7 @@ static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue, /*********************************************************************** * HTTP_HttpAddRequestHeadersW (internal) */ -static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, +static BOOL HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier) { LPWSTR lpszStart; @@ -656,6 +636,13 @@ static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr, lpszEnd += 2; /* Jump over \r\n */ } TRACE("interpreting header %s\n", debugstr_w(lpszStart)); + if (*lpszStart == '\0') + { + /* Skip 0-length headers */ + lpszStart = lpszEnd; + bSuccess = TRUE; + continue; + } pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart); if (pFieldAndValue) { @@ -760,57 +747,85 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext) { - LPINTERNET_BUFFERSA ptr; - LPINTERNET_BUFFERSW lpBuffersOutW,ptrW; - BOOL rc = FALSE; + TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext); - TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags, - dwContext); - - ptr = lpBuffersOut; - if (ptr) - lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW)); - else - lpBuffersOutW = NULL; - - ptrW = lpBuffersOutW; - while (ptr) + if (lpBuffersOut) { - 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; + INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } - rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext); + return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext); +} - if (lpBuffersOutW) +static BOOL HTTP_HttpEndRequestW(LPWININETHTTPREQW lpwhr, DWORD dwFlags, DWORD_PTR dwContext) +{ + BOOL rc = FALSE; + INT responseLen; + DWORD dwBufferSize; + INTERNET_ASYNC_RESULT iar; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE); + if (responseLen) + rc = TRUE; + + 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)) { - ptrW = lpBuffersOutW; - while (ptrW) + DWORD dwCode,dwCodeLength = sizeof(DWORD); + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) && + (dwCode == 302 || dwCode == 301 || dwCode == 303)) { - 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; + WCHAR *new_url, 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); + 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)); + rc = HTTP_HandleRedirect(lpwhr, new_url); + if (rc) + rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE); + HeapFree( GetProcessHeap(), 0, new_url ); + } + } } } + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = rc ? 0 : INTERNET_GetLastError(); + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); return rc; } +static void AsyncHttpEndRequestProc(WORKREQUEST *work) +{ + struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW; + LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)work->hdr; + + TRACE("%p\n", lpwhr); + + HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext); +} + /*********************************************************************** * HttpEndRequestW (WININET.@) * @@ -826,10 +841,15 @@ BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, { BOOL rc = FALSE; LPWININETHTTPREQW lpwhr; - INT responseLen; - DWORD dwBufferSize; TRACE("-->\n"); + + if (lpBuffersOut) + { + INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest ); if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) @@ -837,58 +857,27 @@ BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); if (lpwhr) WININET_Release( &lpwhr->hdr ); - return FALSE; + 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)) + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) { - 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); - } - } + 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); + INTERNET_SetLastError(ERROR_IO_PENDING); } + else + rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext); WININET_Release( &lpwhr->hdr ); TRACE("%i <--\n",rc); @@ -1017,12 +1006,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, types = lpszAcceptTypes; while (*types) { - /* find out how many there are */ - if (((ULONG_PTR)*types >> 16) && **types) + __TRY { - TRACE("accept type: %s\n", debugstr_a(*types)); - acceptTypesCount++; + /* find out how many there are */ + if (*types && **types) + { + TRACE("accept type: %s\n", debugstr_a(*types)); + acceptTypesCount++; + } } + __EXCEPT_PAGE_FAULT + { + WARN("invalid accept type pointer\n"); + } + __ENDTRY; types++; } szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1)); @@ -1032,20 +1029,26 @@ 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; + if (*types && **types) + { + len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 ); + szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len); - acceptTypesCount++; + MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len); + acceptTypesCount++; + } } + __EXCEPT_PAGE_FAULT + { + /* ignore invalid pointer */ + } + __ENDTRY; types++; } szAcceptTypes[acceptTypesCount] = NULL; } - else szAcceptTypes = 0; rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName, szVersion, szReferrer, @@ -1377,6 +1380,32 @@ static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr) WININET_Release(&lpwhr->lpHttpSession->hdr); + 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; + } + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb); HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders); @@ -1402,31 +1431,6 @@ static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr) 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); @@ -1598,29 +1602,224 @@ 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 = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + + case INTERNET_OPTION_PASSWORD: + HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword); + if (!(req->lpHttpSession->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY; + 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 */ +static BOOL read_more_data( WININETHTTPREQW *req, int maxlen ) { - int bytes_read; + int len; - 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); - - /* always return success, even if the network layer returns an error */ - *read = 0; - HTTP_FinishedReading(req); - return ERROR_SUCCESS; + if (req->read_size && req->read_pos) + { + /* move existing data to the start of the buffer */ + memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size ); + req->read_pos = 0; } + if (maxlen == -1) maxlen = sizeof(req->read_buf); + if (!NETCON_recv( &req->netConnection, req->read_buf + req->read_size, + maxlen - req->read_size, 0, &len )) return FALSE; + req->read_size += len; + return TRUE; +} + +/* remove some amount of data from the read buffer */ +static void remove_data( WININETHTTPREQW *req, int count ) +{ + if (!(req->read_size -= count)) req->read_pos = 0; + else req->read_pos += count; +} + +static BOOL read_line( WININETHTTPREQW *req, LPSTR buffer, DWORD *len ) +{ + int count, bytes_read, pos = 0; + + for (;;) + { + char *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size ); + + if (eol) + { + count = eol - (req->read_buf + req->read_pos); + bytes_read = count + 1; + } + else count = bytes_read = req->read_size; + + 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; + + if (!read_more_data( req, -1 )) return FALSE; + if (!req->read_size) + { + *len = 0; + TRACE( "returning empty string\n" ); + return FALSE; + } + } + + 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; +} + +/* discard data contents until we reach end of line */ +static BOOL discard_eol( WININETHTTPREQW *req ) +{ + do + { + char *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; + } + req->read_pos = req->read_size = 0; /* discard everything */ + if (!read_more_data( req, -1 )) return FALSE; + } while (req->read_size); + return TRUE; +} + +/* read the size of the next chunk */ +static BOOL start_next_chunk( WININETHTTPREQW *req ) +{ + DWORD chunk_size = 0; + + if (!req->dwContentLength) return TRUE; + if (req->dwContentLength == req->dwContentRead) + { + /* read terminator for the previous chunk */ + if (!discard_eol( req )) return FALSE; + 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') + { + TRACE( "reading %u byte chunk\n", chunk_size ); + req->dwContentLength = chunk_size; + req->dwContentRead = 0; + if (!discard_eol( req )) return FALSE; + return TRUE; + } + remove_data( req, 1 ); + } + if (!read_more_data( req, -1 )) return FALSE; + if (!req->read_size) + { + req->dwContentLength = req->dwContentRead = 0; + return TRUE; + } + } +} + +/* return the size of data available to be read immediately */ +static DWORD get_avail_data( WININETHTTPREQW *req ) +{ + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + return 0; + return min( req->read_size, req->dwContentLength - req->dwContentRead ); +} + +/* check if we have reached the end of the data to read */ +static BOOL end_of_read_data( WININETHTTPREQW *req ) +{ + if (req->read_chunked) return (req->dwContentLength == 0); + if (req->dwContentLength == ~0u) return FALSE; + return (req->dwContentLength == req->dwContentRead); +} + +static BOOL refill_buffer( WININETHTTPREQW *req ) +{ + int len = sizeof(req->read_buf); + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if (!start_next_chunk( req )) return FALSE; + } + + if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead ); + if (len <= req->read_size) return TRUE; + + if (!read_more_data( req, len )) return FALSE; + if (!req->read_size) req->dwContentLength = req->dwContentRead = 0; + return TRUE; +} + +static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif) +{ + INTERNET_ASYNC_RESULT iar; + + TRACE("%p\n", req); + + if (refill_buffer( req )) { + iar.dwResult = (DWORD_PTR)req->hdr.hInternet; + iar.dwError = first_notif ? 0 : get_avail_data(req); + }else { + iar.dwResult = 0; + iar.dwError = INTERNET_GetLastError(); + } + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) +{ + int len, bytes_read = 0; + + if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead)) + { + if (!start_next_chunk( req )) goto done; + } + 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)) + bytes_read += len; + /* always return success, even if the network layer returns an error */ + } +done: req->dwContentRead += bytes_read; *read = bytes_read; + TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength ); if(req->lpszCacheFile) { BOOL res; DWORD dwBytesWritten; @@ -1636,102 +1835,6 @@ static DWORD HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *re return ERROR_SUCCESS; } -static DWORD get_chunk_size(const char *buffer) -{ - 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; -} - -static DWORD HTTP_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - char reply[MAX_REPLY_LEN], *p = buffer; - DWORD buflen, to_read, to_write = size; - int bytes_read; - - *read = 0; - for (;;) - { - if (*read == size) break; - - if (req->dwContentLength == ~0UL) /* new chunk */ - { - 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; - } - } - to_read = min(to_write, req->dwContentLength - req->dwContentRead); - - 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); - - /* always return success, even if the network layer returns an error */ - *read = 0; - break; - } - if (!bytes_read) break; - - req->dwContentRead += bytes_read; - to_write -= bytes_read; - *read += bytes_read; - - if (req->lpszCacheFile) - { - DWORD dwBytesWritten; - - if (!WriteFile(req->hCacheFile, p, bytes_read, &dwBytesWritten, NULL)) - WARN("WriteFile failed: %u\n", GetLastError()); - } - p += bytes_read; - - if (req->dwContentRead == req->dwContentLength) /* chunk complete */ - { - req->dwContentRead = 0; - req->dwContentLength = ~0UL; - - buflen = sizeof(reply); - if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) - { - ERR("Malformed chunk\n"); - *read = 0; - break; - } - } - } - if (!*read) HTTP_FinishedReading(req); - return ERROR_SUCCESS; -} - -static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync) -{ - WCHAR encoding[20]; - DWORD buflen = sizeof(encoding); - static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0}; - - if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) && - !strcmpiW(encoding, szChunked)) - { - return HTTP_ReadChunked(req, buffer, size, read, sync); - } - else - return HTTP_Read(req, buffer, size, read, sync); -} static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read) { @@ -1739,7 +1842,7 @@ static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size 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; @@ -1774,22 +1877,77 @@ 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) - { - WORKREQUEST workRequest; + workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc; + workRequest.hdr = WININET_AddRef(&req->hdr); + workRequest.u.InternetReadFileExA.lpBuffersOut = buffers; - workRequest.asyncproc = HTTPREQ_AsyncReadFileExProc; - 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)); + + 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 void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest) +{ + struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW; + WININETHTTPREQW *req = (WININETHTTPREQW*)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; + + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); +} + +static DWORD HTTPREQ_ReadFileExW(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSW *buffers, + DWORD flags, DWORD_PTR context) +{ + + WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; + DWORD res; + + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); + + 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) && !get_avail_data(req)) + { + WORKREQUEST workRequest; + + 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, @@ -1806,58 +1964,62 @@ static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *bu static BOOL HTTPREQ_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written) { + BOOL ret; LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)hdr; - return NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written); + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); + + *written = 0; + if ((ret = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written))) + lpwhr->dwBytesWritten += *written; + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD)); + return ret; } static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest) { WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr; - INTERNET_ASYNC_RESULT iar; - char buffer[4048]; - TRACE("%p\n", workRequest->hdr); - - iar.dwResult = NETCON_recv(&req->netConnection, buffer, - min(sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)&iar.dwError); - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + HTTP_ReceiveRequestData(req, FALSE); } static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) { WININETHTTPREQW *req = (WININETHTTPREQW*)hdr; - BYTE buffer[4048]; - BOOL async; TRACE("(%p %p %x %lx)\n", req, available, flags, ctx); - if(!NETCON_query_data_available(&req->netConnection, available) || *available) - return ERROR_SUCCESS; - - /* 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; - - if (NETCON_recv(&req->netConnection, buffer, - min(async ? 1 : sizeof(buffer), req->dwContentLength - req->dwContentRead), - MSG_PEEK, (int *)available) && async && *available) + if (!(*available = get_avail_data( req ))) { - WORKREQUEST workRequest; + if (end_of_read_data( req )) return ERROR_SUCCESS; - *available = 0; - workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; - workRequest.hdr = WININET_AddRef( &req->hdr ); + if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + WORKREQUEST workRequest; - INTERNET_AsyncCall(&workRequest); + workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc; + workRequest.hdr = WININET_AddRef( &req->hdr ); - return ERROR_IO_PENDING; + INTERNET_AsyncCall(&workRequest); + + return ERROR_IO_PENDING; + } + else + { + refill_buffer( req ); + *available = get_avail_data( req ); + } } + if (*available == sizeof(req->read_buf)) /* 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 ); + } + + TRACE( "returning %u\n", *available ); return ERROR_SUCCESS; } @@ -1868,6 +2030,7 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = { HTTPREQ_SetOption, HTTPREQ_ReadFile, HTTPREQ_ReadFileExA, + HTTPREQ_ReadFileExW, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, NULL @@ -1913,6 +2076,7 @@ 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; WININET_AddRef( &lpwhs->hdr ); lpwhr->lpHttpSession = lpwhs; @@ -1950,7 +2114,7 @@ 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); @@ -2027,12 +2191,15 @@ static void HTTP_DrainContent(WININETHTTPREQW *req) if (!NETCON_connected(&req->netConnection)) return; if (req->dwContentLength == -1) + { NETCON_close(&req->netConnection); + return; + } do { char buffer[2048]; - if (HTTP_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) + if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS) return; } while (bytes_read); } @@ -2169,27 +2336,28 @@ static const LPCWSTR header_lookup[] = { /*********************************************************************** * HTTP_HttpQueryInfoW (internal) */ -static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLevel, +static BOOL HTTP_HttpQueryInfoW( LPWININETHTTPREQW 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 FALSE; index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only); break; case HTTP_QUERY_RAW_HEADERS_CRLF: { LPWSTR headers; - DWORD len; + DWORD len = 0; BOOL ret = FALSE; if (request_only) @@ -2197,15 +2365,24 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev 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) { + len += sizeof(WCHAR); INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); ret = FALSE; } 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; } @@ -2217,10 +2394,9 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev } 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; @@ -2232,17 +2408,17 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } - - 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); @@ -2258,11 +2434,12 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } - memcpy(lpBuffer, lpwhr->lpszStatusText, (len+1)*sizeof(WCHAR)); + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); + } *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - return TRUE; } break; @@ -2276,18 +2453,19 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } - memcpy(lpBuffer, lpwhr->lpszVersion, (len+1)*sizeof(WCHAR)); + if (lpBuffer) + { + memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR)); + TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len)); + } *lpdwBufferLength = len * sizeof(WCHAR); - - TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len)); - return TRUE; } 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); } @@ -2304,18 +2482,16 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev return bSuccess; } - 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); + *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue); + TRACE(" returning number: %d\n", *(int *)lpBuffer); + bSuccess = TRUE; } - else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME) + else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) { time_t tmpTime; struct tm tmpTM; @@ -2324,24 +2500,20 @@ 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; + 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; + bSuccess = TRUE; - 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); + 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) { @@ -2353,12 +2525,13 @@ static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD dwInfoLev INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER); return bSuccess; } - - memcpy(lpBuffer, lphttpHdr->lpszValue, len); + if (lpBuffer) + { + memcpy(lpBuffer, lphttpHdr->lpszValue, len); + TRACE(" returning string: %s\n", debugstr_w(lpBuffer)); + } *lpdwBufferLength = len - sizeof(WCHAR); bSuccess = TRUE; - - TRACE(" returning string : %s\n", debugstr_w(lpBuffer)); } return bSuccess; } @@ -2778,8 +2951,13 @@ BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders, req = &workRequest.u.HttpSendRequestW; if (lpszHeaders) { - req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR)); - memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR)); + DWORD size; + + if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR); + else size = dwHeaderLength * sizeof(WCHAR); + + req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(req->lpszHeader, lpszHeaders, size); } else req->lpszHeader = 0; @@ -2849,13 +3027,75 @@ static BOOL HTTP_GetRequestURL(WININETHTTPREQW *req, LPWSTR buf) return TRUE; } +/*********************************************************************** + * HTTP_GetRedirectURL (internal) + */ +static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) +{ + static WCHAR szHttp[] = {'h','t','t','p',0}; + static WCHAR szHttps[] = {'h','t','t','p','s',0}; + LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession; + URL_COMPONENTSW urlComponents; + DWORD url_length = 0; + LPWSTR orig_url; + LPWSTR combined_url; + + if (lpszUrl[0]=='/') return WININET_strdupW( lpszUrl ); + + 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; + + 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 NULL; + } + + 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)); + + 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; +} + + /*********************************************************************** * 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]; @@ -2873,55 +3113,6 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) 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; @@ -2940,13 +3131,8 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) urlComponents.dwUrlPathLength = 2048; urlComponents.lpszExtraInfo = NULL; urlComponents.dwExtraInfoLength = 0; - if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents)) - { - HeapFree(GetProcessHeap(), 0, combined_url); + if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) return FALSE; - } - - HeapFree(GetProcessHeap(), 0, combined_url); if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) && (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) @@ -3020,6 +3206,8 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl) NETCON_close(&lpwhr->netConnection); if (!HTTP_ResolveName(lpwhr)) return FALSE; if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE; + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; } } else @@ -3039,7 +3227,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,10 +3235,10 @@ 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); @@ -3124,29 +3312,28 @@ static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr) static void HTTP_InsertCookies(LPWININETHTTPREQW 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); - 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); } } @@ -3168,7 +3355,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, DWORD dwContentLength, BOOL bEndRequest) { INT cnt; - BOOL bSuccess = FALSE; + BOOL bSuccess = FALSE, redirected = FALSE; LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; @@ -3186,10 +3373,11 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (!lpwhr->lpszVerb) lpwhr->lpszVerb = WININET_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) { @@ -3269,7 +3457,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, 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 ); @@ -3288,6 +3476,8 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, 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,8 +3486,6 @@ 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); @@ -3315,22 +3503,7 @@ 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, @@ -3339,21 +3512,29 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders, if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess) { - 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)) { + /* 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); - 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)); + bSuccess = HTTP_HandleRedirect(lpwhr, new_url); + if (bSuccess) + { + HeapFree(GetProcessHeap(), 0, requestString); + loop_next = TRUE; + } + HeapFree( GetProcessHeap(), 0, new_url ); } + redirected = TRUE; } } if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess) @@ -3429,12 +3610,31 @@ lend: /* TODO: send notification for P3P header */ - iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; - iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); + if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) + { + if (bSuccess) + { + if (lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) HTTP_ReceiveRequestData(lpwhr, TRUE); + else + { + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = 0; - INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, - INTERNET_STATUS_REQUEST_COMPLETE, &iar, - sizeof(INTERNET_ASYNC_RESULT)); + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + } + } + else + { + iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet; + iar.dwError = INTERNET_GetLastError(); + + INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_COMPLETE, &iar, + sizeof(INTERNET_ASYNC_RESULT)); + } + } TRACE("<--\n"); if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS); @@ -3479,11 +3679,34 @@ static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi return INET_QueryOption(option, buffer, size, unicode); } +static DWORD HTTPSESSION_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size) +{ + WININETHTTPSESSIONW *ses = (WININETHTTPSESSIONW*)hdr; + + switch(option) { + case INTERNET_OPTION_USERNAME: + { + HeapFree(GetProcessHeap(), 0, ses->lpszUserName); + if (!(ses->lpszUserName = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_PASSWORD: + { + HeapFree(GetProcessHeap(), 0, ses->lpszPassword); + if (!(ses->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + default: break; + } + + return ERROR_INTERNET_INVALID_OPTION; +} + static const HANDLEHEADERVtbl HTTPSESSIONVtbl = { HTTPSESSION_Destroy, NULL, HTTPSESSION_QueryOption, - NULL, + HTTPSESSION_SetOption, NULL, NULL, NULL, @@ -3611,7 +3834,7 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) TRACE("-->\n"); - if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) + if (lpwhr->hdr.htype != WH_HHTTPREQ) { INTERNET_SetLastError(ERROR_INVALID_PARAMETER); goto lend; @@ -3670,6 +3893,9 @@ static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr) bSuccess = TRUE; lend: + lpwhr->read_pos = lpwhr->read_size = 0; + lpwhr->read_chunked = FALSE; + TRACE("%d <--\n", bSuccess); return bSuccess; } @@ -3714,7 +3940,6 @@ static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear) 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; @@ -3731,18 +3956,13 @@ 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); - /* * 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 ); /* split the version from the status code */ @@ -3792,11 +4012,18 @@ 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; + if (!strchr(bufferA, ':')) + { + WARN("invalid header\n"); + continue; + } MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) @@ -4051,7 +4278,7 @@ 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(LPWININETHTTPREQW lpwhr) { WCHAR szVersion[10]; WCHAR szConnectionResponse[20]; @@ -4062,9 +4289,9 @@ BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr) /* 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)) + if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, + &dwBufferSize, NULL) && + !strcmpiW(szVersion, g_szHttp1_1)) { keepalive = TRUE; } diff --git a/reactos/dll/win32/wininet/internet.c b/reactos/dll/win32/wininet/internet.c index bad795ddbd4..aa2a6b720f0 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 @@ -113,7 +117,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 +127,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; @@ -182,7 +186,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, @@ -410,8 +415,11 @@ static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai ) TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy)); enabled = 1; } - if (!enabled) TRACE("Proxy is not enabled.\n"); - + if (!enabled) + { + TRACE("Proxy is not enabled.\n"); + lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT; + } RegCloseKey( key ); return (enabled > 0); } @@ -459,8 +467,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); @@ -543,8 +551,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 +584,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); @@ -779,7 +791,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 +828,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 +868,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 +912,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); @@ -1813,8 +1825,8 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA( INTERNET_STATUS_CALLBACK retVal; LPWININETHANDLEHEADER lpwh; - TRACE("0x%08x\n", (ULONG)hInternet); - + TRACE("%p\n", hInternet); + if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1841,7 +1853,7 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW( INTERNET_STATUS_CALLBACK retVal; LPWININETHANDLEHEADER lpwh; - TRACE("0x%08x\n", (ULONG)hInternet); + TRACE("%p\n", hInternet); if (!(lpwh = WININET_GetObject(hInternet))) return INTERNET_INVALID_STATUS_CALLBACK; @@ -1994,33 +2006,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); + LPWININETHANDLEHEADER hdr; + DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE; - INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + 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; + } + + 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 +2066,11 @@ 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; @@ -2133,8 +2155,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: @@ -2256,9 +2277,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) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + WININET_Release(lpwhh); + INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE); + return FALSE; } case INTERNET_OPTION_HTTP_VERSION: { @@ -2342,8 +2368,35 @@ 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"); + INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_COOKIES_3RD_PARTY: + FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n"); + INTERNET_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"); + INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_PATH: + FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n"); + INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_CODEPAGE_EXTRA: + FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n"); + INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; + break; + case INTERNET_OPTION_IDN: + FIXME("INTERNET_OPTION_IDN; STUB\n"); + INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION); + ret = FALSE; break; default: FIXME("Option %d STUB\n",dwOption); @@ -2381,12 +2434,15 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_CALLBACK: { LPWININETHANDLEHEADER lpwh; - INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer; - 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: { @@ -2475,6 +2531,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 +2560,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 (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR)) + 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; + } sprintfW( string, date, WININET_wkday[time->wDayOfWeek], @@ -2805,6 +2880,8 @@ 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); @@ -3010,7 +3087,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 +3108,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); @@ -3104,7 +3181,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"); @@ -3451,6 +3528,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; } @@ -3699,7 +3779,6 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags, } } - if (lpUrlComponents->lpszUrlPath) { dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath); @@ -3707,6 +3786,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 +3818,25 @@ DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR s return ERROR_SUCCESS; } +/*********************************************************************** + * 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) ); + return 0; +} + +/*********************************************************************** + * PrivacyGetZonePreferenceW (WININET.@) + */ +DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template, + LPWSTR preference, LPDWORD length ) +{ + FIXME( "%x %x: stub\n", zone, type ); + 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..48271d650ec 100644 --- a/reactos/dll/win32/wininet/internet.h +++ b/reactos/dll/win32/wininet/internet.h @@ -42,29 +42,17 @@ # 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__ */ -/* ReactOS-specific definitions */ -#undef CP_UNIXCP -#define CP_UNIXCP CP_THREAD_ACP - /* used for netconnection.c stuff */ 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 ) @@ -133,6 +121,7 @@ typedef struct { DWORD (*SetOption)(WININETHANDLEHEADER*,DWORD,void*,DWORD); DWORD (*ReadFile)(WININETHANDLEHEADER*,void*,DWORD,DWORD*); DWORD (*ReadFileExA)(WININETHANDLEHEADER*,INTERNET_BUFFERSA*,DWORD,DWORD_PTR); + DWORD (*ReadFileExW)(WININETHANDLEHEADER*,INTERNET_BUFFERSW*,DWORD,DWORD_PTR); BOOL (*WriteFile)(WININETHANDLEHEADER*,const void*,DWORD,DWORD*); DWORD (*QueryDataAvailable)(WININETHANDLEHEADER*,DWORD*,DWORD,DWORD_PTR); DWORD (*FindNextFileW)(WININETHANDLEHEADER*,void*); @@ -206,12 +195,18 @@ typedef struct 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; + 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 */ + char read_buf[4096]; /* buffer for already read but not returned data */ } WININETHTTPREQW, *LPWININETHTTPREQW; @@ -297,6 +292,12 @@ struct WORKREQ_HTTPSENDREQUESTW BOOL bEndRequest; }; +struct WORKREQ_HTTPENDREQUESTW +{ + DWORD dwFlags; + DWORD_PTR dwContext; +}; + struct WORKREQ_SENDCALLBACK { DWORD_PTR dwContext; @@ -320,6 +321,11 @@ struct WORKREQ_INTERNETREADFILEEXA LPINTERNET_BUFFERSA lpBuffersOut; }; +struct WORKREQ_INTERNETREADFILEEXW +{ + LPINTERNET_BUFFERSW lpBuffersOut; +}; + typedef struct WORKREQ { void (*asyncproc)(struct WORKREQ*); @@ -338,9 +344,11 @@ 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; @@ -381,7 +389,6 @@ 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, DWORD dwInternetStatus, LPVOID lpvStatusInfo, @@ -391,8 +398,6 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER 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, @@ -406,7 +411,6 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, BOOL 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); diff --git a/reactos/dll/win32/wininet/netconnection.c b/reactos/dll/win32/wininet/netconnection.c index 5d8b4d75534..d0d6f8e1dd2 100644 --- a/reactos/dll/win32/wininet/netconnection.c +++ b/reactos/dll/win32/wininet/netconnection.c @@ -23,6 +23,10 @@ #include "config.h" #include "wine/port.h" +#if defined(__MINGW32__) || defined (_MSC_VER) +#include +#endif + #include #ifdef HAVE_POLL_H #include @@ -33,10 +37,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 +61,6 @@ #undef FAR #undef DSA #endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif #include #include @@ -115,17 +118,18 @@ MAKE_FUNCPTR(SSL_connect); MAKE_FUNCPTR(SSL_shutdown); MAKE_FUNCPTR(SSL_write); MAKE_FUNCPTR(SSL_read); +MAKE_FUNCPTR(SSL_pending); 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); /* OpenSSL's libcrypto functions that we use */ MAKE_FUNCPTR(BIO_new_fp); MAKE_FUNCPTR(ERR_get_error); MAKE_FUNCPTR(ERR_error_string); +MAKE_FUNCPTR(i2d_X509); #undef MAKE_FUNCPTR #endif @@ -178,12 +182,12 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) DYNSSL(SSL_shutdown); DYNSSL(SSL_write); DYNSSL(SSL_read); + DYNSSL(SSL_pending); 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); #undef DYNSSL #define DYNCRYPTO(x) \ @@ -197,6 +201,7 @@ BOOL NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) DYNCRYPTO(BIO_new_fp); DYNCRYPTO(ERR_get_error); DYNCRYPTO(ERR_error_string); + DYNCRYPTO(i2d_X509); #undef DYNCRYPTO pSSL_library_init(); @@ -204,8 +209,6 @@ 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; #else FIXME("can't use SSL, not compiled in.\n"); INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); @@ -326,11 +329,6 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection) #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; @@ -538,55 +536,8 @@ BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int f 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 || !len; #else return FALSE; #endif @@ -604,13 +555,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,115 +565,17 @@ 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 @@ -788,7 +637,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/urlcache.c b/reactos/dll/win32/wininet/urlcache.c index b4feba3260c..f385c7e81cb 100644 --- a/reactos/dll/win32/wininet/urlcache.c +++ b/reactos/dll/win32/wininet/urlcache.c @@ -692,6 +692,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) @@ -3623,10 +3624,26 @@ BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLa /*********************************************************************** * GetDiskInfoA (WININET.@) */ -DWORD WINAPI GetDiskInfoA(void *p0, void *p1, void *p2, void *p3) +BOOL WINAPI GetDiskInfoA(PCSTR path, PDWORD cluster_size, PDWORDLONG free, PDWORDLONG total) { - FIXME("(%p, %p, %p, %p)\n", p0, p1, p2, p3); - return 0; + 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 +3654,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..b68cf8d4a57 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) @@ -142,7 +150,12 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort, WCHAR *found; char *name; int len, sz; +#ifdef HAVE_GETADDRINFO + struct addrinfo *res, hints; + int ret; +#else struct hostent *phe; +#endif TRACE("%s\n", debugstr_w(lpszServerName)); @@ -158,27 +171,45 @@ 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) ); + hints.ai_family = AF_INET; + + ret = getaddrinfo( name, NULL, &hints, &res ); + HeapFree( GetProcessHeap(), 0, name ); + if (ret != 0) + { + TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret)); + return FALSE; + } + memset( psa, 0, sizeof(struct sockaddr_in) ); + memcpy( &psa->sin_addr, &((struct sockaddr_in *)res->ai_addr)->sin_addr, sizeof(struct in_addr) ); + psa->sin_family = res->ai_family; + psa->sin_port = htons(nServerPort); + + 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); LeaveCriticalSection( &cs_gethostbyname ); +#endif return TRUE; } diff --git a/reactos/dll/win32/wininet/wininet.rbuild b/reactos/dll/win32/wininet/wininet.rbuild index cf0064396ea..e2a96c941f1 100644 --- a/reactos/dll/win32/wininet/wininet.rbuild +++ b/reactos/dll/win32/wininet/wininet.rbuild @@ -18,6 +18,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..d5995eb3cc3 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 @@ -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)