[WININET_WINETEST] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / modules / rostests / winetests / wininet / http.c
index 1c5cbfe..de34a37 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -172,7 +173,7 @@ static BOOL (WINAPI *pInternetGetSecurityInfoByURLA)(LPSTR,PCCERT_CHAIN_CONTEXT*
 static int strcmp_wa(LPCWSTR strw, const char *stra)
 {
     WCHAR buf[512];
-    MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, ARRAY_SIZE(buf));
     return lstrcmpW(strw, buf);
 }
 
@@ -723,8 +724,11 @@ static void InternetReadFile_test(int flags, const test_data_t *test)
 
     length = sizeof(buffer)-2;
     memset(buffer, 0x77, sizeof(buffer));
+    SetLastError(0xdeadbeef);
     res = HttpQueryInfoA(hor,HTTP_QUERY_RAW_HEADERS,buffer,&length,0x0);
     ok(res, "HttpQueryInfoA(HTTP_QUERY_RAW_HEADERS) failed with error %d\n", GetLastError());
+    ok(GetLastError() == 0 ||
+                broken(GetLastError() == 0xdeadbeef /* XP/W2K3 */), "Last Error not reset %u\n", GetLastError());
     /* show that the function writes data past the length returned */
     ok(buffer[length-2], "Expected any header character, got 0x00\n");
     ok(!buffer[length-1], "Expected 0x00, got %02X\n", buffer[length-1]);
@@ -985,7 +989,10 @@ static void InternetReadFile_chunked_test(void)
         {
             char *buffer = HeapAlloc(GetProcessHeap(),0,length+1);
 
+            SetLastError(0xdeadbeef);
             res = InternetReadFile(hor,buffer,length,&got);
+            ok(GetLastError() == 0 ||
+                broken(GetLastError() == 0xdeadbeef /* XP/W2K3 */), "Last Error not reset %u\n", GetLastError());
 
             buffer[got]=0;
             trace("ReadFile -> %i %i\n",res,got);
@@ -998,8 +1005,11 @@ static void InternetReadFile_chunked_test(void)
         if (length == 0)
         {
             got = 0xdeadbeef;
+            SetLastError(0xdeadbeef);
             res = InternetReadFile( hor, buffer, 1, &got );
             ok( res, "InternetReadFile failed: %u\n", GetLastError() );
+            ok(GetLastError() == 0 ||
+                broken(GetLastError() == 0xdeadbeef /* XP/W2K3 */), "Last Error not reset %u\n", GetLastError());
             ok( !got, "got %u\n", got );
             break;
         }
@@ -2044,6 +2054,11 @@ static const char okmsg[] =
 "Server: winetest\r\n"
 "\r\n";
 
+static const char okmsg201[] =
+"HTTP/1.1 201 OK\r\n"
+"Server: winetest\r\n"
+"\r\n";
+
 static const char okmsg2[] =
 "HTTP/1.1 200 OK\r\n"
 "Date: Mon, 01 Dec 2008 13:44:34 GMT\r\n"
@@ -2053,6 +2068,12 @@ static const char okmsg2[] =
 "Set-Cookie: two\r\n"
 "\r\n";
 
+static DWORD64 content_length;
+static const char largemsg[] =
+"HTTP/1.1 200 OK\r\n"
+"Content-Length: %I64u\r\n"
+"\r\n";
+
 static const char okmsg_cookie_path[] =
 "HTTP/1.1 200 OK\r\n"
 "Date: Mon, 01 Dec 2008 13:44:34 GMT\r\n"
@@ -2432,6 +2453,22 @@ static DWORD CALLBACK server_thread(LPVOID param)
             else
                 send(c, notokmsg, sizeof notokmsg-1, 0);
         }
