urlmon: Add some error handling to the http protocol. (try 3)

David Hedberg dhedberg at codeweavers.com
Sat Jan 8 23:28:54 CST 2011


Try 3: Merge some duplicate checks in the tests.
---
 dlls/urlmon/http.c      |  173 +++++++++++++++++++++++++++++++++++++-
 dlls/urlmon/tests/url.c |  214 ++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 370 insertions(+), 17 deletions(-)

diff --git a/dlls/urlmon/http.c b/dlls/urlmon/http.c
index 7904229..23f6e69 100644
--- a/dlls/urlmon/http.c
+++ b/dlls/urlmon/http.c
@@ -80,6 +80,145 @@ static LPWSTR query_http_info(HttpProtocol *This, DWORD option)
     return ret;
 }
 
+static inline BOOL set_security_flag(HttpProtocol *This, DWORD new_flag)
+{
+    DWORD flags, size = sizeof(flags);
+    BOOL res;
+
+    res = InternetQueryOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size);
+    if(res) {
+        flags |= new_flag;
+        res = InternetSetOptionW(This->base.request, INTERNET_OPTION_SECURITY_FLAGS, &flags, size);
+    }
+    if(!res)
+        ERR("Failed to set security flag(s): %x\n", new_flag);
+
+    return res;
+}
+
+static inline HRESULT internet_error_to_hres(DWORD error)
+{
+    switch(error)
+    {
+    case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+    case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+    case ERROR_INTERNET_INVALID_CA:
+    case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
+        return INET_E_INVALID_CERTIFICATE;
+    case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+    case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
+    case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
+        return INET_E_REDIRECT_FAILED;
+    default:
+        return INET_E_DOWNLOAD_FAILURE;
+    }
+}
+
+static HRESULT handle_http_error(HttpProtocol *This, DWORD error)
+{
+    IServiceProvider *serv_prov;
+    IWindowForBindingUI *wfb_ui;
+    IHttpSecurity *http_security;
+    BOOL security_problem;
+    HRESULT hres;
+
+    switch(error) {
+    case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+    case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+    case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+    case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
+    case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION:
+    case ERROR_INTERNET_INVALID_CA:
+    case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
+        security_problem = TRUE;
+        break;
+    default:
+        security_problem = FALSE;
+    }
+
+    hres = IInternetProtocolSink_QueryInterface(This->base.protocol_sink, &IID_IServiceProvider,
+                                                (void**)&serv_prov);
+    if(FAILED(hres)) {
+        ERR("Failed to get IServiceProvider.\n");
+        return E_ABORT;
+    }
+
+    if(security_problem) {
+        hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpSecurity, &IID_IHttpSecurity,
+                                             (void**)&http_security);
+        if(SUCCEEDED(hres)) {
+            hres = IHttpSecurity_OnSecurityProblem(http_security, error);
+            IHttpSecurity_Release(http_security);
+
+            if(hres != S_FALSE)
+            {
+                BOOL res = FALSE;
+
+                IServiceProvider_Release(serv_prov);
+
+                if(hres == S_OK) {
+                    if(error == ERROR_INTERNET_SEC_CERT_DATE_INVALID)
+                        res = set_security_flag(This, SECURITY_FLAG_IGNORE_CERT_DATE_INVALID);
+                    else if(error == ERROR_INTERNET_SEC_CERT_CN_INVALID)
+                        res = set_security_flag(This, SECURITY_FLAG_IGNORE_CERT_CN_INVALID);
+                    else if(error == ERROR_INTERNET_INVALID_CA)
+                        res = set_security_flag(This, SECURITY_FLAG_IGNORE_UNKNOWN_CA);
+
+                    if(res)
+                        return RPC_E_RETRY;
+
+                    FIXME("Don't know how to ignore error %d\n", error);
+                    return E_ABORT;
+                }
+
+                if(hres == E_ABORT)
+                    return E_ABORT;
+                if(hres == RPC_E_RETRY)
+                    return RPC_E_RETRY;
+
+                return internet_error_to_hres(error);
+            }
+        }
+    }
+
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IWindowForBindingUI, &IID_IWindowForBindingUI,
+                                         (void**)&wfb_ui);
+    if(SUCCEEDED(hres)) {
+        HWND hwnd;
+        const IID *iid_reason;
+
+        if(security_problem)
+            iid_reason = &IID_IHttpSecurity;
+        else if(error == ERROR_INTERNET_INCORRECT_PASSWORD)
+            iid_reason = &IID_IAuthenticate;
+        else
+            iid_reason = &IID_IWindowForBindingUI;
+
+        hres = IWindowForBindingUI_GetWindow(wfb_ui, iid_reason, &hwnd);
+        if(SUCCEEDED(hres) && hwnd)
+        {
+            DWORD res;
+
+            res = InternetErrorDlg(hwnd, This->base.request, error,
+                                   FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
+                                   NULL);
+
+            if(res == ERROR_INTERNET_FORCE_RETRY || res == ERROR_SUCCESS)
+                hres = RPC_E_RETRY;
+            else
+                hres = E_FAIL;
+        }
+        IWindowForBindingUI_Release(wfb_ui);
+    }
+
+    IServiceProvider_Release(serv_prov);
+
+    if(hres == RPC_E_RETRY)
+        return hres;
+
+    return internet_error_to_hres(error);
+}
+
 static ULONG send_http_request(HttpProtocol *This)
 {
     INTERNET_BUFFERSW send_buffer = {sizeof(INTERNET_BUFFERSW)};
@@ -285,13 +424,18 @@ static HRESULT HttpProtocol_open_request(Protocol *prot, IUri *uri, DWORD reques
     if(!res)
         WARN("InternetSetOption(INTERNET_OPTION_HTTP_DECODING) failed: %08x\n", GetLastError());
 
-    error = send_http_request(This);
+    do {
+        error = send_http_request(This);
 
-    if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
-        return S_OK;
+        if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
+            return S_OK;
+
+        hres = handle_http_error(This, error);
+
+    } while(hres == RPC_E_RETRY);
 
     WARN("HttpSendRequest failed: %d\n", error);
-    return INET_E_DOWNLOAD_FAILURE;
+    return hres;
 }
 
 static HRESULT HttpProtocol_end_request(Protocol *protocol)
@@ -393,7 +537,26 @@ static void HttpProtocol_close_connection(Protocol *prot)
 
 static void HttpProtocol_on_error(Protocol *prot, DWORD error)
 {
-    FIXME("(%p) %d - stub\n", prot, error);
+    HttpProtocol *This = impl_from_Protocol(prot);
+    HRESULT hres;
+
+    TRACE("(%p) %d\n", prot, error);
+
+    if(prot->flags & FLAG_FIRST_CONTINUE_COMPLETE) {
+        FIXME("Not handling error %d\n", error);
+        return;
+    }
+
+    while((hres = handle_http_error(This, error)) == RPC_E_RETRY) {
+        error = send_http_request(This);
+
+        if(error == ERROR_IO_PENDING || error == ERROR_SUCCESS)
+            return;
+    }
+
+    protocol_abort(prot, hres);
+    protocol_close_connection(prot);
+    return;
 }
 
 static const ProtocolVtbl AsyncProtocolVtbl = {
diff --git a/dlls/urlmon/tests/url.c b/dlls/urlmon/tests/url.c
index 2c2acf7..029f203 100644
--- a/dlls/urlmon/tests/url.c
+++ b/dlls/urlmon/tests/url.c
@@ -91,10 +91,12 @@ DEFINE_EXPECT(QueryInterface_IInternetBindInfo);
 DEFINE_EXPECT(QueryInterface_IAuthenticate);
 DEFINE_EXPECT(QueryInterface_IInternetProtocol);
 DEFINE_EXPECT(QueryInterface_IWindowForBindingUI);
+DEFINE_EXPECT(QueryInterface_IHttpSecurity);
 DEFINE_EXPECT(QueryService_IAuthenticate);
 DEFINE_EXPECT(QueryService_IInternetProtocol);
 DEFINE_EXPECT(QueryService_IInternetBindInfo);
 DEFINE_EXPECT(QueryService_IWindowForBindingUI);
+DEFINE_EXPECT(QueryService_IHttpSecurity);
 DEFINE_EXPECT(BeginningTransaction);
 DEFINE_EXPECT(OnResponse);
 DEFINE_EXPECT(QueryInterface_IHttpNegotiate2);
@@ -140,6 +142,9 @@ DEFINE_EXPECT(Load);
 DEFINE_EXPECT(PutProperty_MIMETYPEPROP);
 DEFINE_EXPECT(PutProperty_CLASSIDPROP);
 DEFINE_EXPECT(SetPriority);
+DEFINE_EXPECT(GetWindow_IHttpSecurity);
+DEFINE_EXPECT(GetWindow_IWindowForBindingUI);
+DEFINE_EXPECT(OnSecurityProblem);
 
 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
@@ -159,6 +164,9 @@ static const WCHAR MK_URL[] = {'m','k',':','@','M','S','I','T','S','t','o','r','
 static const WCHAR https_urlW[] =
     {'h','t','t','p','s',':','/','/','w','w','w','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',
      '/','t','e','s','t','.','h','t','m','l',0};
+static const WCHAR https_invalid_cn_urlW[] =
+    {'h','t','t','p','s',':','/','/','2','0','9','.','4','6','.','2','5','.','1','3','2',
+     '/','t','e','s','t','.','h','t','m','l',0};
 static const WCHAR ftp_urlW[] = {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g',
     '/','p','u','b','/','o','t','h','e','r','/',
     'w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0};
@@ -183,16 +191,18 @@ static const WCHAR emptyW[] = {0};
 
 static BOOL stopped_binding = FALSE, stopped_obj_binding = FALSE, emulate_protocol = FALSE,
     data_available = FALSE, http_is_first = TRUE, bind_to_object = FALSE, filedwl_api;
-static DWORD read = 0, bindf = 0, prot_state = 0, thread_id, tymed;
+static DWORD read = 0, bindf = 0, prot_state = 0, thread_id, tymed, security_problem;
 static CHAR mime_type[512];
 static IInternetProtocolSink *protocol_sink = NULL;
 static IBinding *current_binding;
 static HANDLE complete_event, complete_event2;
 static HRESULT binding_hres;
+static HRESULT onsecurityproblem_hres;
 static BOOL have_IHttpNegotiate2, use_bscex, is_async_prot;
 static BOOL test_redirect, use_cache_file, callback_read, no_callback, test_abort;
 static WCHAR cache_file_name[MAX_PATH];
 static BOOL only_check_prot_args = FALSE;
+static BOOL invalid_cn_accepted = FALSE;
 
 static LPCWSTR urls[] = {
     WINE_ABOUT_URL,
@@ -627,6 +637,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
         IServiceProvider *service_provider;
         IHttpNegotiate *http_negotiate;
         IHttpNegotiate2 *http_negotiate2;
+        IHttpSecurity *http_security;
         LPWSTR ua = (LPWSTR)0xdeadbeef, accept_mimes[256];
         LPWSTR additional_headers = (LPWSTR)0xdeadbeef;
         BYTE sec_id[100];
@@ -708,6 +719,18 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
         ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres);
         ok(size == no_callback ? 512 : 13, "size=%d\n", size);
 
+        if(!no_callback) {
+            SET_EXPECT(QueryService_IHttpSecurity);
+            SET_EXPECT(QueryInterface_IHttpSecurity);
+        }
+        hres = IServiceProvider_QueryService(service_provider, &IID_IHttpSecurity,
+                &IID_IHttpSecurity, (void**)&http_security);
+        ok(hres == (no_callback ? E_NOINTERFACE : S_OK), "QueryService failed: 0x%08x\n", hres);
+        if(!no_callback) {
+            CHECK_CALLED(QueryService_IHttpSecurity);
+            CHECK_CALLED(QueryInterface_IHttpSecurity);
+        }
+
         IServiceProvider_Release(service_provider);
 
         IInternetProtocolSink_AddRef(pOIProtSink);
@@ -1104,7 +1127,10 @@ static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL,
         LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
 {
-    CHECK_EXPECT(BeginningTransaction);
+    if(onsecurityproblem_hres == S_OK)
+        CHECK_EXPECT2(BeginningTransaction);
+    else
+        CHECK_EXPECT(BeginningTransaction);
 
     ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId());
 
@@ -1173,6 +1199,73 @@ static IHttpNegotiate2Vtbl HttpNegotiateVtbl = {
 
 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiateVtbl };
 
+static HRESULT WINAPI HttpSecurity_QueryInterface(IHttpSecurity *iface, REFIID riid, void **ppv)
+{
+    ok(0, "Unexpected call\n");
+    *ppv = NULL;
+    if(IsEqualGUID(&IID_IHttpSecurity, riid) ||
+       IsEqualGUID(&IID_IWindowForBindingUI, riid) ||
+       IsEqualGUID(&IID_IUnknown, riid))
+    {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    ok(0, "Unexpected interface requested.\n");
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI HttpSecurity_AddRef(IHttpSecurity *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI HttpSecurity_Release(IHttpSecurity *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI HttpSecurity_GetWindow(IHttpSecurity *iface, REFGUID rguidReason, HWND *phwnd)
+{
+    if(IsEqualGUID(rguidReason, &IID_IHttpSecurity))
+        CHECK_EXPECT(GetWindow_IHttpSecurity);
+    else if(IsEqualGUID(rguidReason, &IID_IWindowForBindingUI))
+        CHECK_EXPECT2(GetWindow_IWindowForBindingUI);
+    else
+        ok(0, "Unexpected rguidReason: %s\n", debugstr_guid(rguidReason));
+
+    *phwnd = NULL;
+    return S_OK;
+}
+
+static HRESULT WINAPI HttpSecurity_OnSecurityProblem(IHttpSecurity *iface, DWORD dwProblem)
+{
+    CHECK_EXPECT(OnSecurityProblem);
+    if(!security_problem) {
+        ok(dwProblem == ERROR_INTERNET_SEC_CERT_CN_INVALID ||
+           broken(dwProblem == ERROR_INTERNET_SEC_CERT_ERRORS) /* Some versions of IE6 */,
+           "Got problem: %d\n", dwProblem);
+        security_problem = dwProblem;
+
+        if(dwProblem == ERROR_INTERNET_SEC_CERT_ERRORS)
+            binding_hres = INET_E_SECURITY_PROBLEM;
+    }else
+        ok(dwProblem == security_problem, "Got problem: %d\n", dwProblem);
+
+    return onsecurityproblem_hres;
+}
+
+static const IHttpSecurityVtbl HttpSecurityVtbl = {
+    HttpSecurity_QueryInterface,
+    HttpSecurity_AddRef,
+    HttpSecurity_Release,
+    HttpSecurity_GetWindow,
+    HttpSecurity_OnSecurityProblem
+};
+
+static IHttpSecurity HttpSecurity = { &HttpSecurityVtbl };
+
 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
 {
     ok(0, "unexpected call\n");
@@ -1208,8 +1301,15 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
     }
 
     if(IsEqualGUID(&IID_IWindowForBindingUI, guidService)) {
-        CHECK_EXPECT(QueryService_IWindowForBindingUI);
-        return E_NOTIMPL;
+        CHECK_EXPECT2(QueryService_IWindowForBindingUI);
+        *ppv = &HttpSecurity;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(&IID_IHttpSecurity, guidService)) {
+        CHECK_EXPECT(QueryService_IHttpSecurity);
+        *ppv = &HttpSecurity;
+        return S_OK;
     }
 
     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
@@ -1292,6 +1392,11 @@ static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallbackEx *iface, REF
         CHECK_EXPECT2(QueryInterface_IWindowForBindingUI);
         return E_NOINTERFACE;
     }
+    else if(IsEqualGUID(&IID_IHttpSecurity, riid))
+    {
+        CHECK_EXPECT2(QueryInterface_IHttpSecurity);
+        return E_NOINTERFACE;
+    }
     else
     {
         ok(0, "unexpected interface %s\n", debugstr_guid(riid));
@@ -1366,6 +1471,8 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallbackEx *iface, ULONG u
             CHECK_EXPECT(Obj_OnProgress_FINDINGRESOURCE);
         else if(test_protocol == FTP_TEST)
             todo_wine CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
+        else if(onsecurityproblem_hres == S_OK)
+            CHECK_EXPECT2(OnProgress_FINDINGRESOURCE); /* todo wine */
         else
             CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
         if(emulate_protocol && (test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == WINETEST_TEST))
@@ -1376,6 +1483,8 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallbackEx *iface, ULONG u
             CHECK_EXPECT(Obj_OnProgress_CONNECTING);
         else if(test_protocol == FTP_TEST)
             todo_wine CHECK_EXPECT(OnProgress_CONNECTING);
+        else if(onsecurityproblem_hres == S_OK)
+            CHECK_EXPECT2(OnProgress_CONNECTING);
         else
             CHECK_EXPECT(OnProgress_CONNECTING);
         if(emulate_protocol && (test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == WINETEST_TEST))
@@ -1559,6 +1668,8 @@ static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallbackEx *iface, HRES
 
     if(filedwl_api)
         ok(SUCCEEDED(hresult), "binding failed: %08x\n", hresult);
+    else if(invalid_cn_accepted)
+        todo_wine ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
     else
         ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres);
     ok(szError == NULL, "szError should be NULL\n");
@@ -2443,6 +2554,7 @@ static BOOL test_RegisterBindStatusCallback(void)
 #define BINDTEST_NO_CALLBACK_READ  0x0040
 #define BINDTEST_NO_CALLBACK   0x0080
 #define BINDTEST_ABORT         0x0100
+#define BINDTEST_INVALID_CN    0x0200
 
 static void init_bind_test(int protocol, DWORD flags, DWORD t)
 {
@@ -2461,6 +2573,10 @@ static void init_bind_test(int protocol, DWORD flags, DWORD t)
         urls[HTTP_TEST] = SHORT_RESPONSE_URL;
     else
         urls[HTTP_TEST] = WINE_ABOUT_URL;
+    if(flags & BINDTEST_INVALID_CN)
+        urls[HTTPS_TEST] = https_invalid_cn_urlW;
+    else
+        urls[HTTPS_TEST] = https_urlW;
     test_redirect = (flags & BINDTEST_REDIRECT) != 0;
     use_cache_file = (flags & BINDTEST_USE_CACHE) != 0;
     callback_read = !(flags & BINDTEST_NO_CALLBACK_READ);
@@ -2520,6 +2636,14 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
 
     if(tymed == TYMED_FILE && (test_protocol == ABOUT_TEST || test_protocol == ITS_TEST))
         binding_hres = INET_E_DATA_NOT_AVAILABLE;
+    if((flags & BINDTEST_INVALID_CN) && !invalid_cn_accepted &&
+       (onsecurityproblem_hres != S_OK || security_problem == ERROR_INTERNET_SEC_CERT_ERRORS)) {
+        if(security_problem == ERROR_INTERNET_SEC_CERT_ERRORS)
+            binding_hres = INET_E_SECURITY_PROBLEM;
+        else
+            binding_hres = INET_E_INVALID_CERTIFICATE;
+    }
+
 
     if(only_check_prot_args)
         SET_EXPECT(OnStopBinding);
@@ -2546,11 +2670,19 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
             SET_EXPECT(QueryInterface_IHttpNegotiate);
             SET_EXPECT(QueryInterface_IWindowForBindingUI);
             SET_EXPECT(QueryService_IWindowForBindingUI);
+            SET_EXPECT(GetWindow_IWindowForBindingUI);
             SET_EXPECT(BeginningTransaction);
             SET_EXPECT(QueryInterface_IHttpNegotiate2);
             SET_EXPECT(GetRootSecurityId);
             SET_EXPECT(OnProgress_FINDINGRESOURCE);
             SET_EXPECT(OnProgress_CONNECTING);
+            if(flags & BINDTEST_INVALID_CN) {
+                SET_EXPECT(QueryInterface_IHttpSecurity);
+                SET_EXPECT(QueryService_IHttpSecurity);
+                SET_EXPECT(OnSecurityProblem);
+                if(SUCCEEDED(onsecurityproblem_hres))
+                    SET_EXPECT(GetWindow_IHttpSecurity);
+            }
         }
         if(!no_callback) {
             if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FTP_TEST
@@ -2600,6 +2732,19 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
         ok(hres == INET_E_DATA_NOT_AVAILABLE,
            "IMoniker_BindToStorage failed: %08x, expected INET_E_DATA_NOT_AVAILABLE\n", hres);
         ok(unk == NULL, "istr should be NULL\n");
+    }else if((flags & BINDTEST_INVALID_CN) && binding_hres != S_OK) {
+        ok(hres == binding_hres, "Got %08x\n", hres);
+        ok(unk == NULL, "Got %p\n", unk);
+    }else if((flags & BINDTEST_INVALID_CN) && invalid_cn_accepted) {
+        todo_wine {
+            ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
+            ok(unk != NULL, "unk == NULL\n");
+            if(unk == NULL) {
+                ok(0, "Expected security problem to be ignored.");
+                invalid_cn_accepted = FALSE;
+                binding_hres = INET_E_INVALID_CERTIFICATE;
+            }
+        }
     }else {
         ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres);
         ok(unk != NULL, "unk == NULL\n");
@@ -2609,7 +2754,7 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
         unk = NULL;
     }
 
-    if(FAILED(hres))
+    if(FAILED(hres) && !(flags & BINDTEST_INVALID_CN))
         return;
 
     if((bindf & BINDF_ASYNCHRONOUS) && !no_callback) {
@@ -2645,13 +2790,14 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
             CHECK_CALLED(QueryInterface_IHttpNegotiate);
             CLEAR_CALLED(QueryInterface_IWindowForBindingUI);
             CLEAR_CALLED(QueryService_IWindowForBindingUI);
+            CLEAR_CALLED(GetWindow_IWindowForBindingUI);
             CHECK_CALLED(BeginningTransaction);
             if (have_IHttpNegotiate2)
             {
                 CHECK_CALLED(QueryInterface_IHttpNegotiate2);
                 CHECK_CALLED(GetRootSecurityId);
             }
-            if(http_is_first || test_protocol == HTTPS_TEST) {
+            if(http_is_first || (test_protocol == HTTPS_TEST && !(flags & BINDTEST_INVALID_CN))) {
                 CHECK_CALLED(OnProgress_FINDINGRESOURCE);
                 CHECK_CALLED(OnProgress_CONNECTING);
             }else todo_wine {
@@ -2659,24 +2805,45 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
                 /* IE7 does call this */
                 CLEAR_CALLED(OnProgress_CONNECTING);
             }
+            if((flags & BINDTEST_INVALID_CN) && !invalid_cn_accepted)  {
+                CHECK_CALLED(QueryInterface_IHttpSecurity);
+                CHECK_CALLED(QueryService_IHttpSecurity);
+                CHECK_CALLED(OnSecurityProblem);
+            }else {
+                CHECK_NOT_CALLED(QueryInterface_IHttpSecurity);
+                CHECK_NOT_CALLED(QueryService_IHttpSecurity);
+                CHECK_NOT_CALLED(OnSecurityProblem);
+            }
         }
         if(!no_callback) {
             if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST || test_protocol == WINETEST_TEST)
-                CHECK_CALLED(OnProgress_SENDINGREQUEST);
+                if(flags & BINDTEST_INVALID_CN)
+                    CLEAR_CALLED(OnProgress_SENDINGREQUEST);
+                else
+                    CHECK_CALLED(OnProgress_SENDINGREQUEST);
             else if(test_protocol == FTP_TEST)
                 todo_wine CHECK_CALLED(OnProgress_SENDINGREQUEST);
             if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == WINETEST_TEST) {
                 CLEAR_CALLED(QueryInterface_IHttpNegotiate);
-                CHECK_CALLED(OnResponse);
+                if(!(flags & BINDTEST_INVALID_CN) || (binding_hres == S_OK)) {
+                    CHECK_CALLED(OnResponse);
+                }
+            }
+            if(!(flags & BINDTEST_INVALID_CN) || binding_hres == S_OK) {
+                CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
+                CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
+                CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
             }
-            CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
-            CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
             if(test_protocol == FILE_TEST)
                 CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE);
             if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FTP_TEST  || test_protocol == WINETEST_TEST)
                 CLEAR_CALLED(OnProgress_DOWNLOADINGDATA);
-            CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
-            if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST)
+            if((flags & BINDTEST_INVALID_CN)) {
+                if(binding_hres == S_OK)
+                    CHECK_CALLED(OnDataAvailable);
+                else
+                    CHECK_NOT_CALLED(OnDataAvailable);
+            }else if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST)
                 CHECK_CALLED(OnDataAvailable);
             CHECK_CALLED(OnStopBinding);
         }
@@ -2689,6 +2856,9 @@ static void test_BindToStorage(int protocol, DWORD flags, DWORD t)
     if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST)
         http_is_first = FALSE;
 
