[KMTestSuite]
[reactos.git] / winetests / wininet / http.c
index 93b3877..5db7f64 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "wine/test.h"
 
-#define TEST_URL "http://test.winehq.org/hello.html"
+#define TEST_URL "http://test.winehq.org/tests/hello.html"
 
 static BOOL first_connection_to_test_url = TRUE;
 
@@ -62,14 +62,14 @@ static BOOL first_connection_to_test_url = TRUE;
         if (!expect[status] && !optional[status] && wine_allow[status]) \
         { \
             todo_wine ok(expect[status], "unexpected status %d (%s)\n", status, \
-                         status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \
+                         status < MAX_INTERNET_STATUS && status_string[status] ? \
                          status_string[status] : "unknown");            \
             wine_allow[status]--; \
         } \
         else \
         { \
             ok(expect[status] || optional[status], "unexpected status %d (%s)\n", status,   \
-               status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \
+               status < MAX_INTERNET_STATUS && status_string[status] ? \
                status_string[status] : "unknown");                      \
             if (expect[status]) expect[status]--; \
             else optional[status]--; \
@@ -86,7 +86,7 @@ static BOOL first_connection_to_test_url = TRUE;
     do { \
         ok(notified[status] + optional[status] == (num), \
            "expected status %d (%s) %d times, received %d times\n", \
-           status, status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \
+           status, status < MAX_INTERNET_STATUS && status_string[status] ? \
            status_string[status] : "unknown", (num), notified[status]); \
         CLEAR_NOTIFIED(status);                                         \
     }while(0)
@@ -98,31 +98,43 @@ static BOOL first_connection_to_test_url = TRUE;
     CHECK_NOTIFIED2(status, 0)
 
 #define MAX_INTERNET_STATUS (INTERNET_STATUS_COOKIE_HISTORY+1)
-#define MAX_STATUS_NAME 50
 static int expect[MAX_INTERNET_STATUS], optional[MAX_INTERNET_STATUS],
     wine_allow[MAX_INTERNET_STATUS], notified[MAX_INTERNET_STATUS];
-static CHAR status_string[MAX_INTERNET_STATUS][MAX_STATUS_NAME];
+static const char *status_string[MAX_INTERNET_STATUS];
 
-static HANDLE hCompleteEvent;
+static HANDLE hCompleteEvent, conn_close_event;
 
 #define TESTF_REDIRECT      0x01
 #define TESTF_COMPRESSED    0x02
 #define TESTF_ALLOW_COOKIE  0x04
+#define TESTF_CHUNKED       0x08
 
 typedef struct {
     const char *url;
     const char *redirected_url;
     const char *host;
     const char *path;
+    const char *headers;
     DWORD flags;
+    const char *post_data;
+    const char *content;
 } test_data_t;
 
 static const test_data_t test_data[] = {
     {
-        "http://test.winehq.org/testredirect",
-        "http://test.winehq.org/hello.html",
+        "http://test.winehq.org/tests/data.php",
+        "http://test.winehq.org/tests/data.php",
         "test.winehq.org",
-        "/testredirect",
+        "/tests/data.php",
+        "",
+        TESTF_CHUNKED
+    },
+    {
+        "http://test.winehq.org/tests/redirect",
+        "http://test.winehq.org/tests/hello.html",
+        "test.winehq.org",
+        "/tests/redirect",
+        "",
         TESTF_REDIRECT
     },
     {
@@ -130,12 +142,43 @@ static const test_data_t test_data[] = {
         "http://www.codeweavers.com/",
         "www.codeweavers.com",
         "",
+        "Accept-Encoding: gzip, deflate",
         TESTF_COMPRESSED|TESTF_ALLOW_COOKIE
+    },
+    {
+        "http://test.winehq.org/tests/post.php",
+        "http://test.winehq.org/tests/post.php",
+        "test.winehq.org",
+        "/tests/post.php",
+        "Content-Type: application/x-www-form-urlencoded",
+        0,
+        "mode=Test",
+        "mode => Test\n"
     }
 };
 
 static INTERNET_STATUS_CALLBACK (WINAPI *pInternetSetStatusCallbackA)(HINTERNET ,INTERNET_STATUS_CALLBACK);
 
+static BOOL proxy_active(void)
+{
+    HKEY internet_settings;
+    DWORD proxy_enable;
+    DWORD size;
+
+    if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+                      0, KEY_QUERY_VALUE, &internet_settings) != ERROR_SUCCESS)
+        return FALSE;
+
+    size = sizeof(DWORD);
+    if (RegQueryValueExA(internet_settings, "ProxyEnable", NULL, NULL, (LPBYTE) &proxy_enable, &size) != ERROR_SUCCESS)
+        proxy_enable = 0;
+
+    RegCloseKey(internet_settings);
+
+    return proxy_enable != 0;
+}
+
+static int close_handle_cnt;
 
 static VOID WINAPI callback(
      HINTERNET hInternet,
@@ -235,6 +278,8 @@ static VOID WINAPI callback(
             trace("%04x:Callback %p 0x%lx INTERNET_STATUS_HANDLE_CLOSING %p %d\n",
                 GetCurrentThreadId(), hInternet, dwContext,
                 *(HINTERNET *)lpvStatusInformation, dwStatusInformationLength);
+            if(!--close_handle_cnt)
+                SetEvent(hCompleteEvent);
             break;
         case INTERNET_STATUS_REQUEST_COMPLETE:
         {
@@ -268,11 +313,26 @@ static VOID WINAPI callback(
     }
 }
 
-static void InternetReadFile_test(int flags, const test_data_t *test)
+static void close_async_handle(HINTERNET handle, HANDLE complete_event, int handle_cnt)
 {
     BOOL res;
+
+    close_handle_cnt = handle_cnt;
+
+    SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt);
+    res = InternetCloseHandle(handle);
+    ok(res, "InternetCloseHandle failed: %u\n", GetLastError());
+    WaitForSingleObject(hCompleteEvent, INFINITE);
+    CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt);
+    SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, handle_cnt);
+}
+
+static void InternetReadFile_test(int flags, const test_data_t *test)
+{
+    char *post_data = NULL;
+    BOOL res, on_async = TRUE;
     CHAR buffer[4000];
-    DWORD length;
+    DWORD length, post_len = 0;
     DWORD out;
     const char *types[2] = { "*", NULL };
     HINTERNET hi, hic = 0, hor = 0;
@@ -305,7 +365,7 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
 
     trace("HttpOpenRequestA <--\n");
-    hor = HttpOpenRequestA(hic, "GET", test->path, NULL, NULL, types,
+    hor = HttpOpenRequestA(hic, test->post_data ? "POST" : "GET", test->path, NULL, NULL, types,
                            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE,
                            0xdeadbead);
     if (hor == 0x0 && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) {
@@ -344,17 +404,8 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     {
         SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME);
         SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED);
-        SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME);
-        SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED);
     }