+        if (strstr(buffer, "HEAD /upload3.txt"))
+        {
+            if (strstr(buffer, "Authorization: Basic dXNlcjE6cHdkMQ=="))
+                send(c, okmsg, sizeof okmsg-1, 0);
+            else
+                send(c, noauthmsg, sizeof noauthmsg-1, 0);
+        }
+        if (strstr(buffer, "HEAD /upload4.txt"))
+        {
+            if (strstr(buffer, "Authorization: Bearer dXNlcjE6cHdkMQ=="))
+                send(c, okmsg, sizeof okmsg-1, 0);
+            else if (strstr(buffer, "Authorization: Basic dXNlcjpwd2Q="))
+                send(c, okmsg201, sizeof okmsg-1, 0);
+            else
+                send(c, noauthmsg, sizeof noauthmsg-1, 0);
+        }
         if (strstr(buffer, "/test_cookie_path1"))
         {
             if (strstr(buffer, "subcookie=data"))
@@ -2508,6 +2545,13 @@ static DWORD CALLBACK server_thread(LPVOID param)
         {
             send(c, okmsg, sizeof(okmsg)-1, 0);
         }
+
+        if (strstr(buffer, "HEAD /test_large_content"))
+        {
+            char msg[sizeof(largemsg) + 16];
+            sprintf(msg, largemsg, content_length);
+            send(c, msg, strlen(msg), 0);
+        }
         if (strstr(buffer, "HEAD /test_auth_host1"))
         {
             if (strstr(buffer, "Authorization: Basic dGVzdDE6cGFzcw=="))
@@ -4245,7 +4289,7 @@ static void test_head_request(int port)
     len = sizeof(content_length);
     content_length = -1;
     ret = HttpQueryInfoA(req.request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &content_length, &len, 0);
-    ok(ret, "HttpQueryInfo dailed: %u\n", GetLastError());
+    ok(ret, "HttpQueryInfo failed: %u\n", GetLastError());
     ok(len == sizeof(DWORD), "len = %u\n", len);
     ok(content_length == 100, "content_length = %u\n", content_length);
 
@@ -4544,7 +4588,7 @@ static void test_http_status(int port)
     DWORD i, size;
     BOOL res;
 
-    for(i=0; i < sizeof(http_status_tests)/sizeof(*http_status_tests); i++) {
+    for(i = 0; i < ARRAY_SIZE(http_status_tests); i++) {
         send_buffer = http_status_tests[i].response_text;
 
         open_simple_request(&req, "localhost", port, NULL, "/send_from_buffer");
@@ -4681,6 +4725,7 @@ static void test_basic_auth_credentials_reuse(int port)
     HINTERNET ses, con, req;
     DWORD status, size;
     BOOL ret;
+    char buffer[0x40];
 
     ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
     ok( ses != NULL, "InternetOpenA failed\n" );
@@ -4695,6 +4740,20 @@ static void test_basic_auth_credentials_reuse(int port)
     ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
     ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
 
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "user"), "got %s\n", buffer);
+    ok(size == 4, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "pwd"), "got %s\n", buffer);
+    ok(size == 3, "got %u\n", size);
+
     status = 0xdeadbeef;
     size = sizeof(status);
     ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
@@ -4718,6 +4777,316 @@ static void test_basic_auth_credentials_reuse(int port)
     ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
     ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
 
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "user"), "got %s\n", buffer);
+    ok(size == 4, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "pwd"), "got %s\n", buffer);
+    ok(size == 3, "got %u\n", size);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 200, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+}
+
+static void test_basic_auth_credentials_end_session(int port)
+{
+    HINTERNET ses, con, req;
+    DWORD status, size;
+    BOOL ret;
+    char buffer[0x40];
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, "user", "pwd",
+                            INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "user"), "got %s\n", buffer);
+    ok(size == 4, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "pwd"), "got %s\n", buffer);
+    ok(size == 3, "got %u\n", size);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == HTTP_STATUS_OK, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    /* Clear the cached credentials */
+    ret = InternetSetOptionA(ses,  INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+
+    con = InternetConnectA( ses, "localhost", port, NULL, NULL,
+                            INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "PUT", "/upload2.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, ""), "got %s\n", buffer);
+    ok(size == 0, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, ""), "got %s\n", buffer);
+    ok(size == 0, "got %u\n", size);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == HTTP_STATUS_BAD_REQUEST, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+}
+
+static void test_basic_auth_credentials_different(int port)
+{
+    HINTERNET ses, con, req;
+    DWORD status, size;
+    BOOL ret;
+    char buffer[0x40];
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, "user", "pwd",
+                            INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "user"), "got %s\n", buffer);
+    ok(size == 4, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "pwd"), "got %s\n", buffer);
+    ok(size == 3, "got %u\n", size);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 200, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, "user1", "pwd1",
+                            INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload3.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_USERNAME, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "user1"), "got %s\n", buffer);
+    ok(size == 5, "got %u\n", size);
+
+    size = sizeof(buffer);
+    SetLastError(0xdeadbeef);
+    ret = InternetQueryOptionA(req, INTERNET_OPTION_PASSWORD, buffer, &size);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+    ok(!strcmp(buffer, "pwd1"), "got %s\n", buffer);
+    ok(size == 4, "got %u\n", size);
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 200, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+}
+
+/*
+ * Manually set the Authorization for both calls.
+ */
+static void test_basic_auth_credentials_manual(int port)
+{
+    HINTERNET ses, con, req;
+    DWORD status, size;
+    BOOL ret;
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    /* Clear the cached credentials */
+    ret = InternetSetOptionA(ses,  INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+
+    con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    /* Set Authorization Header */
+    ret = HttpAddRequestHeadersA(req, "Authorization: Basic dXNlcjpwd2Q=\r\n", ~0u,
+                            HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
+    ok(ret, "HttpAddRequestHeaders Failed\n");
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 200, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+
+    /* Show manual headers are cached. */
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 401, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload4.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    /* Set Authorization Header */
+    ret = HttpAddRequestHeadersA(req, "Authorization: Bearer dXNlcjE6cHdkMQ==\r\n", ~0u,
+                            HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
+    ok(ret, "HttpAddRequestHeaders Failed\n");
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 200, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
+}
+
+/*
+ * Manually set the Authorization for the bearer call, which shows the cached is used.
+ */
+static void test_basic_auth_credentials_cached_manual(int port)
+{
+    HINTERNET ses, con, req;
+    DWORD status, size;
+    BOOL ret;
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    /* Clear the cached credentials */
+    ret = InternetSetOptionA(ses,  INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0);
+    ok(ret, "unexpected failure %u\n", GetLastError());
+
+     con = InternetConnectA( ses, "localhost", port, "user", "pwd",
+                            INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
     status = 0xdeadbeef;
     size = sizeof(status);
     ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
@@ -4727,6 +5096,33 @@ static void test_basic_auth_credentials_reuse(int port)
     InternetCloseHandle( req );
     InternetCloseHandle( con );
     InternetCloseHandle( ses );
+
+    ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+    ok( ses != NULL, "InternetOpenA failed\n" );
+
+    con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 );
+    ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() );
+
+    req = HttpOpenRequestA( con, "HEAD", "/upload4.txt", NULL, NULL, NULL, 0, 0 );
+    ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() );
+
+    /* Setting an Authorization Header doesn't override the cached one. */
+    ret = HttpAddRequestHeadersA(req, "Authorization: Bearer dXNlcjE6cHdkMQ==\r\n", ~0u,
+                            HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
+    ok(ret, "HttpAddRequestHeaders Failed\n");
+
+    ret = HttpSendRequestA( req, NULL, 0, NULL, 0 );
+    ok( ret, "HttpSendRequestA failed %u\n", GetLastError() );
+
+    status = 0xdeadbeef;
+    size = sizeof(status);
+    ret = HttpQueryInfoA( req, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL );
+    ok( ret, "HttpQueryInfoA failed %u\n", GetLastError() );
+    ok( status == 201, "got %u\n", status );
+
+    InternetCloseHandle( req );
+    InternetCloseHandle( con );
+    InternetCloseHandle( ses );
 }
 
 static void test_async_read(int port)
@@ -5792,6 +6188,94 @@ static void test_remove_dot_segments(int port)
     close_request(&req);
 }
 
+struct large_test
+{
+    DWORD64 content_length;
+    BOOL ret;
+};
+
+static void test_large_content(int port)
+{
+    struct large_test tests[] = {
+        { 0,                   TRUE },
+        { UINT_MAX-1,          TRUE },
+        { UINT_MAX,            TRUE },
+        { (DWORD64)UINT_MAX+1, FALSE },
+        { ~0,                  FALSE },
+    };
+    test_request_t req;
+    DWORD sizelen, len;
+    DWORD read_size;
+    DWORD64 len64;
+    char buf[16];
+    BOOL ret;
+    size_t i;
+
+    open_simple_request(&req, "localhost", port, "HEAD", "/test_large_content");
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        content_length = tests[i].content_length;
+        ret = HttpSendRequestA(req.request, NULL, 0, NULL, 0);
+        ok(ret, "HttpSendRequest failed: %u\n", GetLastError());
+
+        len = ~0;
+        sizelen = sizeof(len);
+        SetLastError(0xdeadbeef);
+        ret = HttpQueryInfoA(req.request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+                             &len, &sizelen, 0);
+        if (tests[i].ret)
+        {
+            ok(ret, "HttpQueryInfo should have succeeded\n");
+            ok(GetLastError() == ERROR_SUCCESS ||
+                broken(GetLastError() == 0xdeadbeef), /* xp, 2k8, vista */
+                "expected ERROR_SUCCESS, got %x\n", GetLastError());
+            ok(len == (DWORD)tests[i].content_length, "expected %u, got %u\n",
+                (DWORD)tests[i].content_length, len);
+        }
+        else
+        {
+            ok(!ret, "HttpQueryInfo should have failed\n");
+            ok(GetLastError() == ERROR_HTTP_INVALID_HEADER,
+                "expected ERROR_HTTP_INVALID_HEADER, got %x\n", GetLastError());
+            ok(len == ~0, "expected ~0, got %u\n", len);
+        }
+        ok(sizelen == sizeof(DWORD), "sizelen %u\n", sizelen);
+    }
+
+    /* test argument size */
+    len64 = ~0;
+    sizelen = sizeof(len64);
+    SetLastError(0xdeadbeef);
+    ret = HttpQueryInfoA(req.request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+                         &len64, &len, 0);
+    ok(!ret, "HttpQueryInfo should have failed\n");
+    ok(GetLastError() == ERROR_HTTP_INVALID_HEADER,
+        "expected ERROR_HTTP_INVALID_HEADER, got %x\n", GetLastError());
+    ok(sizelen == sizeof(DWORD64), "sizelen %u\n", sizelen);
+    ok(len64 == ~0, "len64 %x%08x\n", (DWORD)(len64 >> 32), (DWORD)len64);
+
+    close_request(&req);
+
+    /* test internal use of HttpQueryInfo on large size */
+    open_read_test_request(port, &req,
+                           "HTTP/1.1 200 OK\r\n"
+                           "Server: winetest\r\n"
+                           "Content-Length: 4294967296\r\n"
+                           "\r\n"
+                           "xx");
+    read_expect_async(req.request, buf, 4, &read_size, "xx");
+    send_response_and_wait("yy1234567890", FALSE, buf, &read_size, "xxyy", 4, 0, 2);
+    read_expect_sync_data(req.request, buf, 10, "1234567890");
+
+    SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION);
+    SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED);
+    close_async_handle(req.session, 2);
+    CHECK_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION);
+    CHECK_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED);
+    close_connection();
+}
+
 static void test_http_connection(void)
 {
     struct server_info si;
@@ -5801,7 +6285,7 @@ static void test_http_connection(void)
     si.hEvent = CreateEventW(NULL, 0, 0, NULL);
     si.port = 7531;
 
-    hThread = CreateThread(NULL, 0, server_thread, (LPVOID) &si, 0, &id);
+    hThread = CreateThread(NULL, 0, server_thread, &si, 0, &id);
     ok( hThread != NULL, "create thread failed\n");
 
     r = WaitForSingleObject(si.hEvent, 10000);
@@ -5843,6 +6327,10 @@ static void test_http_connection(void)
     test_request_content_length(si.port);
     test_accept_encoding(si.port);
     test_basic_auth_credentials_reuse(si.port);
+    test_basic_auth_credentials_end_session(si.port);
+    test_basic_auth_credentials_different(si.port);
+    test_basic_auth_credentials_manual(si.port);
+    test_basic_auth_credentials_cached_manual(si.port);
     test_async_read(si.port);
     test_http_read(si.port);
     test_connection_break(si.port);
@@ -5861,6 +6349,7 @@ else
 }
 #endif
     test_remove_dot_segments(si.port);