+    if((flags & BINDTEST_INVALID_CN) && onsecurityproblem_hres == S_OK && security_problem != ERROR_INTERNET_SEC_CERT_ERRORS)
+        invalid_cn_accepted = TRUE;
+
     if(unk) {
         BYTE buf[512];
         DWORD readed;
@@ -2777,6 +2947,7 @@ static void test_BindToObject(int protocol, DWORD flags)
             SET_EXPECT(Obj_OnProgress_CONNECTING);
             SET_EXPECT(QueryInterface_IWindowForBindingUI);
             SET_EXPECT(QueryService_IWindowForBindingUI);
+            SET_EXPECT(GetWindow_IWindowForBindingUI);
         }
         if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST)
             SET_EXPECT(Obj_OnProgress_SENDINGREQUEST);
@@ -2862,6 +3033,7 @@ static void test_BindToObject(int protocol, DWORD flags)
             }
             CLEAR_CALLED(QueryInterface_IWindowForBindingUI);
             CLEAR_CALLED(QueryService_IWindowForBindingUI);
+            CLEAR_CALLED(GetWindow_IWindowForBindingUI);
         }
         if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST) {
             if(urls[test_protocol] == SHORT_RESPONSE_URL)
@@ -3270,6 +3442,24 @@ START_TEST(url)
         trace("file test (no callback)...\n");
         test_BindToStorage(FILE_TEST, BINDTEST_NO_CALLBACK, TYMED_ISTREAM);
 
+        trace("synchronous https test (invalid CN, dialog)\n");
+        onsecurityproblem_hres = S_FALSE;
+        http_is_first = TRUE;
+        test_BindToStorage(HTTPS_TEST, BINDTEST_INVALID_CN, TYMED_ISTREAM);
+
+        trace("synchronous https test (invalid CN, fail)\n");
+        onsecurityproblem_hres = E_FAIL;
+        test_BindToStorage(HTTPS_TEST, BINDTEST_INVALID_CN, TYMED_ISTREAM);
+
+        trace("synchronous https test (invalid CN, accept)\n");
+        onsecurityproblem_hres = S_OK;
+        test_BindToStorage(HTTPS_TEST, BINDTEST_INVALID_CN, TYMED_ISTREAM);
+
+        trace("asynchronous https test (invalid CN, dialog 2)\n");
+        onsecurityproblem_hres = S_FALSE;
+        test_BindToStorage(HTTPS_TEST, BINDTEST_INVALID_CN, TYMED_ISTREAM);
+        invalid_cn_accepted = FALSE;
+
         bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
 
         trace("about test (no read)...\n");
-- 
1.7.4.rc1




More information about the wine-patches mailing list