-    else
-    {
-        SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2);
-        SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2);
-    }
-    SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER);
     SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
-    SET_WINE_ALLOW(INTERNET_STATUS_CONNECTED_TO_SERVER);
     SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
     SET_EXPECT2(INTERNET_STATUS_SENDING_REQUEST, (test->flags & TESTF_REDIRECT) ? 2 : 1);
     SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, (test->flags & TESTF_REDIRECT) ? 2 : 1);
@@ -369,8 +420,6 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     SET_OPTIONAL(INTERNET_STATUS_CONNECTED_TO_SERVER);
     if (flags & INTERNET_FLAG_ASYNC)
         SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
-    else
-        SET_WINE_ALLOW(INTERNET_STATUS_REQUEST_COMPLETE);
 
     if(test->flags & TESTF_COMPRESSED) {
         BOOL b = TRUE;
@@ -383,8 +432,13 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     }
 
     trace("HttpSendRequestA -->\n");
+    if(test->post_data) {
+        post_len = strlen(test->post_data);
+        post_data = HeapAlloc(GetProcessHeap(), 0, post_len);
+        memcpy(post_data, test->post_data, post_len);
+    }
     SetLastError(0xdeadbeef);
-    res = HttpSendRequestA(hor, (test->flags & TESTF_COMPRESSED) ? "Accept-Encoding: gzip, deflate" : "", -1, NULL, 0);
+    res = HttpSendRequestA(hor, test->headers, -1, post_data, post_len);
     if (flags & INTERNET_FLAG_ASYNC)
         ok(!res && (GetLastError() == ERROR_IO_PENDING),
             "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n");
@@ -395,6 +449,7 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
 
     if (flags & INTERNET_FLAG_ASYNC)
         WaitForSingleObject(hCompleteEvent, INFINITE);
+    HeapFree(GetProcessHeap(), 0, post_data);
 
     if(test->flags & TESTF_ALLOW_COOKIE) {
         CLEAR_NOTIFIED(INTERNET_STATUS_COOKIE_SENT);
@@ -402,10 +457,18 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     }
     if (first_connection_to_test_url)
     {
-        CHECK_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
-        CHECK_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
+        if (! proxy_active())
+        {
+            CHECK_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
+            CHECK_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
+        }
+        else
+        {
+            CLEAR_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
+            CLEAR_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
+        }
     }
-    else todo_wine
+    else
     {
         CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
         CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
@@ -418,8 +481,6 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
         CHECK_NOTIFIED(INTERNET_STATUS_REDIRECT);
     if (flags & INTERNET_FLAG_ASYNC)
         CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
-    else
-        CHECK_NOT_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
     /* Sent on WinXP only if first_connection_to_test_url is TRUE, on Win98 always sent */
     CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTING_TO_SERVER);
     CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTED_TO_SERVER);
@@ -474,9 +535,6 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
         if (flags & INTERNET_FLAG_ASYNC)
             SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
         res = InternetQueryDataAvailable(hor,&length,0x0,0x0);
-        ok(!(!res && length != 0),"InternetQueryDataAvailable failed with non-zero length\n");
-        ok(res || ((flags & INTERNET_FLAG_ASYNC) && GetLastError() == ERROR_IO_PENDING),
-           "InternetQueryDataAvailable failed, error %d\n", GetLastError());
         if (flags & INTERNET_FLAG_ASYNC)
         {
             if (res)
@@ -485,11 +543,22 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
             }
             else if (GetLastError() == ERROR_IO_PENDING)
             {
+                trace("PENDING\n");
+                /* on some tests, InternetQueryDataAvailable returns non-zero length and ERROR_IO_PENDING */
+                if(!(test->flags & TESTF_CHUNKED))
+                    ok(!length, "InternetQueryDataAvailable returned ERROR_IO_PENDING and %u length\n", length);
                 WaitForSingleObject(hCompleteEvent, INFINITE);
                 CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
                 continue;
+            }else {
+                ok(0, "InternetQueryDataAvailable failed: %u\n", GetLastError());
             }
+        }else {
+            ok(res, "InternetQueryDataAvailable failed: %u\n", GetLastError());
         }
+        trace("LENGTH %d\n", length);
+        if(test->flags & TESTF_CHUNKED)
+            ok(length <= 8192, "length = %d, expected <= 8192\n", length);
         if (length)
         {
             char *buffer;
@@ -501,10 +570,14 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
 
             trace("ReadFile -> %s %i\n",res?"TRUE":"FALSE",length);
 
+            if(test->content)
+                ok(!strcmp(buffer, test->content), "buffer = '%s', expected '%s'\n", buffer, test->content);
             HeapFree(GetProcessHeap(),0,buffer);
-        }
-        if (length == 0)
+        }else {
+            ok(!on_async, "Returned zero size in response to request complete\n");
             break;
+        }
+        on_async = FALSE;
     }
     if(test->flags & TESTF_REDIRECT) {
         CHECK_NOTIFIED2(INTERNET_STATUS_CLOSING_CONNECTION, 2);
@@ -512,44 +585,7 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
     }
 abort:
     trace("aborting\n");