+    test_large_content(si.port);
 
     /* send the basic request again to shutdown the server thread */
     test_basic_request(si.port, "GET", "/quit");
@@ -5908,12 +6397,15 @@ static const cert_struct_test_t test_winehq_com_cert = {
     "Minnesota\r\n"
     "Saint Paul\r\n"
     "WineHQ\r\n"
+    "IT\r\n"
     "test.winehq.com\r\n"
     "webmaster@winehq.org",
 
     "US\r\n"
     "Minnesota\r\n"
+    "Saint Paul\r\n"
     "WineHQ\r\n"
+    "IT\r\n"
     "test.winehq.com\r\n"
     "webmaster@winehq.org"
 };
@@ -5928,6 +6420,12 @@ static void test_cert_struct(HINTERNET req, const cert_struct_test_t *test)
 
     size = sizeof(info);
     res = InternetQueryOptionA(req, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, &info, &size);
+    if (!res)
+    {
+        win_skip("Querying INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT failed, skipping tests\n");
+        return;
+    }
+
     ok(res, "InternetQueryOption failed: %u\n", GetLastError());
     ok(size == sizeof(info), "size = %u\n", size);
 
@@ -6142,7 +6640,7 @@ static void test_security_flags(void)
     ok(!res && GetLastError() == ERROR_IO_PENDING, "HttpSendRequest failed: %u\n", GetLastError());
 
     WaitForSingleObject(complete_event, INFINITE);
