From 852c7ae40417ee0ef33242c63bfcc29b10cb522f Mon Sep 17 00:00:00 2001
From: David Hammerton <david@transgaming.com>
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      | 244 ++++++----------
 dlls/wininet/internet.h      |  29 +-
 dlls/wininet/netconnection.c | 490 +++++++++++++++++++++++++++++++
 include/config.h.in          |   9 +
 9 files changed, 1647 insertions(+), 299 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.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
+ *     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)
+    {
+        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(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 (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);
+            }
+        }
+
+        /* 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);
+            }
+        }
 
-    /* Set termination string for request */
-    strcpy(requestString + cnt, "\r\n\r\n");
+        if (lpwhr->lpszHostName)
+            cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName);
 
-    TRACE("(%s) len(%d)\n", requestString, requestStringLen);
-    /* Send the request and store the results */
-    if (!HTTP_OpenConnection(lpwhr))
-        goto lend;
+        /* Append passed request headers */
+        if (lpszHeaders)
+        {
+            strcpy(requestString + cnt, "\r\n");
+            cnt += 2;
+            strcpy(requestString + cnt, lpszHeaders);
+            cnt += headerLength;
+        }
 
-    SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
-                      INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
+        /* Set termination string for request */
+        strcpy(requestString + cnt, "\r\n\r\n");
 
-    cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0);
+        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_SENDING_REQUEST, NULL, 0);
 
-    SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
-                      INTERNET_STATUS_REQUEST_SENT,
-                      &requestStringLen,sizeof(DWORD));
+        NETCON_send(&lpwhr->netConnection, requestString, requestStringLen,
+                    0, &cnt);
 
-    SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
-                      INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
 
-    if (cnt < 0)
-        goto lend;
+        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)
+        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));
-
-    if (!szServerName || !szUserName || !szPassword)
+    INT lenServer = 0;
+    INT lenUser = 0;
+    INT lenPass = 0;
+    CHAR *szServerName = NULL;
+    CHAR *szUserName = NULL;
+    CHAR *szPassword = NULL;
+
+    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;
-
-        default:
-            break;
-    }
-
-    if (nSocket != -1)
-    {
-        char buffer[4048];
-
-        retval = recv(nSocket,buffer,4048,MSG_PEEK);
-    }
-    else
-    {
-        SetLastError(ERROR_NO_MORE_FILES);
-    }
+    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;
 
-    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 <sys/types.h>
 # include <netinet/in.h>
 #endif
+#ifdef HAVE_OPENSSL_SSL_H
+# include <openssl/ssl.h>
+#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 <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <openssl/ssl.h> 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
 
-- 
GitLab