-    SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
-    if (hor != 0x0) {
-        SET_WINE_ALLOW(INTERNET_STATUS_CLOSING_CONNECTION);
-        SET_WINE_ALLOW(INTERNET_STATUS_CONNECTION_CLOSED);
-        SetLastError(0xdeadbeef);
-        trace("closing\n");
-        res = InternetCloseHandle(hor);
-        ok (res, "InternetCloseHandle of handle opened by HttpOpenRequestA failed\n");
-        SetLastError(0xdeadbeef);
-        res = InternetCloseHandle(hor);
-        ok (!res, "Double close of handle opened by HttpOpenRequestA succeeded\n");
-        ok (GetLastError() == ERROR_INVALID_HANDLE,
-            "Double close of handle should have set ERROR_INVALID_HANDLE instead of %u\n",
-            GetLastError());
-    }
-    /* We intentionally do not close the handle opened by InternetConnectA as this
-     * tickles bug #9479: native closes child internet handles when the parent handles
-     * are closed. This is verified below by checking that the number of
-     * INTERNET_STATUS_HANDLE_CLOSING notifications matches the number expected. */
-    if (hi != 0x0) {
-      SET_WINE_ALLOW(INTERNET_STATUS_HANDLE_CLOSING);
-        trace("closing 2\n");
-      res = InternetCloseHandle(hi);
-      ok (res, "InternetCloseHandle of handle opened by InternetOpenA failed\n");
-      if (flags & INTERNET_FLAG_ASYNC)
-          Sleep(100);
-    }
-    CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
-    if (hor != 0x0) todo_wine
-    {
-        CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
-        CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
-    }
-    else
-    {
-        CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
-        CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
-    }
+    close_async_handle(hi, hCompleteEvent, 2);
     CloseHandle(hCompleteEvent);
     first_connection_to_test_url = FALSE;
 }
@@ -580,7 +616,7 @@ static void InternetReadFile_chunked_test(void)
     if (hic == 0x0) goto abort;
 
     trace("HttpOpenRequestA <--\n");
-    hor = HttpOpenRequestA(hic, "GET", "/testchunked", NULL, NULL, types,
+    hor = HttpOpenRequestA(hic, "GET", "/tests/chunked", NULL, NULL, types,
                            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE,
                            0xdeadbead);
     if (hor == 0x0 && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) {
@@ -614,8 +650,10 @@ static void InternetReadFile_chunked_test(void)
     res = HttpQueryInfoA(hor,HTTP_QUERY_TRANSFER_ENCODING,buffer,&length,0x0);
     buffer[length]=0;
     trace("Option TRANSFER_ENCODING -> %i  %s\n",res,buffer);
-    ok( res, "Failed to get TRANSFER_ENCODING option, error %u\n", GetLastError() );
-    ok( !strcmp( buffer, "chunked" ), "Wrong transfer encoding '%s'\n", buffer );
+    ok( res || ( proxy_active() && GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND ),
+        "Failed to get TRANSFER_ENCODING option, error %u\n", GetLastError() );
+    ok( !strcmp( buffer, "chunked" ) || ( ! res && proxy_active() && GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND ),
+        "Wrong transfer encoding '%s'\n", buffer );
 
     SetLastError( 0xdeadbeef );
     length = 16;
@@ -697,7 +735,7 @@ static void InternetReadFileExA_test(int flags)
     SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
 
     trace("HttpOpenRequestA <--\n");
-    hor = HttpOpenRequestA(hic, "GET", "/testredirect", NULL, NULL, types,
+    hor = HttpOpenRequestA(hic, "GET", "/tests/redirect", NULL, NULL, types,
                            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE,
                            0xdeadbead);
     if (hor == 0x0 && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) {
@@ -721,17 +759,8 @@ static void InternetReadFileExA_test(int flags)
     {
         SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME);
         SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED);
-        SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME);
-        SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED);
-    }
-    else
-    {
-        SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2);
-        SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2);
     }
-    SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER);
     SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
-    SET_WINE_ALLOW(INTERNET_STATUS_CONNECTED_TO_SERVER);
     SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
     SET_EXPECT2(INTERNET_STATUS_SENDING_REQUEST, 2);
     SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, 2);
@@ -766,7 +795,7 @@ static void InternetReadFileExA_test(int flags)
         CHECK_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
         CHECK_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
     }
-    else todo_wine
+    else
     {
         CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME);
         CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED);
@@ -810,8 +839,6 @@ static void InternetReadFileExA_test(int flags)
     inetbuffers.dwOffsetLow = 5678;
     SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE);
     SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED);
-    SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
-    SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
     rc = InternetReadFileEx(hor, &inetbuffers, 0, 0xdeadcafe);
     ok(rc, "InternetReadFileEx failed with error %u\n", GetLastError());
         trace("read %i bytes\n", inetbuffers.dwBufferLength);
@@ -829,8 +856,6 @@ static void InternetReadFileExA_test(int flags)
     length = 0;
     trace("Entering Query loop\n");
 
-    SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
-    SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
     while (TRUE)
     {
         inetbuffers.dwStructSize = sizeof(INTERNET_BUFFERS);
@@ -841,8 +866,6 @@ static void InternetReadFileExA_test(int flags)
 
         SET_WINE_ALLOW(INTERNET_STATUS_RECEIVING_RESPONSE);
         SET_WINE_ALLOW(INTERNET_STATUS_RESPONSE_RECEIVED);
-        SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
-        SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
         SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
         rc = InternetReadFileExA(hor, &inetbuffers, IRF_ASYNC | IRF_USE_CONTEXT, 0xcafebabe);
         if (!rc)
@@ -899,37 +922,8 @@ static void InternetReadFileExA_test(int flags)
     ok(length > 0, "failed to read any of the document\n");
     trace("Finished. Read %d bytes\n", length);
 
-    /* WinXP does not send, but Win98 does */
-    CLEAR_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
-    CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
 abort:
-    SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
-    if (hor) {
-        SET_WINE_ALLOW(INTERNET_STATUS_CLOSING_CONNECTION);
-        SET_WINE_ALLOW(INTERNET_STATUS_CONNECTION_CLOSED);
-        rc = InternetCloseHandle(hor);
-        ok ((rc != 0), "InternetCloseHandle of handle opened by HttpOpenRequestA failed\n");
-        rc = InternetCloseHandle(hor);
-        ok ((rc == 0), "Double close of handle opened by HttpOpenRequestA succeeded\n");
-    }
-    if (hic) {
-        rc = InternetCloseHandle(hic);
-        ok ((rc != 0), "InternetCloseHandle of handle opened by InternetConnectA failed\n");
-    }
-    if (hi) {
-      SET_WINE_ALLOW(INTERNET_STATUS_HANDLE_CLOSING);
-      rc = InternetCloseHandle(hi);
-      ok ((rc != 0), "InternetCloseHandle of handle opened by InternetOpenA failed\n");
-      if (flags & INTERNET_FLAG_ASYNC)
-          Sleep(100);
-      CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0));
-    }
-    /* to enable once Wine is fixed to never send it
-    CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
-    CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
-    */
-    CLEAR_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
-    CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
+    close_async_handle(hi, hCompleteEvent, 2);
     CloseHandle(hCompleteEvent);
     first_connection_to_test_url = FALSE;
 }