-    ok(req_error == ERROR_INTERNET_SEC_CERT_REV_FAILED || broken(req_error == ERROR_INTERNET_SEC_CERT_ERRORS),
+    ok(req_error == ERROR_INTERNET_SEC_CERT_ERRORS,
        "req_error = %d\n", req_error);
 
     size = 0;
@@ -6166,6 +6664,9 @@ static void test_security_flags(void)
         ok(!cert->lpszEncryptionAlgName, "unexpected encryption algorithm name\n");
         ok(!cert->lpszProtocolName, "unexpected protocol name\n");
         ok(cert->dwKeySize != 0xdeadbeef, "unexpected key size\n");
+
+        LocalFree(cert->lpszSubjectInfo);
+        LocalFree(cert->lpszIssuerInfo);
     }
     HeapFree(GetProcessHeap(), 0, cert);
 
@@ -6178,7 +6679,7 @@ static void test_security_flags(void)
     CLEAR_NOTIFIED(INTERNET_STATUS_COOKIE_SENT);
     CLEAR_NOTIFIED(INTERNET_STATUS_DETECTING_PROXY);
 
-    if(req_error != ERROR_INTERNET_SEC_CERT_REV_FAILED) {
+    if(req_error != ERROR_INTERNET_SEC_CERT_ERRORS) {
         win_skip("Unexpected cert errors %u, skipping security flags tests\n", req_error);
 
         close_async_handle(ses, 3);
@@ -6192,10 +6693,10 @@ static void test_security_flags(void)
     test_request_flags(req, 8);
     /* IE11 finds both rev failure and invalid CA. Previous versions required rev failure
        to be ignored before invalid CA was reported. */
-    test_secflags_option(req, _SECURITY_FLAG_CERT_REV_FAILED, _SECURITY_FLAG_CERT_INVALID_CA);
+    test_secflags_option(req, _SECURITY_FLAG_CERT_INVALID_CA, _SECURITY_FLAG_CERT_REV_FAILED);
 
     set_secflags(req, FALSE, SECURITY_FLAG_IGNORE_REVOCATION);
-    test_secflags_option(req, _SECURITY_FLAG_CERT_REV_FAILED|SECURITY_FLAG_IGNORE_REVOCATION, _SECURITY_FLAG_CERT_INVALID_CA);
+    test_secflags_option(req, _SECURITY_FLAG_CERT_INVALID_CA|SECURITY_FLAG_IGNORE_REVOCATION, _SECURITY_FLAG_CERT_REV_FAILED);
 
     SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
     SET_EXPECT(INTERNET_STATUS_CONNECTED_TO_SERVER);
@@ -6209,7 +6710,7 @@ static void test_security_flags(void)
     ok(!res && GetLastError() == ERROR_IO_PENDING, "HttpSendRequest failed: %u\n", GetLastError());
 
     WaitForSingleObject(complete_event, INFINITE);
-    ok(req_error == ERROR_INTERNET_SEC_CERT_ERRORS, "req_error = %d\n", req_error);
+    ok(req_error == ERROR_INTERNET_INVALID_CA || req_error == ERROR_INTERNET_SEC_CERT_ERRORS, "req_error = %d\n", req_error);
 
     CHECK_NOTIFIED(INTERNET_STATUS_CONNECTING_TO_SERVER);
     CHECK_NOTIFIED(INTERNET_STATUS_CONNECTED_TO_SERVER);
@@ -6220,11 +6721,11 @@ static void test_security_flags(void)
     CLEAR_NOTIFIED(INTERNET_STATUS_DETECTING_PROXY);
 
     test_request_flags(req, INTERNET_REQFLAG_NO_HEADERS);
-    test_secflags_option(req, SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_REV_FAILED|_SECURITY_FLAG_CERT_INVALID_CA, 0);
+    test_secflags_option(req, SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_INVALID_CA, 0);
     test_security_info("https://test.winehq.com/data/some_file.html?q", ERROR_INTERNET_ITEM_NOT_FOUND, 0);
 
     set_secflags(req, FALSE, SECURITY_FLAG_IGNORE_UNKNOWN_CA);
-    test_secflags_option(req, _SECURITY_FLAG_CERT_INVALID_CA|_SECURITY_FLAG_CERT_REV_FAILED
+    test_secflags_option(req, _SECURITY_FLAG_CERT_INVALID_CA
             |SECURITY_FLAG_IGNORE_REVOCATION|SECURITY_FLAG_IGNORE_UNKNOWN_CA, 0);
     test_http_version(req);
 
@@ -6262,11 +6763,11 @@ static void test_security_flags(void)
 
     test_request_flags(req, 0);
     test_secflags_option(req, SECURITY_FLAG_SECURE|SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_IGNORE_REVOCATION
-            |SECURITY_FLAG_STRENGTH_STRONG|_SECURITY_FLAG_CERT_REV_FAILED|_SECURITY_FLAG_CERT_INVALID_CA, 0);
+            |SECURITY_FLAG_STRENGTH_STRONG|_SECURITY_FLAG_CERT_INVALID_CA, 0);
 
     test_cert_struct(req, &test_winehq_com_cert);
     test_security_info("https://test.winehq.com/data/some_file.html?q", 0,
-            _SECURITY_FLAG_CERT_INVALID_CA|_SECURITY_FLAG_CERT_REV_FAILED);
+            _SECURITY_FLAG_CERT_INVALID_CA);
 
     res = InternetReadFile(req, buf, sizeof(buf), &size);
     ok(res, "InternetReadFile failed: %u\n", GetLastError());
@@ -6299,7 +6800,7 @@ static void test_security_flags(void)
     CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED);
 
     test_secflags_option(req, SECURITY_FLAG_SECURE|SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_STRENGTH_STRONG
-            |SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_REV_FAILED|_SECURITY_FLAG_CERT_INVALID_CA, 0);
+            |SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_INVALID_CA, 0);
     test_http_version(req);
 
     SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER);
