From 852c7ae40417ee0ef33242c63bfcc29b10cb522f Mon Sep 17 00:00:00 2001 From: David Hammerton Date: Fri, 20 Jun 2003 23:26:56 +0000 Subject: [PATCH] - implemented support for https protocol - fixes to the http protocol --- configure | 133 ++++++++- configure.ac | 4 +- dlls/wininet/Makefile.in | 2 + dlls/wininet/cookie.c | 490 +++++++++++++++++++++++++++++++ dlls/wininet/http.c | 545 +++++++++++++++++++++++++---------- dlls/wininet/internet.c | 242 ++++++---------- dlls/wininet/internet.h | 29 +- dlls/wininet/netconnection.c | 490 +++++++++++++++++++++++++++++++ include/config.h.in | 9 + 9 files changed, 1646 insertions(+), 298 deletions(-) create mode 100644 dlls/wininet/cookie.c create mode 100644 dlls/wininet/netconnection.c diff --git a/configure b/configure index 3408e1acc63..01f894b1752 100755 --- a/configure +++ b/configure @@ -6672,7 +6672,6 @@ done - XFILES="" OPENGLFILES="" @@ -12848,6 +12847,136 @@ cat >>confdefs.h <<_ACEOF #define SONAME_LIBJACK "$ac_cv_lib_soname_jack" _ACEOF fi + +echo "$as_me:$LINENO: checking for -lssl soname" >&5 +echo $ECHO_N "checking for -lssl soname... $ECHO_C" >&6 +if test "${ac_cv_lib_soname_ssl+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_get_soname_save_LIBS=$LIBS +LIBS="-lssl $LIBS" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char SSL_library_init (); +int +main () +{ +SSL_library_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_soname_ssl=`$ac_cv_path_LDD conftest$ac_exeext | grep libssl\\.so | sed 's/^[ ]*\([^ ]*\)[ ]*=>.*$/\1/'` + if test "x$ac_cv_lib_soname_ssl" = "x" + then + ac_cv_lib_soname_ssl="libssl.so" + fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_soname_ssl="libssl.so" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_get_soname_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_soname_ssl" >&5 +echo "${ECHO_T}$ac_cv_lib_soname_ssl" >&6 +if test "x$ac_cv_lib_soname_ssl" != xNONE +then +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBSSL "$ac_cv_lib_soname_ssl" +_ACEOF +fi + +echo "$as_me:$LINENO: checking for -lcrypto soname" >&5 +echo $ECHO_N "checking for -lcrypto soname... $ECHO_C" >&6 +if test "${ac_cv_lib_soname_crypto+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_get_soname_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char BIO_new_socket (); +int +main () +{ +BIO_new_socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_soname_crypto=`$ac_cv_path_LDD conftest$ac_exeext | grep libcrypto\\.so | sed 's/^[ ]*\([^ ]*\)[ ]*=>.*$/\1/'` + if test "x$ac_cv_lib_soname_crypto" = "x" + then + ac_cv_lib_soname_crypto="libcrypto.so" + fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_soname_crypto="libcrypto.so" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_get_soname_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_soname_crypto" >&5 +echo "${ECHO_T}$ac_cv_lib_soname_crypto" >&6 +if test "x$ac_cv_lib_soname_crypto" != xNONE +then +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBCRYPTO "$ac_cv_lib_soname_crypto" +_ACEOF +fi fi @@ -13443,6 +13572,7 @@ done + for ac_header in \ @@ -13473,6 +13603,7 @@ for ac_header in \ netinet/in_systm.h \ netinet/tcp.h \ netinet/tcp_fsm.h \ + openssl/ssl.h \ pty.h \ pwd.h \ regex.h \ diff --git a/configure.ac b/configure.ac index 2b832dda1d3..acb949bf969 100644 --- a/configure.ac +++ b/configure.ac @@ -161,7 +161,6 @@ AC_CHECK_HEADERS(gif_lib.h, [AC_DEFINE(HAVE_LIBGIF,1) GIFLIB="-lgif"])])) - AC_SUBST(XLIB) AC_SUBST(XFILES) XFILES="" @@ -910,6 +909,8 @@ then WINE_GET_SONAME(GL,glXQueryExtension,[$X_LIBS $X_EXTRA_LIBS]) WINE_GET_SONAME(cups,cupsGetDefault) WINE_GET_SONAME(jack,jack_client_new) + WINE_GET_SONAME(ssl,SSL_library_init) + WINE_GET_SONAME(crypto,BIO_new_socket) fi @@ -1004,6 +1005,7 @@ AC_CHECK_HEADERS(\ netinet/in_systm.h \ netinet/tcp.h \ netinet/tcp_fsm.h \ + openssl/ssl.h \ pty.h \ pwd.h \ regex.h \ diff --git a/dlls/wininet/Makefile.in b/dlls/wininet/Makefile.in index 5ac21e3acf0..ec64f11c4fd 100644 --- a/dlls/wininet/Makefile.in +++ b/dlls/wininet/Makefile.in @@ -11,9 +11,11 @@ LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ + cookie.c \ ftp.c \ http.c \ internet.c \ + netconnection.c \ urlcache.c \ utility.c \ wininet_main.c diff --git a/dlls/wininet/cookie.c b/dlls/wininet/cookie.c new file mode 100644 index 00000000000..d2c0f1d62bf --- /dev/null +++ b/dlls/wininet/cookie.c @@ -0,0 +1,490 @@ +/* + * Wininet - cookie handling stuff + * + * Copyright 2002 TransGaming Technologies Inc. + * + * David Hammerton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wininet.h" +#include "winerror.h" + +#include "wine/debug.h" +#include "internet.h" + +#define RESPONSE_TIMEOUT 30 /* FROM internet.c */ + + +WINE_DEFAULT_DEBUG_CHANNEL(wininet); + +/* FIXME + * Cookies are currently memory only. + * Cookies are NOT THREAD SAFE + * Cookies could use ALOT OF MEMORY. We need some kind of memory management here! + * Cookies should care about the expiry time + */ + +typedef struct _cookie_domain cookie_domain; +typedef struct _cookie cookie; + +struct _cookie +{ + struct _cookie *next; + struct _cookie *prev; + + struct _cookie_domain *parent; + + LPSTR lpCookieName; + LPSTR lpCookieData; + time_t expiry; /* FIXME: not used */ +}; + +struct _cookie_domain +{ + struct _cookie_domain *next; + struct _cookie_domain *prev; + + LPSTR lpCookieDomain; + LPSTR lpCookiePath; + cookie *cookie_tail; +}; + +static cookie_domain *cookieDomainTail; + +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCSTR name, LPCSTR data); +static cookie *COOKIE_findCookie(cookie_domain *domain, LPCSTR lpszCookieName); +static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain); +static cookie_domain *COOKIE_addDomain(LPCSTR domain, LPCSTR path); +static cookie_domain *COOKIE_addDomainFromUrl(LPCSTR lpszUrl); +static cookie_domain *COOKIE_findNextDomain(LPCSTR lpszCookieDomain, LPCSTR lpszCookiePath, + cookie_domain *prev_domain, BOOL allow_partial); +static cookie_domain *COOKIE_findNextDomainFromUrl(LPCSTR lpszUrl, cookie_domain *prev_domain, + BOOL allow_partial); +static void COOKIE_deleteDomain(cookie_domain *deadDomain); + + +/* adds a cookie to the domain */ +static cookie *COOKIE_addCookie(cookie_domain *domain, LPCSTR name, LPCSTR data) +{ + cookie *newCookie = HeapAlloc(GetProcessHeap(), 0, sizeof(cookie)); + + newCookie->next = NULL; + newCookie->prev = NULL; + newCookie->lpCookieName = NULL; + newCookie->lpCookieData = NULL; + + if (name) + { + newCookie->lpCookieName = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1); + strcpy(newCookie->lpCookieName, name); + } + if (data) + { + newCookie->lpCookieData = HeapAlloc(GetProcessHeap(), 0, strlen(data) + 1); + strcpy(newCookie->lpCookieData, data); + } + + TRACE("added cookie %p (data is %s)\n", newCookie, data); + + newCookie->prev = domain->cookie_tail; + newCookie->parent = domain; + domain->cookie_tail = newCookie; + return newCookie; +} + + +/* finds a cookie in the domain matching the cookie name */ +static cookie *COOKIE_findCookie(cookie_domain *domain, LPCSTR lpszCookieName) +{ + cookie *searchCookie = domain->cookie_tail; + TRACE("(%p, %s)\n", domain, debugstr_a(lpszCookieName)); + + while (searchCookie) + { + BOOL candidate = TRUE; + if (candidate && lpszCookieName) + { + if (candidate && !searchCookie->lpCookieName) + candidate = FALSE; + if (candidate && strcmp(lpszCookieName, searchCookie->lpCookieName) != 0) + candidate = FALSE; + } + if (candidate) + return searchCookie; + searchCookie = searchCookie->prev; + } + return NULL; +} + +/* removes a cookie from the list, if its the last cookie we also remove the domain */ +static void COOKIE_deleteCookie(cookie *deadCookie, BOOL deleteDomain) +{ + if (deadCookie->lpCookieName) + HeapFree(GetProcessHeap(), 0, deadCookie->lpCookieName); + if (deadCookie->lpCookieData) + HeapFree(GetProcessHeap(), 0, deadCookie->lpCookieData); + if (deadCookie->prev) + deadCookie->prev->next = deadCookie->next; + if (deadCookie->next) + deadCookie->next->prev = deadCookie->prev; + + if (deadCookie == deadCookie->parent->cookie_tail) + { + /* special case: last cookie, lets remove the domain to save memory */ + deadCookie->parent->cookie_tail = deadCookie->prev; + if (!deadCookie->parent->cookie_tail && deleteDomain) + COOKIE_deleteDomain(deadCookie->parent); + } +} + +/* allocates a domain and adds it to the end */ +static cookie_domain *COOKIE_addDomain(LPCSTR domain, LPCSTR path) +{ + cookie_domain *newDomain = HeapAlloc(GetProcessHeap(), 0, sizeof(cookie_domain)); + + newDomain->next = NULL; + newDomain->prev = NULL; + newDomain->cookie_tail = NULL; + newDomain->lpCookieDomain = NULL; + newDomain->lpCookiePath = NULL; + + if (domain) + { + newDomain->lpCookieDomain = HeapAlloc(GetProcessHeap(), 0, strlen(domain) + 1); + strcpy(newDomain->lpCookieDomain, domain); + } + if (path) + { + newDomain->lpCookiePath = HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1); + strcpy(newDomain->lpCookiePath, path); + } + + newDomain->prev = cookieDomainTail; + cookieDomainTail = newDomain; + TRACE("Adding domain: %p\n", newDomain); + return newDomain; +} + +static cookie_domain *COOKIE_addDomainFromUrl(LPCSTR lpszUrl) +{ + char hostName[2048], path[2048]; + URL_COMPONENTSA UrlComponents; + + UrlComponents.lpszExtraInfo = NULL; + UrlComponents.lpszPassword = NULL; + UrlComponents.lpszScheme = NULL; + UrlComponents.lpszUrlPath = path; + UrlComponents.lpszUserName = NULL; + UrlComponents.lpszHostName = hostName; + UrlComponents.dwHostNameLength = 2048; + UrlComponents.dwUrlPathLength = 2048; + + InternetCrackUrlA(lpszUrl, 0, 0, &UrlComponents); + + TRACE("Url cracked. Domain: %s, Path: %s.\n", debugstr_a(UrlComponents.lpszHostName), + debugstr_a(UrlComponents.lpszUrlPath)); + + /* hack for now - FIXME - There seems to be a bug in InternetCrackUrl?? */ + UrlComponents.lpszUrlPath = NULL; + + return COOKIE_addDomain(UrlComponents.lpszHostName, UrlComponents.lpszUrlPath); +} + +/* find a domain. domain must match if its not NULL. path must match if its not NULL */ +static cookie_domain *COOKIE_findNextDomain(LPCSTR lpszCookieDomain, LPCSTR lpszCookiePath, + cookie_domain *prev_domain, BOOL allow_partial) +{ + cookie_domain *searchDomain; + + if (prev_domain) + { + if(!prev_domain->prev) + { + TRACE("no more domains available, it would seem.\n"); + return NULL; + } + searchDomain = prev_domain->prev; + } + else searchDomain = cookieDomainTail; + + while (searchDomain) + { + BOOL candidate = TRUE; + TRACE("searching on domain %p\n", searchDomain); + if (candidate && lpszCookieDomain) + { + if (candidate && !searchDomain->lpCookieDomain) + candidate = FALSE; + TRACE("candidate! (%p)\n", searchDomain->lpCookieDomain); + TRACE("comparing domain %s with %s\n", lpszCookieDomain, searchDomain->lpCookieDomain); + if (candidate && allow_partial && !strstr(lpszCookieDomain, searchDomain->lpCookieDomain)) + candidate = FALSE; + else if (candidate && !allow_partial && + strcmp(lpszCookieDomain, searchDomain->lpCookieDomain) != 0) + candidate = FALSE; + } + if (candidate && lpszCookiePath) + { TRACE("comparing paths\n"); + if (candidate && !searchDomain->lpCookiePath) + candidate = FALSE; + if (candidate && strcmp(lpszCookiePath, searchDomain->lpCookiePath) != 0) + candidate = FALSE; + } + if (candidate) + { + TRACE("returning the domain %p\n", searchDomain); + return searchDomain; + } + searchDomain = searchDomain->prev; + } + TRACE("found no domain, returning NULL\n"); + return NULL; +} + +static cookie_domain *COOKIE_findNextDomainFromUrl(LPCSTR lpszUrl, cookie_domain *previous_domain, + BOOL allow_partial) +{ + char hostName[2048], path[2048]; + URL_COMPONENTSA UrlComponents; + + UrlComponents.lpszExtraInfo = NULL; + UrlComponents.lpszPassword = NULL; + UrlComponents.lpszScheme = NULL; + UrlComponents.lpszUrlPath = path; + UrlComponents.lpszUserName = NULL; + UrlComponents.lpszHostName = hostName; + UrlComponents.dwHostNameLength = 2048; + UrlComponents.dwUrlPathLength = 2048; + + InternetCrackUrlA(lpszUrl, 0, 0, &UrlComponents); + + TRACE("Url cracked. Domain: %s, Path: %s.\n", debugstr_a(UrlComponents.lpszHostName), + debugstr_a(UrlComponents.lpszUrlPath)); + + /* hack for now - FIXME - There seems to be a bug in InternetCrackUrl?? */ + UrlComponents.lpszUrlPath = NULL; + + return COOKIE_findNextDomain(UrlComponents.lpszHostName, UrlComponents.lpszUrlPath, + previous_domain, allow_partial); +} + +/* remove a domain from the list and delete it */ +static void COOKIE_deleteDomain(cookie_domain *deadDomain) +{ + while (deadDomain->cookie_tail) + COOKIE_deleteCookie(deadDomain->cookie_tail, FALSE); + if (deadDomain->lpCookieDomain) + HeapFree(GetProcessHeap(), 0, deadDomain->lpCookieDomain); + if (deadDomain->lpCookiePath) + HeapFree(GetProcessHeap(), 0, deadDomain->lpCookiePath); + if (deadDomain->prev) + deadDomain->prev->next = deadDomain->next; + if (deadDomain->next) + deadDomain->next->prev = deadDomain->prev; + + if (cookieDomainTail == deadDomain) + cookieDomainTail = deadDomain->prev; + HeapFree(GetProcessHeap(), 0, deadDomain); +} + +/*********************************************************************** + * InternetGetCookieA (WININET.@) + * + * Retrieve cookie from the specified url + * + * It should be noted that on windows the lpszCookieName parameter is "not implemented". + * So it won't be implemented here. + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, + LPSTR lpCookieData, LPDWORD lpdwSize) +{ + cookie_domain *cookiesDomain = NULL; + cookie *thisCookie; + int cnt = 0, domain_count = 0; + /* Ok, this is just ODD!. During my tests, it appears M$ like to send out + * a cookie called 'MtrxTracking' to some urls. Also returns it from InternetGetCookie. + * I'm not exactly sure what to make of this, so its here for now. + * It'd be nice to know what exactly is going on, M$ tracking users? Does this need + * to be unique? Should I generate a random number here? etc. + */ + char *TrackingString = "MtrxTrackingID=01234567890123456789012345678901"; + + TRACE("(%s, %s, %p, %p)\n", debugstr_a(lpszUrl),debugstr_a(lpszCookieName), + lpCookieData, lpdwSize); + + if (lpCookieData) + cnt += snprintf(lpCookieData + cnt, *lpdwSize - cnt, "%s", TrackingString); + else + cnt += strlen(TrackingString); + + while ((cookiesDomain = COOKIE_findNextDomainFromUrl(lpszUrl, cookiesDomain, TRUE))) + { + domain_count++; + TRACE("found domain %p\n", cookiesDomain); + + thisCookie = cookiesDomain->cookie_tail; + if (lpCookieData == NULL) /* return the size of the buffer required to lpdwSize */ + { + while (thisCookie) + { + cnt += 2; /* '; ' */ + cnt += strlen(thisCookie->lpCookieName); + cnt += 1; /* = */ + cnt += strlen(thisCookie->lpCookieData); + + thisCookie = thisCookie->prev; + } + } + while (thisCookie) + { + cnt += snprintf(lpCookieData + cnt, *lpdwSize - cnt, "; "); + cnt += snprintf(lpCookieData + cnt, *lpdwSize - cnt, "%s=%s", thisCookie->lpCookieName, + thisCookie->lpCookieData); + + thisCookie = thisCookie->prev; + } + } + if (lpCookieData == NULL) + { + cnt += 1; /* NULL */ + *lpdwSize = cnt; + TRACE("returning\n"); + return TRUE; + } + + if (!domain_count) + return FALSE; + + *lpdwSize = cnt + 1; + + TRACE("Returning %i (from %i domains): %s\n", cnt, domain_count, lpCookieData); + + return (cnt ? TRUE : FALSE); +} + + +/*********************************************************************** + * InternetGetCookieW (WININET.@) + * + * Retrieve cookie from the specified url + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI InternetGetCookieW(LPCSTR lpszUrl, LPCWSTR lpszCookieName, + LPWSTR lpCookieData, LPDWORD lpdwSize) +{ + FIXME("STUB\n"); + TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl), debugstr_w(lpszCookieName), + lpCookieData); + return FALSE; +} + + +/*********************************************************************** + * InternetSetCookieA (WININET.@) + * + * Sets cookie for the specified url + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, + LPCSTR lpCookieData) +{ + cookie *thisCookie; + cookie_domain *thisCookieDomain; + + TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), + debugstr_a(lpszCookieName), lpCookieData); + + if (!lpCookieData || !strlen(lpCookieData)) + { + TRACE("no cookie data, not adding\n"); + return FALSE; + } + if (!lpszCookieName) + { + /* some apps (or is it us??) try to add a cookie with no cookie name, but + * the cookie data in the form of name=data. */ + /* FIXME, probably a bug here, for now I don't care */ + char *ourCookieName, *ourCookieData; + int ourCookieNameSize; + BOOL ret; + if (!(ourCookieData = strchr(lpCookieData, '='))) + { + TRACE("something terribly wrong with cookie data %s\n", ourCookieData); + return FALSE; + } + ourCookieNameSize = ourCookieData - lpCookieData; + ourCookieData += 1; + ourCookieName = HeapAlloc(GetProcessHeap(), 0, ourCookieNameSize + 1); + strncpy(ourCookieName, ourCookieData, ourCookieNameSize); + ourCookieName[ourCookieNameSize] = '\0'; + TRACE("setting (hacked) cookie of %s, %s\n", ourCookieName, ourCookieData); + ret = InternetSetCookieA(lpszUrl, ourCookieName, ourCookieData); + HeapFree(GetProcessHeap(), 0, ourCookieName); + return ret; + } + + if (!(thisCookieDomain = COOKIE_findNextDomainFromUrl(lpszUrl, NULL, FALSE))) + thisCookieDomain = COOKIE_addDomainFromUrl(lpszUrl); + + if ((thisCookie = COOKIE_findCookie(thisCookieDomain, lpszCookieName))) + COOKIE_deleteCookie(thisCookie, FALSE); + + thisCookie = COOKIE_addCookie(thisCookieDomain, lpszCookieName, lpCookieData); + return TRUE; +} + + +/*********************************************************************** + * InternetSetCookieW (WININET.@) + * + * Sets cookie for the specified url + * + * RETURNS + * TRUE on success + * FALSE on failure + * + */ +BOOL WINAPI InternetSetCookieW(LPCSTR lpszUrl, LPCWSTR lpszCookieName, + LPCWSTR lpCookieData) +{ + FIXME("STUB\n"); + TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), + debugstr_w(lpszCookieName), debugstr_w(lpCookieData)); + return FALSE; +} diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index df2a1ebf73d..7cc2d380a47 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3,9 +3,11 @@ * * Copyright 1999 Corel Corporation * Copyright 2002 CodeWeavers Inc. + * Copyright 2002 TransGaming Technologies Inc. * * Ulrich Czekalla * Aric Stewart + * David Hammerton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -111,7 +113,9 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, BOOL bSuccess = FALSE; LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest; - TRACE("\n"); + TRACE("%p, %s, %li, %li\n", hHttpRequest, lpszHeader, dwHeaderLength, + dwModifier); + if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ) { @@ -121,6 +125,8 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, if (!lpszHeader) return TRUE; + + TRACE("copying header: %s\n", lpszHeader); buffer = HTTP_strdup(lpszHeader); lpszStart = buffer; @@ -140,6 +146,7 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest, *lpszEnd = '\0'; + TRACE("interpreting header %s\n", debugstr_a(lpszStart)); if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN)) bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ); @@ -203,7 +210,10 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession; LPWININETAPPINFOA hIC = NULL; - TRACE("(%s, %s, %s, %s, %ld, %ld)\n", lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, dwFlags, dwContext); + TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession, + debugstr_a(lpszVerb), lpszObjectName, + debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); if(lpszAcceptTypes!=NULL) { int i; @@ -249,15 +259,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, workRequest.DWCONTEXT = dwContext; INTERNET_AsyncCall(&workRequest); + TRACE ("returning NULL\n"); return NULL; } else { - return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName, - lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext); + HINTERNET rec = HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName, + lpszVersion, lpszReferrer, lpszAcceptTypes, + dwFlags, dwContext); + TRACE("returning %p\n", rec); + return rec; } } + /*********************************************************************** * HttpOpenRequestW (WININET.@) * @@ -267,27 +282,95 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession, * HINTERNET a HTTP request handle on success * NULL on failure * + * FIXME: This should be the other way around (A should call W) */ HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession, LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes, DWORD dwFlags, DWORD dwContext) { - char szVerb[20], - szObjectName[INTERNET_MAX_PATH_LENGTH]; - TRACE("(%s, %s, %s, %s, %ld, %ld)\n", debugstr_w(lpszVerb), debugstr_w(lpszObjectName), debugstr_w(lpszVersion), debugstr_w(lpszReferrer), dwFlags, dwContext); + CHAR *szVerb = NULL, *szObjectName = NULL; + CHAR *szVersion = NULL, *szReferrer = NULL, **szAcceptTypes = NULL; + INT len; + INT acceptTypesCount; + HINTERNET rc = FALSE; + TRACE("(%p, %s, %s, %s, %s, %p, %08lx, %08lx)\n", hHttpSession, + debugstr_w(lpszVerb), debugstr_w(lpszObjectName), + debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes, + dwFlags, dwContext); - if(lpszVerb!=NULL) - WideCharToMultiByte(CP_ACP,0,lpszVerb,-1,szVerb,20,NULL,NULL); - else - szVerb[0]=0; - if(lpszObjectName!=NULL) - WideCharToMultiByte(CP_ACP,0,lpszObjectName,-1,szObjectName,INTERNET_MAX_PATH_LENGTH,NULL,NULL); - else - szObjectName[0]=0; - TRACE("object name=%s\n",szObjectName); - FIXME("lpszVersion, lpszReferrer and lpszAcceptTypes ignored\n"); - return HttpOpenRequestA(hHttpSession, szVerb[0]?szVerb:NULL, szObjectName, NULL, NULL, NULL, dwFlags, dwContext); + if (lpszVerb) + { + len = lstrlenW(lpszVerb)+1; + if (!(szVerb = (CHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR)))) + goto end; + WideCharToMultiByte(CP_ACP, -1, lpszVerb, -1, szVerb, len, NULL, NULL); + } + + if (lpszObjectName) + { + len = lstrlenW(lpszObjectName)+1; + if (!(szObjectName = (CHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR)))) + goto end; + WideCharToMultiByte(CP_ACP, -1, lpszObjectName, -1, szObjectName, len, NULL, NULL); + } + + if (lpszVersion) + { + len = lstrlenW(lpszVersion)+1; + if (!(szVersion = (CHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR)))) + goto end; + WideCharToMultiByte(CP_ACP, -1, lpszVersion, -1, szVersion, len, NULL, NULL); + } + + if (lpszReferrer) + { + len = lstrlenW(lpszReferrer)+1; + if (!(szReferrer = (CHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(CHAR)))) + goto end; + WideCharToMultiByte(CP_ACP, -1, lpszReferrer, -1, szReferrer, len, NULL, NULL); + } + + acceptTypesCount = 0; + if (lpszAcceptTypes) + { + while (lpszAcceptTypes[acceptTypesCount]) { acceptTypesCount++; } /* find out how many there are */ + szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR *) * acceptTypesCount); + acceptTypesCount = 0; + while (lpszAcceptTypes[acceptTypesCount]) + { + len = lstrlenW(lpszAcceptTypes[acceptTypesCount])+1; + if (!(szAcceptTypes[acceptTypesCount] = (CHAR *) HeapAlloc(GetProcessHeap(), + 0, len * sizeof(CHAR)))) + goto end; + WideCharToMultiByte(CP_ACP, -1, lpszAcceptTypes[acceptTypesCount], + -1, szAcceptTypes[acceptTypesCount], len, NULL, NULL); + acceptTypesCount++; + } + } + else szAcceptTypes = 0; + + rc = HttpOpenRequestA(hHttpSession, (LPCSTR)szVerb, (LPCSTR)szObjectName, + (LPCSTR)szVersion, (LPCSTR)szReferrer, + (LPCSTR *)szAcceptTypes, dwFlags, dwContext); + +end: + if (szAcceptTypes) + { + acceptTypesCount = 0; + while (szAcceptTypes[acceptTypesCount]) + { + HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]); + acceptTypesCount++; + } + HeapFree(GetProcessHeap(), 0, szAcceptTypes); + } + if (szReferrer) HeapFree(GetProcessHeap(), 0, szReferrer); + if (szVersion) HeapFree(GetProcessHeap(), 0, szVersion); + if (szObjectName) HeapFree(GetProcessHeap(), 0, szObjectName); + if (szVerb) HeapFree(GetProcessHeap(), 0, szVerb); + + return rc; } /*********************************************************************** @@ -308,6 +391,9 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession; LPWININETAPPINFOA hIC = NULL; LPWININETHTTPREQA lpwhr; + LPSTR lpszCookies; + LPSTR lpszUrl = NULL; + DWORD nCookieSize; TRACE("--> \n"); @@ -330,7 +416,7 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, lpwhr->hdr.lpwhparent = hHttpSession; lpwhr->hdr.dwFlags = dwFlags; lpwhr->hdr.dwContext = dwContext; - lpwhr->nSocketFD = -1; + NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE); if (NULL != lpszObjectName && strlen(lpszObjectName)) { DWORD needed = 0; @@ -348,11 +434,8 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, } } - if (NULL != hIC->lpszAgent && strlen(hIC->lpszAgent)) - HTTP_ProcessHeader(lpwhr, HTTP_USERAGENT, hIC->lpszAgent, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW); - if (NULL != lpszReferrer && strlen(lpszReferrer)) - HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW); + HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE); if(lpszAcceptTypes!=NULL) { @@ -366,7 +449,7 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, else if (strlen(lpszVerb)) lpwhr->lpszVerb = HTTP_strdup(lpszVerb); - if (NULL != lpszReferrer) + if (NULL != lpszReferrer && strlen(lpszReferrer)) { char buf[MAXHOSTNAME]; URL_COMPONENTSA UrlComponents; @@ -420,6 +503,36 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName); } + if (hIC->lpszAgent) + { + char *agent_header = HeapAlloc(GetProcessHeap(), 0, strlen(hIC->lpszAgent) + 1 + 14); + sprintf(agent_header, "User-Agent: %s\r\n", hIC->lpszAgent); + HttpAddRequestHeadersA((HINTERNET)lpwhr, agent_header, strlen(agent_header), + HTTP_ADDREQ_FLAG_ADD); + HeapFree(GetProcessHeap(), 0, agent_header); + } + + lpszUrl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + 1 + 7); + sprintf(lpszUrl, "http://%s", lpwhr->lpszHostName); + if (InternetGetCookieA(lpszUrl, NULL, NULL, &nCookieSize)) + { + int cnt = 0; + + lpszCookies = HeapAlloc(GetProcessHeap(), 0, nCookieSize + 1 + 8); + + cnt += sprintf(lpszCookies, "Cookie: "); + InternetGetCookieA(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize); + cnt += nCookieSize - 1; + sprintf(lpszCookies + cnt, "\r\n"); + + HttpAddRequestHeadersA((HINTERNET)lpwhr, lpszCookies, strlen(lpszCookies), + HTTP_ADDREQ_FLAG_ADD); + HeapFree(GetProcessHeap(), 0, lpszCookies); + } + HeapFree(GetProcessHeap(), 0, lpszUrl); + + + if (hIC->lpfnStatusCB) { INTERNET_ASYNC_RESULT iar; @@ -443,7 +556,6 @@ HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession, INTERNET_STATUS_RESOLVING_NAME, lpwhs->lpszServerName, strlen(lpwhs->lpszServerName)+1); - if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort, &lpwhs->phostent, &lpwhs->socketAddress)) { @@ -906,6 +1018,8 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest; LPWININETHTTPSESSIONA lpwhs = NULL; LPWININETAPPINFOA hIC = NULL; + BOOL loop_next = FALSE; + int CustHeaderIndex; TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest); @@ -940,131 +1054,272 @@ BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders, goto lend; } - /* If we don't have a path we set it to root */ - if (NULL == lpwhr->lpszPath) - lpwhr->lpszPath = HTTP_strdup("/"); - - if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0 - && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */ + do { - char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2); - *fixurl = '/'; - strcpy(fixurl + 1, lpwhr->lpszPath); - HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath ); - lpwhr->lpszPath = fixurl; - } + TRACE("Going to url %s %s\n", debugstr_a(lpwhr->lpszHostName), debugstr_a(lpwhr->lpszPath)); + loop_next = FALSE; - /* Calculate length of request string */ - requestStringLen = - strlen(lpwhr->lpszVerb) + - strlen(lpwhr->lpszPath) + - (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) + - strlen(HTTPHEADER) + - 5; /* " \r\n\r\n" */ + /* If we don't have a path we set it to root */ + if (NULL == lpwhr->lpszPath) + lpwhr->lpszPath = HTTP_strdup("/"); - /* Add length of passed headers */ - if (lpszHeaders) - { - headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength; - requestStringLen += headerLength + 2; /* \r\n */ - } + if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0 + && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */ + { + char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2); + *fixurl = '/'; + strcpy(fixurl + 1, lpwhr->lpszPath); + HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath ); + lpwhr->lpszPath = fixurl; + } - /* Calculate length of custom request headers */ - for (i = 0; i < lpwhr->nCustHeaders; i++) - { + /* Calculate length of request string */ + requestStringLen = + strlen(lpwhr->lpszVerb) + + strlen(lpwhr->lpszPath) + + strlen(HTTPHEADER) + + 5; /* " \r\n\r\n" */ + + /* Add length of passed headers */ + if (lpszHeaders) + { + headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength; + requestStringLen += headerLength + 2; /* \r\n */ + } + + /* Calculate length of custom request headers */ + for (i = 0; i < lpwhr->nCustHeaders; i++) + { if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) { - requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) + - strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */ + requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) + + strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */ } - } + } - /* Calculate the length of standard request headers */ - for (i = 0; i <= HTTP_QUERY_MAX; i++) - { - if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) - { - requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) + - strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */ - } - } + /* Calculate the length of standard request headers */ + for (i = 0; i <= HTTP_QUERY_MAX; i++) + { + if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) + { + requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) + + strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */ + } + } - /* Allocate string to hold entire request */ - requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1); - if (NULL == requestString) - { - INTERNET_SetLastError(ERROR_OUTOFMEMORY); - goto lend; - } + if (lpwhr->lpszHostName) + requestStringLen += (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)); - /* Build request string */ - cnt = sprintf(requestString, "%s %s%s%s", - lpwhr->lpszVerb, - lpwhr->lpszPath, - lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER, - lpwhr->lpszHostName ? lpwhr->lpszHostName : ""); - /* Append standard request headers */ - for (i = 0; i <= HTTP_QUERY_MAX; i++) - { - if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) - { - cnt += sprintf(requestString + cnt, "\r\n%s: %s", - lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue); - TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue); - } - } + /* Allocate string to hold entire request */ + requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1); + if (NULL == requestString) + { + INTERNET_SetLastError(ERROR_OUTOFMEMORY); + goto lend; + } - /* Append custom request heades */ - for (i = 0; i < lpwhr->nCustHeaders; i++) - { - if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) - { - cnt += sprintf(requestString + cnt, "\r\n%s: %s", - lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue); - TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue); - } - } + /* Build request string */ + cnt = sprintf(requestString, "%s %s%s", + lpwhr->lpszVerb, + lpwhr->lpszPath, + HTTPHEADER); - /* Append passed request headers */ - if (lpszHeaders) - { - strcpy(requestString + cnt, "\r\n"); - cnt += 2; - strcpy(requestString + cnt, lpszHeaders); - cnt += headerLength; - } + /* Append standard request headers */ + for (i = 0; i <= HTTP_QUERY_MAX; i++) + { + if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) + { + cnt += sprintf(requestString + cnt, "\r\n%s: %s", + lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue); + TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue); + } + } - /* Set termination string for request */ - strcpy(requestString + cnt, "\r\n\r\n"); + /* Append custom request heades */ + for (i = 0; i < lpwhr->nCustHeaders; i++) + { + if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) + { + cnt += sprintf(requestString + cnt, "\r\n%s: %s", + lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue); + TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue); + } + } - TRACE("(%s) len(%d)\n", requestString, requestStringLen); - /* Send the request and store the results */ - if (!HTTP_OpenConnection(lpwhr)) - goto lend; + if (lpwhr->lpszHostName) + cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName); - SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, - INTERNET_STATUS_SENDING_REQUEST, NULL, 0); + /* Append passed request headers */ + if (lpszHeaders) + { + strcpy(requestString + cnt, "\r\n"); + cnt += 2; + strcpy(requestString + cnt, lpszHeaders); + cnt += headerLength; + } - cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0); + /* Set termination string for request */ + strcpy(requestString + cnt, "\r\n\r\n"); - SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, - INTERNET_STATUS_REQUEST_SENT, - &requestStringLen,sizeof(DWORD)); + TRACE("(%s) len(%d)\n", requestString, requestStringLen); + /* Send the request and store the results */ + if (!HTTP_OpenConnection(lpwhr)) + goto lend; - SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, - INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, + INTERNET_STATUS_SENDING_REQUEST, NULL, 0); - if (cnt < 0) - goto lend; + NETCON_send(&lpwhr->netConnection, requestString, requestStringLen, + 0, &cnt); - responseLen = HTTP_GetResponseHeaders(lpwhr); - if (responseLen) + + SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, + INTERNET_STATUS_REQUEST_SENT, + &requestStringLen,sizeof(DWORD)); + + SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, + INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); + + if (cnt < 0) + goto lend; + + responseLen = HTTP_GetResponseHeaders(lpwhr); + if (responseLen) bSuccess = TRUE; - SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, - INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, - sizeof(DWORD)); + SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, + INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, + sizeof(DWORD)); + + /* process headers here. Is this right? */ + CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, "Set-Cookie"); + if (CustHeaderIndex >= 0) + { + LPHTTPHEADERA setCookieHeader; + int nPosStart = 0, nPosEnd = 0; + + setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex]; + + while (setCookieHeader->lpszValue[nPosEnd] != '\0') + { + LPSTR buf_cookie, cookie_name, cookie_data; + LPSTR buf_url; + LPSTR domain = NULL; + 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; + LPSTR lpszDomain = strstr(&setCookieHeader->lpszValue[nPosEnd], "domain="); + if (lpszDomain) + { /* they have specified their own domain, lets use it */ + while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' && + lpszDomain[nDomainPosEnd] != '\0') + { + nDomainPosEnd++; + } + nDomainPosStart = strlen("domain="); + nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1; + domain = HeapAlloc(GetProcessHeap(), 0, nDomainLength + 1); + strncpy(domain, &lpszDomain[nDomainPosStart], nDomainLength); + domain[nDomainLength] = '\0'; + } + } + if (setCookieHeader->lpszValue[nPosEnd] == '\0') break; + buf_cookie = HeapAlloc(GetProcessHeap(), 0, (nPosEnd - nPosStart) + 1); + strncpy(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart)); + buf_cookie[(nPosEnd - nPosStart)] = '\0'; + TRACE("%s\n", 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); + strncpy(cookie_name, buf_cookie, nEqualPos); + cookie_name[nEqualPos] = '\0'; + cookie_data = &buf_cookie[nEqualPos + 1]; + + + buf_url = HeapAlloc(GetProcessHeap(), 0, strlen((domain ? domain : lpwhr->lpszHostName)) + strlen(lpwhr->lpszPath) + 9); + sprintf(buf_url, "http://%s/", (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */ + InternetSetCookieA(buf_url, cookie_name, cookie_data); + + HeapFree(GetProcessHeap(), 0, buf_url); + HeapFree(GetProcessHeap(), 0, buf_cookie); + HeapFree(GetProcessHeap(), 0, cookie_name); + if (domain) HeapFree(GetProcessHeap(), 0, domain); + nPosStart = nPosEnd; + } + } + + /* FIXME: is this right? I'm not sure if this should be here or elsewhere (the loop, too) + * FIXME: don't do this if they specify INTERNET_FLAG_NO_AUTO_REDIRECT */ + if (lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue) + { + URL_COMPONENTSA urlComponents; + char protocol[32], hostName[MAXHOSTNAME], userName[1024]; + char password[1024], path[2048], extra[1024]; + + TRACE("Got a Location header: Going around to a new location: %s", + debugstr_a(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue)); + + urlComponents.dwStructSize = sizeof(URL_COMPONENTSA); + urlComponents.lpszScheme = protocol; + urlComponents.dwSchemeLength = 32; + urlComponents.lpszHostName = hostName; + urlComponents.dwHostNameLength = MAXHOSTNAME; + urlComponents.lpszUserName = userName; + urlComponents.dwUserNameLength = 1024; + urlComponents.lpszPassword = password; + urlComponents.dwPasswordLength = 1024; + urlComponents.lpszUrlPath = path; + urlComponents.dwUrlPathLength = 2048; + urlComponents.lpszExtraInfo = extra; + urlComponents.dwExtraInfoLength = 1024; + if (!InternetCrackUrlA(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue, + strlen(lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue), + 0, &urlComponents)) + goto lend; + + if (urlComponents.nScheme != INTERNET_SCHEME_HTTP) + { + FIXME("cannot redirect to non HTTP page\n"); + goto lend; + } + + HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath); + HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1); + strcpy(lpwhr->lpszPath, path); + + if (urlComponents.dwHostNameLength) + { + HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName); + HeapAlloc(GetProcessHeap(), 0, strlen(hostName) + 1); + strcpy(lpwhr->lpszHostName, hostName); + } + + SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext, + INTERNET_STATUS_REDIRECT, NULL, 0); + + HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue); + lpwhr->StdHeaders[HTTP_QUERY_LOCATION].lpszValue = NULL; + loop_next = TRUE; + } + } + while (loop_next); lend: @@ -1192,7 +1447,7 @@ lerror: * windows */ -TRACE("<--\n"); + TRACE("%p -->\n", hInternet); return (HINTERNET)lpwhs; } @@ -1210,7 +1465,6 @@ TRACE("<--\n"); BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr) { BOOL bSuccess = FALSE; - INT result; LPWININETHTTPSESSIONA lpwhs; LPWININETAPPINFOA hIC = NULL; @@ -1231,17 +1485,15 @@ BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr) &(lpwhs->socketAddress), sizeof(struct sockaddr_in)); - lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0); - if (lpwhr->nSocketFD == -1) + if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype, + SOCK_STREAM, 0)) { WARN("Socket creation failed\n"); goto lend; } - result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress, - sizeof(lpwhs->socketAddress)); - - if (result == -1) + if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress, + sizeof(lpwhs->socketAddress))) { WARN("Unable to connect to host (%s)\n", strerror(errno)); goto lend; @@ -1281,19 +1533,20 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr) TRACE("-->\n"); - if (lpwhr->nSocketFD == -1) + if (!NETCON_connected(&lpwhr->netConnection)) goto lend; /* * HACK peek at the buffer */ - rc = recv(lpwhr->nSocketFD,buffer,buflen,MSG_PEEK); + NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc); /* * We should first receive 'HTTP/1.x nnn' where nnn is the status code. */ buflen = MAX_REPLY_LEN; - if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen)) + memset(buffer, 0, MAX_REPLY_LEN); + if (!NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen)) goto lend; if (strncmp(buffer, "HTTP", 4) != 0) @@ -1306,8 +1559,9 @@ BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr) do { buflen = MAX_REPLY_LEN; - if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen)) + if (NETCON_getNextLine(&lpwhr->netConnection, buffer, &buflen)) { + TRACE("got line %s, now interpretting\n", debugstr_a(buffer)); if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN)) break; @@ -1637,11 +1891,10 @@ VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr) SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext, INTERNET_STATUS_CLOSING_CONNECTION, 0, 0); - if (lpwhr->nSocketFD != -1) - { - close(lpwhr->nSocketFD); - lpwhr->nSocketFD = -1; - } + if (NETCON_connected(&lpwhr->netConnection)) + { + NETCON_close(&lpwhr->netConnection); + } SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext, INTERNET_STATUS_CONNECTION_CLOSED, 0, 0); @@ -1662,7 +1915,7 @@ void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr) TRACE("\n"); - if (lpwhr->nSocketFD != -1) + if (NETCON_connected(&lpwhr->netConnection)) HTTP_CloseConnection(lpwhr); lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent; @@ -1709,7 +1962,7 @@ void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr) void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs) { LPWININETAPPINFOA hIC = NULL; - TRACE("\n"); + TRACE("%p\n", lpwhs); hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent; diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 8b522964bbb..dca2e93e18b 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -3,11 +3,12 @@ * * Copyright 1999 Corel Corporation * Copyright 2002 CodeWeavers Inc. + * Copyright 2002 Jaco Greeff + * Copyright 2002 TransGaming Technologies Inc. * * Ulrich Czekalla * Aric Stewart - * - * Copyright 2002 Jaco Greeff + * David Hammerton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -222,7 +223,8 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, { LPWININETAPPINFOA lpwai = NULL; - TRACE("\n"); + TRACE("(%s, %li, %s, %s, %li)\n", debugstr_a(lpszAgent), dwAccessType, + debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags); /* Clear any error information */ INTERNET_SetLastError(0); @@ -278,6 +280,7 @@ HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, lpwai->dwAccessType = dwAccessType; } + TRACE("returning %p\n", (HINTERNET)lpwai); return (HINTERNET)lpwai; } @@ -299,9 +302,9 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, INT lenAgent = lstrlenW(lpszAgent)+1; INT lenProxy = lstrlenW(lpszProxy)+1; INT lenBypass = lstrlenW(lpszProxyBypass)+1; - CHAR *szAgent = (CHAR *)malloc(lenAgent*sizeof(CHAR)); - CHAR *szProxy = (CHAR *)malloc(lenProxy*sizeof(CHAR)); - CHAR *szBypass = (CHAR *)malloc(lenBypass*sizeof(CHAR)); + CHAR *szAgent = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenAgent*sizeof(CHAR)); + CHAR *szProxy = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenProxy*sizeof(CHAR)); + CHAR *szBypass = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenBypass*sizeof(CHAR)); if (!szAgent || !szProxy || !szBypass) { @@ -323,9 +326,9 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, rc = InternetOpenA(szAgent, dwAccessType, szProxy, szBypass, dwFlags); - free(szAgent); - free(szProxy); - free(szBypass); + HeapFree(GetProcessHeap(), 0, szAgent); + HeapFree(GetProcessHeap(), 0, szProxy); + HeapFree(GetProcessHeap(), 0, szBypass); return rc; } @@ -422,7 +425,9 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, { HINTERNET rc = (HINTERNET) NULL; - TRACE("ServerPort %i\n",nServerPort); + TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_a(lpszServerName), + nServerPort, debugstr_a(lpszUserName), debugstr_a(lpszPassword), + dwService, dwFlags, dwContext); /* Clear any error information */ INTERNET_SetLastError(0); @@ -444,6 +449,7 @@ HINTERNET WINAPI InternetConnectA(HINTERNET hInternet, break; } + TRACE("returning %p\n", rc); return rc; } @@ -464,37 +470,42 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet, DWORD dwService, DWORD dwFlags, DWORD dwContext) { HINTERNET rc = (HINTERNET)NULL; - INT lenServer = lstrlenW(lpszServerName)+1; - INT lenUser = lstrlenW(lpszUserName)+1; - INT lenPass = lstrlenW(lpszPassword)+1; - CHAR *szServerName = (CHAR *)malloc(lenServer*sizeof(CHAR)); - CHAR *szUserName = (CHAR *)malloc(lenUser*sizeof(CHAR)); - CHAR *szPassword = (CHAR *)malloc(lenPass*sizeof(CHAR)); + INT lenServer = 0; + INT lenUser = 0; + INT lenPass = 0; + CHAR *szServerName = NULL; + CHAR *szUserName = NULL; + CHAR *szPassword = NULL; - if (!szServerName || !szUserName || !szPassword) + if (lpszServerName) { - if (szServerName) - free(szServerName); - if (szUserName) - free(szUserName); - if (szPassword) - free(szPassword); - return (HINTERNET)NULL; + lenServer = lstrlenW(lpszServerName)+1; + szServerName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenServer*sizeof(CHAR)); + WideCharToMultiByte(CP_ACP, -1, lpszServerName, -1, szServerName, lenServer, + NULL, NULL); + } + if (lpszUserName) + { + lenUser = lstrlenW(lpszUserName)+1; + szUserName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUser*sizeof(CHAR)); + WideCharToMultiByte(CP_ACP, -1, lpszUserName, -1, szUserName, lenUser, + NULL, NULL); + } + if (lpszPassword) + { + lenPass = lstrlenW(lpszPassword)+1; + szPassword = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenPass*sizeof(CHAR)); + WideCharToMultiByte(CP_ACP, -1, lpszPassword, -1, szPassword, lenPass, + NULL, NULL); } - WideCharToMultiByte(CP_ACP, -1, lpszServerName, -1, szServerName, lenServer, - NULL, NULL); - WideCharToMultiByte(CP_ACP, -1, lpszUserName, -1, szUserName, lenUser, - NULL, NULL); - WideCharToMultiByte(CP_ACP, -1, lpszPassword, -1, szPassword, lenPass, - NULL, NULL); rc = InternetConnectA(hInternet, szServerName, nServerPort, szUserName, szPassword, dwService, dwFlags, dwContext); - free(szServerName); - free(szUserName); - free(szPassword); + if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName); + if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName); + if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword); return rc; } @@ -870,7 +881,7 @@ BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWS { TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len); - if (*dwComponentLen != 0) + if (*dwComponentLen != 0 || *lppszComponent == NULL) { if (*lppszComponent == NULL) { @@ -1244,7 +1255,10 @@ BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer , switch (lpwh->htype) { case WH_HHTTPREQ: - nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD; + FIXME("This shouldn't be here! We don't support this kind" + " of connection anymore. Must use NETCON functions," + " especially if using SSL\n"); + nSocket = ((LPWININETHTTPREQA)hFile)->netConnection.socketFD; break; case WH_HFILE: @@ -1288,14 +1302,29 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer, if (NULL == lpwh) return FALSE; + /* FIXME: this should use NETCON functions! */ switch (lpwh->htype) { case WH_HHTTPREQ: - nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD; + if (!NETCON_recv(&((LPWININETHTTPREQA)hFile)->netConnection, lpBuffer, + dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead)) + { + *dwNumOfBytesRead = 0; + retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */ + } + else + retval = TRUE; break; case WH_HFILE: + /* FIXME: FTP should use NETCON_ stuff */ nSocket = ((LPWININETFILE)hFile)->nDataSocket; + if (nSocket != -1) + { + int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0); + retval = (res >= 0); + *dwNumOfBytesRead = retval ? res : 0; + } break; default: @@ -1356,7 +1385,7 @@ static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD d LPWININETHANDLEHEADER lpwhh; BOOL bSuccess = FALSE; - TRACE("0x%08lx\n", dwOption); + TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength); if (NULL == hInternet) { @@ -1630,86 +1659,6 @@ BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption, } -/*********************************************************************** - * InternetGetCookieA (WININET.@) - * - * Retrieve cookie from the specified url - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI InternetGetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, - LPSTR lpCookieData, LPDWORD lpdwSize) -{ - FIXME("STUB\n"); - TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl),debugstr_a(lpszCookieName), - lpCookieData); - return FALSE; -} - - -/*********************************************************************** - * InternetGetCookieW (WININET.@) - * - * Retrieve cookie from the specified url - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI InternetGetCookieW(LPCSTR lpszUrl, LPCWSTR lpszCookieName, - LPWSTR lpCookieData, LPDWORD lpdwSize) -{ - FIXME("STUB\n"); - TRACE("(%s,%s,%p)\n", debugstr_a(lpszUrl), debugstr_w(lpszCookieName), - lpCookieData); - return FALSE; -} - - -/*********************************************************************** - * InternetSetCookieA (WININET.@) - * - * Sets cookie for the specified url - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI InternetSetCookieA(LPCSTR lpszUrl, LPCSTR lpszCookieName, - LPCSTR lpCookieData) -{ - FIXME("STUB\n"); - TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), - debugstr_a(lpszCookieName), debugstr_a(lpCookieData)); - return FALSE; -} - - -/*********************************************************************** - * InternetSetCookieW (WININET.@) - * - * Sets cookie for the specified url - * - * RETURNS - * TRUE on success - * FALSE on failure - * - */ -BOOL WINAPI InternetSetCookieW(LPCSTR lpszUrl, LPCWSTR lpszCookieName, - LPCWSTR lpCookieData) -{ - FIXME("STUB\n"); - TRACE("(%s,%s,%s)\n", debugstr_a(lpszUrl), - debugstr_w(lpszCookieName), debugstr_w(lpCookieData)); - return FALSE; -} - - /*********************************************************************** * InternetCheckConnectionA (WININET.@) * @@ -1807,11 +1756,11 @@ BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRes BOOL rc; len = lstrlenW(lpszUrl)+1; - if (!(szUrl = (CHAR *)malloc(len*sizeof(CHAR)))) + if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR)))) return FALSE; WideCharToMultiByte(CP_ACP, -1, lpszUrl, -1, szUrl, len, NULL, NULL); rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved); - free(szUrl); + HeapFree(GetProcessHeap(), 0, szUrl); return rc; } @@ -1832,6 +1781,10 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, char protocol[32], hostName[MAXHOSTNAME], userName[1024]; char password[1024], path[2048], extra[1024]; HINTERNET client = NULL, client1 = NULL; + + TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_a(lpszUrl), debugstr_a(lpszHeaders), + dwHeadersLength, dwFlags, dwContext); + urlComponents.dwStructSize = sizeof(URL_COMPONENTSA); urlComponents.lpszScheme = protocol; urlComponents.dwSchemeLength = 32; @@ -1907,15 +1860,15 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, INT lenUrl = lstrlenW(lpszUrl)+1; INT lenHeaders = lstrlenW(lpszHeaders)+1; - CHAR *szUrl = (CHAR *)malloc(lenUrl*sizeof(CHAR)); - CHAR *szHeaders = (CHAR *)malloc(lenHeaders*sizeof(CHAR)); + CHAR *szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(CHAR)); + CHAR *szHeaders = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(CHAR)); if (!szUrl || !szHeaders) { if (szUrl) - free(szUrl); + HeapFree(GetProcessHeap(), 0, szUrl); if (szHeaders) - free(szHeaders); + HeapFree(GetProcessHeap(), 0, szHeaders); return (HINTERNET)NULL; } @@ -1927,8 +1880,8 @@ HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl, rc = InternetOpenUrlA(hInternet, szUrl, szHeaders, dwHeadersLength, dwFlags, dwContext); - free(szUrl); - free(szHeaders); + HeapFree(GetProcessHeap(), 0, szUrl); + HeapFree(GetProcessHeap(), 0, szHeaders); return rc; } @@ -2266,7 +2219,6 @@ LPSTR INTERNET_GetResponseBuffer() return lpwite->response; } - /*********************************************************************** * INTERNET_GetNextLine (internal) * @@ -2340,7 +2292,7 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, { LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hFile; INT retval = -1; - int nSocket = -1; + char buffer[4048]; if (NULL == lpwhr) @@ -2349,32 +2301,24 @@ BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile, return FALSE; } - TRACE("--> %p %i %i\n",lpwhr,lpwhr->hdr.htype,lpwhr->nSocketFD); + TRACE("--> %p %i\n",lpwhr,lpwhr->hdr.htype); switch (lpwhr->hdr.htype) { - case WH_HHTTPREQ: - nSocket = lpwhr->nSocketFD; - break; + case WH_HHTTPREQ: + if (!NETCON_recv(&((LPWININETHTTPREQA)hFile)->netConnection, buffer, + 4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble)) + { + SetLastError(ERROR_NO_MORE_FILES); + retval = FALSE; + } + else + retval = TRUE; + break; - default: - break; - } - - if (nSocket != -1) - { - char buffer[4048]; - - retval = recv(nSocket,buffer,4048,MSG_PEEK); - } - else - { - SetLastError(ERROR_NO_MORE_FILES); - } - - if (lpdwNumberOfBytesAvailble) - { - (*lpdwNumberOfBytesAvailble) = retval; + default: + FIXME("unsuported file type\n"); + break; } TRACE("<-- %i\n",retval); diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index fc4b2f172d8..6e8e0d90c98 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -31,6 +31,20 @@ # include # include #endif +#ifdef HAVE_OPENSSL_SSL_H +# include +#endif + +/* used for netconnection.c stuff */ +typedef struct +{ + BOOL useSSL; + int socketFD; +#ifdef HAVE_OPENSSL_SSL_H + SSL *ssl_s; + int ssl_sock; +#endif +} WININET_NETCONNECTION; typedef enum { @@ -93,7 +107,7 @@ typedef struct LPSTR lpszPath; LPSTR lpszVerb; LPSTR lpszHostName; - INT nSocketFD; + WININET_NETCONNECTION netConnection; HTTPHEADERA StdHeaders[HTTP_QUERY_MAX+1]; HTTPHEADERA *pCustHeaders; INT nCustHeaders; @@ -265,6 +279,19 @@ VOID SendAsyncCallbackInt(LPWININETAPPINFOA hIC, HINTERNET hHttpSession, lpvStatusInfo , DWORD dwStatusInfoLength); +BOOL NETCON_connected(WININET_NETCONNECTION *connection); +void NETCON_init(WININET_NETCONNECTION *connnection, BOOL useSSL); +BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, + int type, int protocol); +BOOL NETCON_close(WININET_NETCONNECTION *connection); +BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, + socklen_t addrlen); +BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, + int *sent /* out */); +BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, + int *recvd /* out */); +BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer); + #define MAX_REPLY_LEN 0x5B4 diff --git a/dlls/wininet/netconnection.c b/dlls/wininet/netconnection.c new file mode 100644 index 00000000000..d21c3e6d402 --- /dev/null +++ b/dlls/wininet/netconnection.c @@ -0,0 +1,490 @@ +/* + * Wininet - networking layer. Uses unix sockets or OpenSSL. + * + * Copyright 2002 TransGaming Technologies Inc. + * + * David Hammerton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#include +#include +#include + +#include "wine/library.h" +#include "windef.h" +#include "winbase.h" +#include "wininet.h" +#include "winerror.h" + +#include "wine/debug.h" +#include "internet.h" + +#define RESPONSE_TIMEOUT 30 /* FROM internet.c */ + + +WINE_DEFAULT_DEBUG_CHANNEL(wininet); + +/* FIXME!!!!!! + * This should use winsock - To use winsock the funtions will have to change a bit + * as they are designed for unix sockets. + * SSL stuff should use crypt32.dll + */ + +#ifdef HAVE_OPENSSL_SSL_H + +#ifndef SONAME_LIBSSL +#define SONAME_LIBSSL "libssl.so" +#endif +#ifndef SONAME_LIBCRYPTO +#define SONAME_LIBCRYPTO "libcrypto.so" +#endif + +static void *OpenSSL_ssl_handle; +static void *OpenSSL_crypto_handle; + +static SSL_METHOD *meth; +static SSL_CTX *ctx; + +#define MAKE_FUNCPTR(f) static typeof(f) * p##f + +/* OpenSSL funtions that we use */ +MAKE_FUNCPTR(SSL_library_init); +MAKE_FUNCPTR(SSL_load_error_strings); +MAKE_FUNCPTR(SSLv23_method); +MAKE_FUNCPTR(SSL_CTX_new); +MAKE_FUNCPTR(SSL_new); +MAKE_FUNCPTR(SSL_set_bio); +MAKE_FUNCPTR(SSL_connect); +MAKE_FUNCPTR(SSL_write); +MAKE_FUNCPTR(SSL_read); +MAKE_FUNCPTR(SSL_CTX_get_timeout); +MAKE_FUNCPTR(SSL_CTX_set_timeout); + +/* OpenSSL's libcrypto functions that we use */ +MAKE_FUNCPTR(BIO_new_socket); +MAKE_FUNCPTR(BIO_new_fp); +#undef MAKE_FUNCPTR + +#endif + +void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) +{ + connection->useSSL = useSSL; + connection->socketFD = -1; + if (connection->useSSL) + { +#ifdef HAVE_OPENSSL_SSL_H + TRACE("using SSL connection\n"); + connection->ssl_sock = -1; + if (OpenSSL_ssl_handle) /* already initilzed everything */ + return; + OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); + if (!OpenSSL_ssl_handle) + { + ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", + SONAME_LIBSSL); + connection->useSSL = FALSE; + return; + } + OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); + if (!OpenSSL_crypto_handle) + { + ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", + SONAME_LIBCRYPTO); + connection->useSSL = FALSE; + return; + } + + /* mmm nice ugly macroness */ +#define DYNSSL(x) \ + p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \ + if (!p##x) \ + { \ + ERR("failed to load symbol %s\n", #x); \ + connection->useSSL = FALSE; \ + return; \ + } + + DYNSSL(SSL_library_init); + DYNSSL(SSL_load_error_strings); + DYNSSL(SSLv23_method); + DYNSSL(SSL_CTX_new); + DYNSSL(SSL_new); + DYNSSL(SSL_set_bio); + DYNSSL(SSL_connect); + DYNSSL(SSL_write); + DYNSSL(SSL_read); + DYNSSL(SSL_CTX_get_timeout); + DYNSSL(SSL_CTX_set_timeout); +#undef DYNSSL + +#define DYNCRYPTO(x) \ + p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \ + if (!p##x) \ + { \ + ERR("failed to load symbol %s\n", #x); \ + connection->useSSL = FALSE; \ + return; \ + } + DYNCRYPTO(BIO_new_fp); + DYNCRYPTO(BIO_new_socket); +#undef DYNCRYPTO + + pSSL_library_init(); + pSSL_load_error_strings(); + pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ + + meth = pSSLv23_method(); + /* FIXME: SECURITY PROBLEM! WE ARN'T VERIFYING THE HOSTS CERTIFICATES OR ANYTHING */ +#else + FIXME("can't use SSL, not compiled in.\n"); + connection->useSSL = FALSE; +#endif + } +} + +BOOL NETCON_connected(WININET_NETCONNECTION *connection) +{ + if (!connection->useSSL) + { + if (connection->socketFD == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + if (connection->ssl_sock == -1) + return FALSE; + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * NETCON_create + * Basically calls 'socket()' unless useSSL is supplised, + * in which case we do other things. + */ +BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, + int type, int protocol) +{ + if (!connection->useSSL) + { + connection->socketFD = socket(domain, type, protocol); + if (connection->socketFD == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + connection->ssl_sock = socket(domain, type, protocol); + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * NETCON_close + * Basically calls 'close()' unless we should use SSL + */ +BOOL NETCON_close(WININET_NETCONNECTION *connection) +{ + if (!NETCON_connected) return FALSE; + if (!connection->useSSL) + { + int result; + result = close(connection->socketFD); + connection->socketFD = -1; + if (result == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + close(connection->ssl_sock); + connection->ssl_sock = -1; + /* FIXME should we call SSL_shutdown here?? Probably on whatever is the + * opposite of NETCON_init.... */ + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * NETCON_connect + * Basically calls 'connect()' unless we should use SSL + */ +BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr, + socklen_t addrlen) +{ + if (!NETCON_connected) return FALSE; + if (!connection->useSSL) + { + int result; + result = connect(connection->socketFD, serv_addr, addrlen); + if (result == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + BIO *sbio; + + ctx = pSSL_CTX_new(meth); + connection->ssl_s = pSSL_new(ctx); + + if (connect(connection->ssl_sock, serv_addr, addrlen) == -1) + return FALSE; + + sbio = pBIO_new_socket(connection->ssl_sock, BIO_NOCLOSE); + pSSL_set_bio(connection->ssl_s, sbio, sbio); + if (pSSL_connect(connection->ssl_s) <= 0) + { + ERR("ssl couldn't connect\n"); + return FALSE; + } + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * NETCON_send + * Basically calls 'send()' unless we should use SSL + * number of chars send is put in *sent + */ +BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags, + int *sent /* out */) +{ + if (!NETCON_connected) return FALSE; + if (!connection->useSSL) + { + *sent = send(connection->socketFD, msg, len, flags); + if (*sent == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + if (flags) + FIXME("SSL_write doesn't support any flags (%08x)\n", flags); + *sent = pSSL_write(connection->ssl_s, msg, len); + if (*sent < 1 && len) + return FALSE; + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * NETCON_recv + * Basically calls 'recv()' unless we should use SSL + * number of chars receieved is put in *recvd + */ +BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags, + int *recvd /* out */) +{ + if (!NETCON_connected) return FALSE; + if (!connection->useSSL) + { + *recvd = recv(connection->socketFD, buf, len, flags); + if (*recvd == -1) + return FALSE; + return TRUE; + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + static char *peek_msg = NULL; + static char *peek_msg_mem = NULL; + + if (flags & (~MSG_PEEK)) + 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 && !peek_msg) + { + peek_msg = peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1); + } + else if (flags & MSG_PEEK && peek_msg) + { + if (len < strlen(peek_msg)) + FIXME("buffer isn't big enough. Do the expect us to wrap?\n"); + strncpy(buf, peek_msg, len); + *recvd = (strlen(peek_msg) <= len ? strlen(peek_msg) : len); + return TRUE; + } + else if (peek_msg) + { + strncpy(buf, peek_msg, len); + peek_msg += *recvd = min(len, strlen(peek_msg)); + if (*peek_msg == '\0' || *(peek_msg - 1) == '\0') + { + HeapFree(GetProcessHeap(), 0, peek_msg_mem); + peek_msg_mem = NULL; + peek_msg = NULL; + } + return TRUE; + } + *recvd = pSSL_read(connection->ssl_s, buf, len); + if (flags & MSG_PEEK) /* must copy stuff into buffer */ + { + if (!*recvd) + { + HeapFree(GetProcessHeap(), 0, peek_msg_mem); + peek_msg_mem = NULL; + peek_msg = NULL; + } + else + { + strncpy(peek_msg, buf, *recvd); + peek_msg[*recvd] = '\0'; + } + } + if (*recvd < 1 && len) + return FALSE; + return TRUE; +#else + return FALSE; +#endif + } +} + +/****************************************************************************** + * 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; + INT 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(ERROR_CONNECTION_ABORTED); /* fixme: right error? */ + 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 - 1; + TRACE(":%d %s\n", nRecv, lpszBuffer); + return TRUE; + } + else + { + return FALSE; + } + } + else + { +#ifdef HAVE_OPENSSL_SSL_H + long prev_timeout; + INT 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 - 1; + TRACE("_SSL:%d %s\n", nRecv, lpszBuffer); + return TRUE; + } + return FALSE; +#else + return FALSE; +#endif + } +} diff --git a/include/config.h.in b/include/config.h.in index f9d813532d2..9adc1a09805 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -371,6 +371,9 @@ /* Define if OpenGL is present on the system */ #undef HAVE_OPENGL +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_SSL_H + /* Define if you have the Open Sound system */ #undef HAVE_OSS @@ -761,6 +764,9 @@ /* The size of a `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG +/* Define to the soname of the libcrypto library. */ +#undef SONAME_LIBCRYPTO + /* Define to the soname of the libcups library. */ #undef SONAME_LIBCUPS @@ -773,6 +779,9 @@ /* Define to the soname of the libjack library. */ #undef SONAME_LIBJACK +/* Define to the soname of the libssl library. */ +#undef SONAME_LIBSSL + /* Define to the soname of the libX11 library. */ #undef SONAME_LIBX11