@@ -1024,7 +1018,7 @@ static void HttpSendRequestEx_test(void)
     szBuffer[dwBytesRead] = 0;
 
     ok(dwBytesRead == 13,"Read %u bytes instead of 13\n",dwBytesRead);
-    ok(strncmp(szBuffer,"mode => Test\n",dwBytesRead)==0,"Got string %s\n",szBuffer);
+    ok(strncmp(szBuffer,"mode => Test\n",dwBytesRead)==0 || broken(proxy_active()),"Got string %s\n",szBuffer);
 
     ok(InternetCloseHandle(hRequest), "Close request handle failed\n");
 done:
@@ -1099,7 +1093,7 @@ static void test_http_cache(void)
                               INTERNET_SERVICE_HTTP, 0, 0);
     ok(connect != NULL, "Unable to connect to http://test.winehq.org with error %d\n", GetLastError());
 
-    request = HttpOpenRequestA(connect, NULL, "/hello.html", NULL, NULL, types, INTERNET_FLAG_NEED_FILE, 0);
+    request = HttpOpenRequestA(connect, NULL, "/tests/hello.html", NULL, NULL, types, INTERNET_FLAG_NEED_FILE, 0);
     if (!request && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED)
     {
         skip( "Network unreachable, skipping test\n" );
@@ -1114,7 +1108,7 @@ static void test_http_cache(void)
     size = sizeof(url);
     ret = InternetQueryOptionA(request, INTERNET_OPTION_URL, url, &size);
     ok(ret, "InternetQueryOptionA(INTERNET_OPTION_URL) failed: %u\n", GetLastError());
-    ok(!strcmp(url, "http://test.winehq.org/hello.html"), "Wrong URL %s\n", url);
+    ok(!strcmp(url, "http://test.winehq.org/tests/hello.html"), "Wrong URL %s\n", url);
 
     size = sizeof(file_name);
     ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size);
@@ -1151,6 +1145,19 @@ static void test_http_cache(void)
     ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
     CloseHandle(file);
 
+    /* Send the same request, requiring it to be retrieved from the cache */
+    request = HttpOpenRequest(connect, "GET", "/tests/hello.html", NULL, NULL, NULL, INTERNET_FLAG_FROM_CACHE, 0);
+
+    ret = HttpSendRequest(request, NULL, 0, NULL, 0);
+    ok(ret, "HttpSendRequest failed\n");
+
+    size = sizeof(buf);
+    ret = InternetReadFile(request, buf, sizeof(buf), &size);
+    ok(ret, "InternetReadFile failed: %u\n", GetLastError());
+    ok(size == 100, "size = %u\n", size);
+
+    ok(InternetCloseHandle(request), "Close request handle failed\n");
+
     request = HttpOpenRequestA(connect, NULL, "/", NULL, NULL, types, INTERNET_FLAG_NO_CACHE_WRITE, 0);
     ok(request != NULL, "Failed to open request handle err %u\n", GetLastError());
 
@@ -1551,6 +1558,7 @@ static const char page1[] =
 struct server_info {
     HANDLE hEvent;
     int port;
+    int num_testH_retrievals;
 };
 
 static DWORD CALLBACK server_thread(LPVOID param)
@@ -1741,6 +1749,29 @@ static DWORD CALLBACK server_thread(LPVOID param)
         {
             send(c, page1, sizeof page1-1, 0);
         }
+        if (strstr(buffer, "GET /testH"))
+        {
+            si->num_testH_retrievals++;
+            if (!strstr(buffer, "Content-Length: 0"))
+            {
+                send(c, okmsg, sizeof okmsg-1, 0);
+                send(c, page1, sizeof page1-1, 0);
+            }
+            else
+                send(c, notokmsg, sizeof notokmsg-1, 0);
+        }
+        if (strstr(buffer, "GET /test_no_content"))
+        {
+            static const char nocontentmsg[] = "HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n";
+            send(c, nocontentmsg, sizeof(nocontentmsg)-1, 0);
+        }
+        if (strstr(buffer, "GET /test_conn_close"))
+        {
+            static const char conn_close_response[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nsome content";
+            send(c, conn_close_response, sizeof(conn_close_response)-1, 0);
+            WaitForSingleObject(conn_close_event, INFINITE);
+            trace("closing connection\n");
+        }
 
         shutdown(c, 2);
         closesocket(c);
@@ -1771,10 +1802,11 @@ static void test_basic_request(int port, const char *verb, const char *url)
 
     count = 0;
     memset(buffer, 0, sizeof buffer);
+    SetLastError(0xdeadbeef);
     r = InternetReadFile(hr, buffer, sizeof buffer, &count);
-    ok(r, "InternetReadFile failed\n");
+    ok(r, "InternetReadFile failed %u\n", GetLastError());
     ok(count == sizeof page1 - 1, "count was wrong\n");
-    ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n");
+    ok(!memcmp(buffer, page1, sizeof page1), "http data wrong, got: %s\n", buffer);
 
     InternetCloseHandle(hr);
     InternetCloseHandle(hc);
@@ -2092,6 +2124,141 @@ static void test_http1_1(int port)
     InternetCloseHandle(ses);
 }
 