@@ -6334,7 +6835,7 @@ static void test_security_flags(void)
 
     test_request_flags(req, 0);
     test_secflags_option(req, SECURITY_FLAG_SECURE|SECURITY_FLAG_IGNORE_UNKNOWN_CA|SECURITY_FLAG_STRENGTH_STRONG
-            |SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_REV_FAILED|_SECURITY_FLAG_CERT_INVALID_CA, 0);
+            |SECURITY_FLAG_IGNORE_REVOCATION|_SECURITY_FLAG_CERT_INVALID_CA, 0);
 
     res = InternetReadFile(req, buf, sizeof(buf), &size);
     ok(res, "InternetReadFile failed: %u\n", GetLastError());
@@ -6903,14 +7404,14 @@ static const struct notification async_send_request_ex_chunked_test[] =
 static const struct notification_data notification_data[] = {
     {
         async_send_request_ex_chunked_test,
-        sizeof(async_send_request_ex_chunked_test)/sizeof(async_send_request_ex_chunked_test[0]),
+        ARRAY_SIZE(async_send_request_ex_chunked_test),
         "GET",
         "test.winehq.org",
         "tests/data.php"
     },
     {
         async_send_request_ex_test,
-        sizeof(async_send_request_ex_test)/sizeof(async_send_request_ex_test[0]),
+        ARRAY_SIZE(async_send_request_ex_test),
         "POST",
         "test.winehq.org",
         "tests/post.php",
@@ -6918,14 +7419,14 @@ static const struct notification_data notification_data[] = {
     },
     {
         async_send_request_ex_test2,
-        sizeof(async_send_request_ex_test)/sizeof(async_send_request_ex_test[0]),
+        ARRAY_SIZE(async_send_request_ex_test2),
         "POST",
         "test.winehq.org",
         "tests/post.php"
     },
     {
         async_send_request_ex_resolve_failure_test,
-        sizeof(async_send_request_ex_resolve_failure_test)/sizeof(async_send_request_ex_resolve_failure_test[0]),
+        ARRAY_SIZE(async_send_request_ex_resolve_failure_test),
         "GET",
         "brokenhost",
         "index.html",