+static void test_no_content(int port)
+{
+    HINTERNET session, connection, req;
+    DWORD res;
+
+    trace("Testing 204 no content response...\n");
+
+    hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    session = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);
+    ok(session != NULL,"InternetOpen failed with error %u\n", GetLastError());
+
+    pInternetSetStatusCallbackA(session, callback);
+
+    SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
+    connection = InternetConnectA(session, "localhost", port,
+            NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef);
+    ok(connection != NULL,"InternetConnect failed with error %u\n", GetLastError());
+    CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED);
+
+    SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
+    req = HttpOpenRequestA(connection, "GET", "/test_no_content", NULL, NULL, NULL,
+            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE, 0xdeadbead);
+    ok(req != NULL, "HttpOpenRequest failed: %u\n", GetLastError());
+    CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED);
+
+    SET_OPTIONAL(INTERNET_STATUS_COOKIE_SENT);
+    SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
+    SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
+    SET_EXPECT(INTERNET_STATUS_SENDING_REQUEST);
+    SET_EXPECT(INTERNET_STATUS_REQUEST_SENT);
+    SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE);
+    SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED);
+    SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
+    SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
+    SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
+
+    res = HttpSendRequestA(req, NULL, -1, NULL, 0);
+    ok(!res && (GetLastError() == ERROR_IO_PENDING),
+       "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n");
+    WaitForSingleObject(hCompleteEvent, INFINITE);
+
+    CLEAR_NOTIFIED(INTERNET_STATUS_COOKIE_SENT);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTING_TO_SERVER);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTED_TO_SERVER);
+    CHECK_NOTIFIED(INTERNET_STATUS_SENDING_REQUEST);
+    CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_SENT);
+    CHECK_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE);
+    CHECK_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED);
+    CHECK_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
+    CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
+
+    close_async_handle(session, hCompleteEvent, 2);
+    CloseHandle(hCompleteEvent);
+}
+
+static void test_conn_close(int port)
+{
+    HINTERNET session, connection, req;
+    DWORD res, avail, size;
+    BYTE buf[1024];
+
+    trace("Testing connection close connection...\n");
+
+    hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    conn_close_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+    session = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);
+    ok(session != NULL,"InternetOpen failed with error %u\n", GetLastError());
+
+    pInternetSetStatusCallbackA(session, callback);
+
+    SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
+    connection = InternetConnectA(session, "localhost", port,
+            NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef);
+    ok(connection != NULL,"InternetConnect failed with error %u\n", GetLastError());
+    CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED);
+
+    SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED);
+    req = HttpOpenRequestA(connection, "GET", "/test_conn_close", NULL, NULL, NULL,
+            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE, 0xdeadbead);
+    ok(req != NULL, "HttpOpenRequest failed: %u\n", GetLastError());
+    CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED);
+
+    SET_OPTIONAL(INTERNET_STATUS_COOKIE_SENT);
+    SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
+    SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
+    SET_EXPECT(INTERNET_STATUS_SENDING_REQUEST);
+    SET_EXPECT(INTERNET_STATUS_REQUEST_SENT);
+    SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE);
+    SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED);
+    SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
+
+    res = HttpSendRequestA(req, NULL, -1, NULL, 0);
+    ok(!res && (GetLastError() == ERROR_IO_PENDING),
+       "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n");
+    WaitForSingleObject(hCompleteEvent, INFINITE);
+
+    CLEAR_NOTIFIED(INTERNET_STATUS_COOKIE_SENT);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTING_TO_SERVER);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTED_TO_SERVER);
+    CHECK_NOTIFIED(INTERNET_STATUS_SENDING_REQUEST);
+    CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_SENT);
+    CHECK_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE);
+    CHECK_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED);
+    CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
+
+    avail = 0;
+    res = InternetQueryDataAvailable(req, &avail, 0, 0);
+    ok(res, "InternetQueryDataAvailable failed: %u\n", GetLastError());
+    ok(avail != 0, "avail = 0\n");
+
+    size = 0;
+    res = InternetReadFile(req, buf, avail, &size);
+    ok(res, "InternetReadFile failed: %u\n", GetLastError());
+
+    res = InternetQueryDataAvailable(req, &avail, 0, 0);
+    ok(!res && (GetLastError() == ERROR_IO_PENDING),
+       "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n");
+    ok(!avail, "avail = %u, expected 0\n", avail);
+
+    SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
+    SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
+    SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE);
+    SetEvent(conn_close_event);
+    WaitForSingleObject(hCompleteEvent, INFINITE);
+    CHECK_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
+    CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE);
+
+    close_async_handle(session, hCompleteEvent, 2);
+    CloseHandle(hCompleteEvent);
+}
+
 static void test_HttpSendRequestW(int port)
 {
     static const WCHAR header[] = {'U','A','-','C','P','U',':',' ','x','8','6',0};
@@ -2523,6 +2690,70 @@ static void test_options(int port)
     InternetCloseHandle(ses);
 }
 
+static void test_url_caching(int port, int *num_retrievals)
+{
+    HINTERNET hi, hc, hr;
+    DWORD r, count;
+    char buffer[0x100];
+
+    ok(*num_retrievals == 0, "expected 0 retrievals prior to test\n");
+
+    hi = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+    ok(hi != NULL, "open failed\n");
+
+    hc = InternetConnect(hi, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
+    ok(hc != NULL, "connect failed\n");
+
+    /* Pre-load the cache: */
+    hr = HttpOpenRequest(hc, "GET", "/testH", NULL, NULL, NULL, 0, 0);
+    ok(hr != NULL, "HttpOpenRequest failed\n");
+
+    r = HttpSendRequest(hr, NULL, 0, NULL, 0);
+    ok(r, "HttpSendRequest failed\n");
+
+    ok(*num_retrievals == 1, "expected 1 retrievals, got %d\n", *num_retrievals);
+
+    count = 0;
+    memset(buffer, 0, sizeof buffer);
+    SetLastError(0xdeadbeef);
+    r = InternetReadFile(hr, buffer, sizeof buffer, &count);
+    ok(r, "InternetReadFile failed %u\n", GetLastError());
+    ok(count == sizeof page1 - 1, "count was wrong\n");
+    ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n");
+
+    InternetCloseHandle(hr);
+
+    /* Send the same request, requiring it to be retrieved from the cache */
+    hr = HttpOpenRequest(hc, "GET", "/testH", NULL, NULL, NULL, INTERNET_FLAG_FROM_CACHE, 0);
+    ok(hr != NULL, "HttpOpenRequest failed\n");
+
+    r = HttpSendRequest(hr, NULL, 0, NULL, 0);
+    /* Older Windows versions succeed with this request, newer ones fail with
+     * ERROR_FILE_NOT_FOUND.  Accept either, as the older version allows us
+     * to verify that the server isn't contacted.
+     */
+    if (!r)
+        ok(GetLastError() == ERROR_FILE_NOT_FOUND,
+           "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+    else
+    {
+        /* The server shouldn't be contacted for this request. */
+        todo_wine
+        ok(*num_retrievals == 1, "expected 1 retrievals\n");
+
+        count = 0;
+        memset(buffer, 0, sizeof buffer);
+        SetLastError(0xdeadbeef);
+        r = InternetReadFile(hr, buffer, sizeof buffer, &count);
+        ok(r, "InternetReadFile failed %u\n", GetLastError());
+        ok(count == sizeof page1 - 1, "count was wrong\n");
+        ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n");
+    }
+
+    InternetCloseHandle(hc);
+    InternetCloseHandle(hi);
+}
+
 static void test_http_connection(void)
 {
     struct server_info si;
@@ -2531,6 +2762,7 @@ static void test_http_connection(void)
 
     si.hEvent = CreateEvent(NULL, 0, 0, NULL);
     si.port = 7531;
+    si.num_testH_retrievals = 0;
 
     hThread = CreateThread(NULL, 0, server_thread, (LPVOID) &si, 0, &id);
     ok( hThread != NULL, "create thread failed\n");
@@ -2559,6 +2791,9 @@ static void test_http_connection(void)
     test_HttpSendRequestW(si.port);
     test_last_error(si.port);
     test_options(si.port);
+    test_url_caching(si.port, &si.num_testH_retrievals);
+    test_no_content(si.port);
+    test_conn_close(si.port);
 
     /* send the basic request again to shutdown the server thread */
     test_basic_request(si.port, "GET", "/quit");
@@ -2568,6 +2803,195 @@ static void test_http_connection(void)
     CloseHandle(hThread);
 }
 
+static void release_cert_info(INTERNET_CERTIFICATE_INFOA *info)
+{
+    LocalFree(info->lpszSubjectInfo);
+    LocalFree(info->lpszIssuerInfo);
+    LocalFree(info->lpszProtocolName);
+    LocalFree(info->lpszSignatureAlgName);
+    LocalFree(info->lpszEncryptionAlgName);
+}
+
+static void test_secure_connection(void)
+{
+    static const WCHAR gizmo5[] = {'G','i','z','m','o','5',0};
+    static const WCHAR testbot[] = {'t','e','s','t','b','o','t','.','w','i','n','e','h','q','.','o','r','g',0};
+    static const WCHAR get[] = {'G','E','T',0};
+    static const WCHAR slash[] = {'/',0};
+    HINTERNET ses, con, req;
+    DWORD size, flags;
+    INTERNET_CERTIFICATE_INFOA *certificate_structA = NULL;
+    INTERNET_CERTIFICATE_INFOW *certificate_structW = NULL;
+    BOOL ret;
+
+    ses = InternetOpen("Gizmo5", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+    ok(ses != NULL, "InternetOpen failed\n");
+
+    con = InternetConnect(ses, "testbot.winehq.org",
+                          INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL,
+                          INTERNET_SERVICE_HTTP, 0, 0);
+    ok(con != NULL, "InternetConnect failed\n");
+
+    req = HttpOpenRequest(con, "GET", "/", NULL, NULL, NULL,
+                          INTERNET_FLAG_SECURE, 0);
+    ok(req != NULL, "HttpOpenRequest failed\n");
+
+    ret = HttpSendRequest(req, NULL, 0, NULL, 0);
+    ok(ret, "HttpSendRequest failed: %d\n", GetLastError());
+
+    size = sizeof(flags);
+    ret = InternetQueryOption(req, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size);
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(flags & SECURITY_FLAG_SECURE, "expected secure flag to be set\n");
+
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               NULL, &size);
+    ok(ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(size == sizeof(INTERNET_CERTIFICATE_INFOA), "size = %d\n", size);
+    certificate_structA = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = InternetQueryOption(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                              certificate_structA, &size);
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    if (ret)
+    {
+        ok(certificate_structA->lpszSubjectInfo &&
+           strlen(certificate_structA->lpszSubjectInfo) > 1,
+           "expected a non-empty subject name\n");
+        ok(certificate_structA->lpszIssuerInfo &&
+           strlen(certificate_structA->lpszIssuerInfo) > 1,
+           "expected a non-empty issuer name\n");
+        ok(!certificate_structA->lpszSignatureAlgName,
+           "unexpected signature algorithm name\n");
+        ok(!certificate_structA->lpszEncryptionAlgName,
+           "unexpected encryption algorithm name\n");
+        ok(!certificate_structA->lpszProtocolName,
+           "unexpected protocol name\n");
+        ok(certificate_structA->dwKeySize, "expected a non-zero key size\n");
+        release_cert_info(certificate_structA);
+    }
+    HeapFree(GetProcessHeap(), 0, certificate_structA);
+
+    /* Querying the same option through InternetQueryOptionW still results in
+     * ASCII strings being returned.
+     */
+    size = 0;
+    ret = InternetQueryOptionW(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               NULL, &size);
+    ok(ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(size == sizeof(INTERNET_CERTIFICATE_INFOW), "size = %d\n", size);
+    certificate_structW = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = InternetQueryOption(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                              certificate_structW, &size);
+    certificate_structA = (INTERNET_CERTIFICATE_INFOA *)certificate_structW;
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    if (ret)
+    {
+        ok(certificate_structA->lpszSubjectInfo &&
+           strlen(certificate_structA->lpszSubjectInfo) > 1,
+           "expected a non-empty subject name\n");
+        ok(certificate_structA->lpszIssuerInfo &&
+           strlen(certificate_structA->lpszIssuerInfo) > 1,
+           "expected a non-empty issuer name\n");
+        ok(!certificate_structA->lpszSignatureAlgName,
+           "unexpected signature algorithm name\n");
+        ok(!certificate_structA->lpszEncryptionAlgName,
+           "unexpected encryption algorithm name\n");
+        ok(!certificate_structA->lpszProtocolName,
+           "unexpected protocol name\n");
+        ok(certificate_structA->dwKeySize, "expected a non-zero key size\n");
+        release_cert_info(certificate_structA);
+    }
+    HeapFree(GetProcessHeap(), 0, certificate_structW);
+
+    InternetCloseHandle(req);
+    InternetCloseHandle(con);
+    InternetCloseHandle(ses);
+
+    /* Repeating the tests with the W functions has the same result: */
+    ses = InternetOpenW(gizmo5, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+    ok(ses != NULL, "InternetOpen failed\n");
+
+    con = InternetConnectW(ses, testbot,
+                          INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL,
+                          INTERNET_SERVICE_HTTP, 0, 0);
+    ok(con != NULL, "InternetConnect failed\n");
+
+    req = HttpOpenRequestW(con, get, slash, NULL, NULL, NULL,
+                          INTERNET_FLAG_SECURE, 0);
+    ok(req != NULL, "HttpOpenRequest failed\n");
+
+    ret = HttpSendRequest(req, NULL, 0, NULL, 0);
+    ok(ret, "HttpSendRequest failed: %d\n", GetLastError());
+
+    size = sizeof(flags);
+    ret = InternetQueryOption(req, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size);
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(flags & SECURITY_FLAG_SECURE, "expected secure flag to be set\n");
+
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               NULL, &size);
+    ok(ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(size == sizeof(INTERNET_CERTIFICATE_INFOA), "size = %d\n", size);
+    certificate_structA = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = InternetQueryOptionW(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               certificate_structA, &size);
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    if (ret)
+    {
+        ok(certificate_structA->lpszSubjectInfo &&
+           strlen(certificate_structA->lpszSubjectInfo) > 1,
+           "expected a non-empty subject name\n");
+        ok(certificate_structA->lpszIssuerInfo &&
+           strlen(certificate_structA->lpszIssuerInfo) > 1,
+           "expected a non-empty issuer name\n");
+        ok(!certificate_structA->lpszSignatureAlgName,
+           "unexpected signature algorithm name\n");
+        ok(!certificate_structA->lpszEncryptionAlgName,
+           "unexpected encryption algorithm name\n");
+        ok(!certificate_structA->lpszProtocolName,
+           "unexpected protocol name\n");
+        ok(certificate_structA->dwKeySize, "expected a non-zero key size\n");
+        release_cert_info(certificate_structA);
+    }
+    HeapFree(GetProcessHeap(), 0, certificate_structA);
+
+    /* Again, querying the same option through InternetQueryOptionW still
+     * results in ASCII strings being returned.
+     */
+    size = 0;
+    ret = InternetQueryOptionW(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               NULL, &size);
+    ok(ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER, "InternetQueryOption failed: %d\n", GetLastError());
+    ok(size == sizeof(INTERNET_CERTIFICATE_INFOW), "size = %d\n", size);
+    certificate_structW = HeapAlloc(GetProcessHeap(), 0, size);
+    ret = InternetQueryOptionW(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
+                               certificate_structW, &size);
+    certificate_structA = (INTERNET_CERTIFICATE_INFOA *)certificate_structW;
+    ok(ret, "InternetQueryOption failed: %d\n", GetLastError());
+    if (ret)
+    {
+        ok(certificate_structA->lpszSubjectInfo &&
+           strlen(certificate_structA->lpszSubjectInfo) > 1,
+           "expected a non-empty subject name\n");
+        ok(certificate_structA->lpszIssuerInfo &&
+           strlen(certificate_structA->lpszIssuerInfo) > 1,
+           "expected a non-empty issuer name\n");
+        ok(!certificate_structA->lpszSignatureAlgName,
+           "unexpected signature algorithm name\n");
+        ok(!certificate_structA->lpszEncryptionAlgName,
+           "unexpected encryption algorithm name\n");
+        ok(!certificate_structA->lpszProtocolName,
+           "unexpected protocol name\n");
+        ok(certificate_structA->dwKeySize, "expected a non-zero key size\n");
+        release_cert_info(certificate_structA);
+    }
+    HeapFree(GetProcessHeap(), 0, certificate_structW);
+
+    InternetCloseHandle(req);
+    InternetCloseHandle(con);
+    InternetCloseHandle(ses);
+}
+
 static void test_user_agent_header(void)
 {
     HINTERNET ses, con, req;
@@ -2575,13 +2999,13 @@ static void test_user_agent_header(void)
     char buffer[64];
     BOOL ret;
 
-    ses = InternetOpen("Gizmo5", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+    ses = InternetOpen("Gizmo5", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
     ok(ses != NULL, "InternetOpen failed\n");
 
     con = InternetConnect(ses, "test.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
     ok(con != NULL, "InternetConnect failed\n");
 
-    req = HttpOpenRequest(con, "GET", "/hello.html", "HTTP/1.0", NULL, NULL, 0, 0);
+    req = HttpOpenRequest(con, "GET", "/tests/hello.html", "HTTP/1.0", NULL, NULL, 0, 0);
     ok(req != NULL, "HttpOpenRequest failed\n");
 
     size = sizeof(buffer);
@@ -2827,8 +3251,8 @@ static const struct notification async_send_request_ex_test[] =
     { internet_connect,      INTERNET_STATUS_HANDLE_CREATED, 0 },
     { http_open_request,     INTERNET_STATUS_HANDLE_CREATED, 0 },
     { http_send_request_ex,  INTERNET_STATUS_DETECTING_PROXY, 1, 0, 1 },
-    { http_send_request_ex,  INTERNET_STATUS_RESOLVING_NAME, 1 },
-    { http_send_request_ex,  INTERNET_STATUS_NAME_RESOLVED, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_RESOLVING_NAME, 1, 0, 1 },
+    { http_send_request_ex,  INTERNET_STATUS_NAME_RESOLVED, 1, 0, 1 },
     { http_send_request_ex,  INTERNET_STATUS_CONNECTING_TO_SERVER, 1 },
     { http_send_request_ex,  INTERNET_STATUS_CONNECTED_TO_SERVER, 1 },
     { http_send_request_ex,  INTERNET_STATUS_SENDING_REQUEST, 1 },
@@ -2839,8 +3263,10 @@ static const struct notification async_send_request_ex_test[] =
     { http_end_request,      INTERNET_STATUS_RECEIVING_RESPONSE, 1 },
     { http_end_request,      INTERNET_STATUS_RESPONSE_RECEIVED, 1 },
     { http_end_request,      INTERNET_STATUS_REQUEST_COMPLETE, 1 },
-    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, 1 },
-    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, 1 }
+    { internet_close_handle, INTERNET_STATUS_CLOSING_CONNECTION, 0, 0, 1 },
+    { internet_close_handle, INTERNET_STATUS_CONNECTION_CLOSED, 0, 0, 1 },
+    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, },
+    { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, }
 };
 
 static void test_async_HttpSendRequestEx(void)
@@ -2934,11 +3360,74 @@ static void test_async_HttpSendRequestEx(void)
     CloseHandle( info.wait );
 }
 
-#define STATUS_STRING(status) \
-    memcpy(status_string[status], #status, sizeof(CHAR) * \
-           (strlen(#status) < MAX_STATUS_NAME ? \
-            strlen(#status) : \
-            MAX_STATUS_NAME - 1))
+static HINTERNET closetest_session, closetest_req, closetest_conn;
+static BOOL closetest_closed;
+
+static void WINAPI closetest_callback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
+     LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
+{
+    DWORD len, type;
+    BOOL res;
+
+    trace("closetest_callback %p: %d\n", hInternet, dwInternetStatus);
+
+    ok(hInternet == closetest_session || hInternet == closetest_conn || hInternet == closetest_req,
+       "Unexpected hInternet %p\n", hInternet);
+    if(!closetest_closed)
+        return;
+
+    len = sizeof(type);
+    res = InternetQueryOptionA(closetest_req, INTERNET_OPTION_HANDLE_TYPE, &type, &len);
+    ok(!res && GetLastError() == ERROR_INVALID_HANDLE,
+       "InternetQueryOptionA(%p INTERNET_OPTION_HANDLE_TYPE) failed: %x %u, expected TRUE ERROR_INVALID_HANDLE\n",
+       closetest_req, res, GetLastError());
+}
+
+static void test_InternetCloseHandle(void)
+{
+    DWORD len, flags;
+    BOOL res;
+
+    closetest_session = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);
+    ok(closetest_session != NULL,"InternetOpen failed with error %u\n", GetLastError());
+
+    pInternetSetStatusCallbackA(closetest_session, closetest_callback);
+
+    closetest_conn = InternetConnectA(closetest_session, "source.winehq.org", INTERNET_INVALID_PORT_NUMBER,
+            NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef);
+    ok(closetest_conn != NULL,"InternetConnect failed with error %u\n", GetLastError());
+
+    closetest_req = HttpOpenRequestA(closetest_conn, "GET", "winegecko.php", NULL, NULL, NULL,
+            INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE, 0xdeadbead);
+
+    res = HttpSendRequestA(closetest_req, NULL, -1, NULL, 0);
+    ok(!res && (GetLastError() == ERROR_IO_PENDING),
+       "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n");
+
+    len = sizeof(flags);
+    res = InternetQueryOptionA(closetest_req, INTERNET_OPTION_REQUEST_FLAGS, &flags, &len);
+    ok(res, "InternetQueryOptionA(%p INTERNET_OPTION_URL) failed: %u\n", closetest_req, GetLastError());
+
+    res = InternetCloseHandle(closetest_session);
+    ok(res, "InternetCloseHandle failed: %u\n", GetLastError());
+    closetest_closed = TRUE;
+    trace("Closed session handle\n");
+
+    res = InternetCloseHandle(closetest_conn);
+    ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "InternetCloseConnection(conn) failed: %x %u\n",
+       res, GetLastError());
+
+    res = InternetCloseHandle(closetest_req);
+    ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "InternetCloseConnection(req) failed: %x %u\n",
+       res, GetLastError());
+
+    len = sizeof(flags);
+    res = InternetQueryOptionA(closetest_req, INTERNET_OPTION_REQUEST_FLAGS, &flags, &len);
+    ok(!res && GetLastError() == ERROR_INVALID_HANDLE,
+       "InternetQueryOptionA(%p INTERNET_OPTION_URL) failed: %x %u, expected TRUE ERROR_INVALID_HANDLE\n",
+       closetest_req, res, GetLastError());
+}
+
 static void init_status_tests(void)
 {
     memset(expect, 0, sizeof(expect));
@@ -2946,6 +3435,8 @@ static void init_status_tests(void)
     memset(wine_allow, 0, sizeof(wine_allow));
     memset(notified, 0, sizeof(notified));
     memset(status_string, 0, sizeof(status_string));
+
+#define STATUS_STRING(status) status_string[status] = #status
     STATUS_STRING(INTERNET_STATUS_RESOLVING_NAME);
     STATUS_STRING(INTERNET_STATUS_NAME_RESOLVED);
     STATUS_STRING(INTERNET_STATUS_CONNECTING_TO_SERVER);
@@ -2972,36 +3463,41 @@ static void init_status_tests(void)
     STATUS_STRING(INTERNET_STATUS_P3P_HEADER);
     STATUS_STRING(INTERNET_STATUS_P3P_POLICYREF);
     STATUS_STRING(INTERNET_STATUS_COOKIE_HISTORY);
-}
 #undef STATUS_STRING
+}
 
 START_TEST(http)
 {
     HMODULE hdll;
     hdll = GetModuleHandleA("wininet.dll");
-    pInternetSetStatusCallbackA = (void*)GetProcAddress(hdll, "InternetSetStatusCallbackA");
 
-    if (!pInternetSetStatusCallbackA)
-        skip("skipping the InternetReadFile tests\n");
-    else
-    {
-        init_status_tests();
-        InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[0]);
-        InternetReadFile_test(0, &test_data[0]);
-        first_connection_to_test_url = TRUE;
-        InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[1]);
-        InternetReadFile_test(0, &test_data[1]);
-        InternetReadFileExA_test(INTERNET_FLAG_ASYNC);
-        test_open_url_async();
-        test_async_HttpSendRequestEx();
+    if(!GetProcAddress(hdll, "InternetGetCookieExW")) {
+        win_skip("Too old IE (older than 6.0)\n");
+        return;
     }
+
+    pInternetSetStatusCallbackA = (void*)GetProcAddress(hdll, "InternetSetStatusCallbackA");
+
+    init_status_tests();
+    test_InternetCloseHandle();
+    InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[0]);
+    InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[1]);
+    InternetReadFile_test(0, &test_data[1]);
+    first_connection_to_test_url = TRUE;
+    InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[2]);
+    InternetReadFile_test(0, &test_data[2]);
+    InternetReadFileExA_test(INTERNET_FLAG_ASYNC);
+    test_open_url_async();
+    test_async_HttpSendRequestEx();
     InternetOpenRequest_test();
     test_http_cache();
     InternetOpenUrlA_test();
     HttpHeaders_test();
     test_http_connection();
+    test_secure_connection();
     test_user_agent_header();
     test_bogus_accept_types_array();
     InternetReadFile_chunked_test();
     HttpSendRequestEx_test();
+    InternetReadFile_test(INTERNET_FLAG_ASYNC, &test_data[3]);
 }