[URLMON_WINETEST] Sync with Wine Staging 3.9. CORE-14656
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Jun 2018 02:50:58 +0000 (03:50 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Jun 2018 02:50:58 +0000 (03:50 +0100)
modules/rostests/winetests/urlmon/protocol.c
modules/rostests/winetests/urlmon/url.c

index 50fe999..d279694 100644 (file)
@@ -20,6 +20,7 @@
 #define CONST_VTABLE
 
 #include <wine/test.h>
 #define CONST_VTABLE
 
 #include <wine/test.h>
+#include <wine/heap.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include <stdarg.h>
 #include <stdio.h>
 
@@ -125,6 +126,8 @@ DEFINE_EXPECT(MimeFilter_Continue);
 DEFINE_EXPECT(Stream_Seek);
 DEFINE_EXPECT(Stream_Read);
 DEFINE_EXPECT(Redirect);
 DEFINE_EXPECT(Stream_Seek);
 DEFINE_EXPECT(Stream_Read);
 DEFINE_EXPECT(Redirect);
+DEFINE_EXPECT(outer_QI_test);
+DEFINE_EXPECT(Protocol_destructor);
 
 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
 static const WCHAR index_url[] =
 
 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
 static const WCHAR index_url[] =
@@ -155,7 +158,7 @@ static PROTOCOLDATA protocoldata, *pdata, continue_protdata;
 static DWORD prot_read, filter_state, http_post_test, thread_id;
 static BOOL security_problem, test_async_req, impl_protex;
 static BOOL async_read_pending, mimefilter_test, direct_read, wait_for_switch, emulate_prot, short_read, test_abort;
 static DWORD prot_read, filter_state, http_post_test, thread_id;
 static BOOL security_problem, test_async_req, impl_protex;
 static BOOL async_read_pending, mimefilter_test, direct_read, wait_for_switch, emulate_prot, short_read, test_abort;
-static BOOL empty_file, no_mime, bind_from_cache, file_with_hash;
+static BOOL empty_file, no_mime, bind_from_cache, file_with_hash, reuse_protocol_thread;
 
 enum {
     STATE_CONNECTING,
 
 enum {
     STATE_CONNECTING,
@@ -174,6 +177,17 @@ static enum {
     BIND_TEST
 } tested_protocol;
 
     BIND_TEST
 } tested_protocol;
 
+typedef struct {
+    IUnknown IUnknown_inner;
+    IInternetProtocolEx IInternetProtocolEx_iface;
+    IInternetPriority IInternetPriority_iface;
+    IUnknown *outer;
+    LONG inner_ref;
+    LONG outer_ref;
+} Protocol;
+
+static Protocol *protocol_emul;
+
 static const WCHAR protocol_names[][10] = {
     {'f','i','l','e',0},
     {'h','t','t','p',0},
 static const WCHAR protocol_names[][10] = {
     {'f','i','l','e',0},
     {'h','t','t','p',0},
@@ -245,14 +259,17 @@ static  HRESULT WINAPI HttpSecurity_GetWindow(IHttpSecurity* iface, REFGUID rgui
 
 static HRESULT WINAPI HttpSecurity_OnSecurityProblem(IHttpSecurity *iface, DWORD dwProblem)
 {
 
 static HRESULT WINAPI HttpSecurity_OnSecurityProblem(IHttpSecurity *iface, DWORD dwProblem)
 {
-    trace("Security problem: %u\n", dwProblem);
-    ok(dwProblem == ERROR_INTERNET_SEC_CERT_REV_FAILED, "Expected ERROR_INTERNET_SEC_CERT_REV_FAILED got %u\n", dwProblem);
+    win_skip("Security problem: %u\n", dwProblem);
+    ok(dwProblem == ERROR_INTERNET_SEC_CERT_REV_FAILED || dwProblem == ERROR_INTERNET_INVALID_CA,
+       "Expected got %u security problem\n", dwProblem);
 
     /* Only retry once */
     if (security_problem)
         return E_ABORT;
 
     security_problem = TRUE;
 
     /* Only retry once */
     if (security_problem)
         return E_ABORT;
 
     security_problem = TRUE;
+    if(dwProblem == ERROR_INTERNET_INVALID_CA)
+        return E_ABORT;
     SET_EXPECT(BeginningTransaction);
 
     return RPC_E_RETRY;
     SET_EXPECT(BeginningTransaction);
 
     return RPC_E_RETRY;
@@ -1156,6 +1173,9 @@ static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HR
 {
     CHECK_EXPECT(ReportResult);
 
 {
     CHECK_EXPECT(ReportResult);
 
+    if(security_problem)
+        return S_OK;
+
     if(tested_protocol == FTP_TEST)
         ok(hrResult == E_PENDING || hrResult == S_OK, "hrResult = %08x, expected E_PENDING or S_OK\n", hrResult);
     else
     if(tested_protocol == FTP_TEST)
         ok(hrResult == E_PENDING || hrResult == S_OK, "hrResult = %08x, expected E_PENDING or S_OK\n", hrResult);
     else
@@ -1503,6 +1523,11 @@ static IInternetBindInfoVtbl bind_info_vtbl = {
 
 static IInternetBindInfo bind_info = { &bind_info_vtbl };
 
 
 static IInternetBindInfo bind_info = { &bind_info_vtbl };
 
+static Protocol *impl_from_IInternetPriority(IInternetPriority *iface)
+{
+    return CONTAINING_RECORD(iface, Protocol, IInternetPriority_iface);
+}
+
 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
                                                   REFIID riid, void **ppv)
 {
 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
                                                   REFIID riid, void **ppv)
 {
@@ -1512,12 +1537,16 @@ static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
 
 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
 {
 
 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
 {
-    return 2;
+    Protocol *This = impl_from_IInternetPriority(iface);
+    This->outer_ref++;
+    return IUnknown_AddRef(This->outer);
 }
 
 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
 {
 }
 
 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
 {
-    return 1;
+    Protocol *This = impl_from_IInternetPriority(iface);
+    This->outer_ref--;
+    return IUnknown_Release(This->outer);
 }
 
 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
 }
 
 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
@@ -1542,8 +1571,6 @@ static const IInternetPriorityVtbl InternetPriorityVtbl = {
     InternetPriority_GetPriority
 };
 
     InternetPriority_GetPriority
 };
 
-static IInternetPriority InternetPriority = { &InternetPriorityVtbl };
-
 static ULONG WINAPI Protocol_AddRef(IInternetProtocolEx *iface)
 {
     return 2;
 static ULONG WINAPI Protocol_AddRef(IInternetProtocolEx *iface)
 {
     return 2;
@@ -1588,83 +1615,81 @@ static HRESULT WINAPI Protocol_Seek(IInternetProtocolEx *iface,
     return E_NOTIMPL;
 }
 
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ProtocolEmul_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
+static Protocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
 {
 {
-    static const IID unknown_iid = {0x7daf9908,0x8415,0x4005,{0x95,0xae, 0xbd,0x27,0xf6,0xe3,0xdc,0x00}};
+    return CONTAINING_RECORD(iface, Protocol, IInternetProtocolEx_iface);
+}
 
 
-    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
-        *ppv = iface;
-        return S_OK;
-    }
+static HRESULT WINAPI ProtocolEmul_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
+{
+    Protocol *This = impl_from_IInternetProtocolEx(iface);
 
 
-    if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
-        if(impl_protex) {
-            *ppv = iface;
-            return S_OK;
-        }
-        *ppv = NULL;
-        return E_NOINTERFACE;
-    }
+    static const IID unknown_iid = {0x7daf9908,0x8415,0x4005,{0x95,0xae, 0xbd,0x27,0xf6,0xe3,0xdc,0x00}};
+    static const IID unknown_iid2 = {0x5b7ebc0c,0xf630,0x4cea,{0x89,0xd3,0x5a,0xf0,0x38,0xed,0x05,0x5c}};
 
 
-    if(IsEqualGUID(&IID_IInternetPriority, riid)) {
-        *ppv = &InternetPriority;
+    /* FIXME: Why is it calling here instead of outer IUnknown? */
+    if(IsEqualGUID(riid, &IID_IInternetPriority)) {
+        *ppv = &This->IInternetPriority_iface;
+        IInternetPriority_AddRef(&This->IInternetPriority_iface);
         return S_OK;
     }
         return S_OK;
     }
-
-    if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
-        CHECK_EXPECT(QueryInterface_IWinInetInfo);
-        *ppv = NULL;
-        return E_NOINTERFACE;
-    }
-
-    if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
-        CHECK_EXPECT(QueryInterface_IWinInetHttpInfo);
-        *ppv = NULL;
-        return E_NOINTERFACE;
-    }
-
-    if(!IsEqualGUID(riid, &unknown_iid)) /* IE10 */
+    if(!IsEqualGUID(riid, &unknown_iid) && !IsEqualGUID(riid, &unknown_iid2)) /* IE10 */
         ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
     *ppv = NULL;
     return E_NOINTERFACE;
 }
 
         ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid));
     *ppv = NULL;
     return E_NOINTERFACE;
 }
 
+static ULONG WINAPI ProtocolEmul_AddRef(IInternetProtocolEx *iface)
+{
+    Protocol *This = impl_from_IInternetProtocolEx(iface);
+    This->outer_ref++;
+    return IUnknown_AddRef(This->outer);
+}
+
+static ULONG WINAPI ProtocolEmul_Release(IInternetProtocolEx *iface)
+{
+    Protocol *This = impl_from_IInternetProtocolEx(iface);
+    This->outer_ref--;
+    return IUnknown_Release(This->outer);
+}
+
 static DWORD WINAPI thread_proc(PVOID arg)
 {
 static DWORD WINAPI thread_proc(PVOID arg)
 {
-    BOOL redirect_only = redirect_on_continue;
+    BOOL redirect = redirect_on_continue;
     HRESULT hres;
 
     memset(&protocoldata, -1, sizeof(protocoldata));
 
     HRESULT hres;
 
     memset(&protocoldata, -1, sizeof(protocoldata));
 
-    prot_state = 0;
+    while(1) {
+        prot_state = 0;
 
 
-    SET_EXPECT(ReportProgress_FINDINGRESOURCE);
-    hres = IInternetProtocolSink_ReportProgress(binding_sink,
-            BINDSTATUS_FINDINGRESOURCE, hostW);
-    CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
-    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+        SET_EXPECT(ReportProgress_FINDINGRESOURCE);
+        hres = IInternetProtocolSink_ReportProgress(binding_sink,
+                BINDSTATUS_FINDINGRESOURCE, hostW);
+        CHECK_CALLED(ReportProgress_FINDINGRESOURCE);
+        ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
 
 
-    SET_EXPECT(ReportProgress_CONNECTING);
-    hres = IInternetProtocolSink_ReportProgress(binding_sink,
-            BINDSTATUS_CONNECTING, winehq_ipW);
-    CHECK_CALLED(ReportProgress_CONNECTING);
-    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+        SET_EXPECT(ReportProgress_CONNECTING);
+        hres = IInternetProtocolSink_ReportProgress(binding_sink,
+                BINDSTATUS_CONNECTING, winehq_ipW);
+        CHECK_CALLED(ReportProgress_CONNECTING);
+        ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
 
 
-    SET_EXPECT(ReportProgress_SENDINGREQUEST);
-    hres = IInternetProtocolSink_ReportProgress(binding_sink,
-            BINDSTATUS_SENDINGREQUEST, NULL);
-    CHECK_CALLED(ReportProgress_SENDINGREQUEST);
-    ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
+        SET_EXPECT(ReportProgress_SENDINGREQUEST);
+        hres = IInternetProtocolSink_ReportProgress(binding_sink,
+                BINDSTATUS_SENDINGREQUEST, NULL);
+        CHECK_CALLED(ReportProgress_SENDINGREQUEST);
+        ok(hres == S_OK, "ReportProgress failed: %08x\n", hres);
 
 
-    prot_state = 1;
-    SET_EXPECT(Switch);
-    hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
-    CHECK_CALLED(Switch);
-    ok(hres == S_OK, "Switch failed: %08x\n", hres);
+        prot_state = 1;
+        SET_EXPECT(Switch);
+        hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
+        CHECK_CALLED(Switch);
+        ok(hres == S_OK, "Switch failed: %08x\n", hres);
 
 
-    if(redirect_only) {
-        prot_state = 0;
-        return 0;
+        if(!redirect)
+            break;
+        redirect = FALSE;
     }
 
     if(!short_read) {
     }
 
     if(!short_read) {
@@ -1819,7 +1844,8 @@ static void protocol_start(IInternetProtocolSink *pOIProtSink, IInternetBindInfo
 
         IServiceProvider_Release(service_provider);
 
 
         IServiceProvider_Release(service_provider);
 
-        CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
+        if(!reuse_protocol_thread)
+            CreateThread(NULL, 0, thread_proc, NULL, 0, &tid);
         return;
     }
 
         return;
     }
 
@@ -1929,11 +1955,13 @@ static HRESULT WINAPI ProtocolEmul_Continue(IInternetProtocolEx *iface,
 
         if(redirect_on_continue) {
             redirect_on_continue = FALSE;
 
         if(redirect_on_continue) {
             redirect_on_continue = FALSE;
+            reuse_protocol_thread = TRUE;
 
             if(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)
                 SET_EXPECT(Redirect);
             SET_EXPECT(ReportProgress_REDIRECTING);
             SET_EXPECT(Terminate);
 
             if(bindinfo_options & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS)
                 SET_EXPECT(Redirect);
             SET_EXPECT(ReportProgress_REDIRECTING);
             SET_EXPECT(Terminate);
+            SET_EXPECT(Protocol_destructor);
             SET_EXPECT(QueryService_InternetProtocol);
             SET_EXPECT(CreateInstance);
             SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
             SET_EXPECT(QueryService_InternetProtocol);
             SET_EXPECT(CreateInstance);
             SET_EXPECT(ReportProgress_PROTOCOLCLASSID);
@@ -1945,6 +1973,7 @@ static HRESULT WINAPI ProtocolEmul_Continue(IInternetProtocolEx *iface,
                 CHECK_CALLED(Redirect);
             CHECK_CALLED(ReportProgress_REDIRECTING);
             CHECK_CALLED(Terminate);
                 CHECK_CALLED(Redirect);
             CHECK_CALLED(ReportProgress_REDIRECTING);
             CHECK_CALLED(Terminate);
+            CHECK_CALLED(Protocol_destructor);
             CHECK_CALLED(QueryService_InternetProtocol);
             CHECK_CALLED(CreateInstance);
             CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
             CHECK_CALLED(QueryService_InternetProtocol);
             CHECK_CALLED(CreateInstance);
             CHECK_CALLED(ReportProgress_PROTOCOLCLASSID);
@@ -2170,8 +2199,8 @@ static HRESULT WINAPI ProtocolEmul_StartEx(IInternetProtocolEx *iface, IUri *pUr
 
 static const IInternetProtocolExVtbl ProtocolVtbl = {
     ProtocolEmul_QueryInterface,
 
 static const IInternetProtocolExVtbl ProtocolVtbl = {
     ProtocolEmul_QueryInterface,
-    Protocol_AddRef,
-    Protocol_Release,
+    ProtocolEmul_AddRef,
+    ProtocolEmul_Release,
     ProtocolEmul_Start,
     ProtocolEmul_Continue,
     Protocol_Abort,
     ProtocolEmul_Start,
     ProtocolEmul_Continue,
     Protocol_Abort,
@@ -2185,7 +2214,80 @@ static const IInternetProtocolExVtbl ProtocolVtbl = {
     ProtocolEmul_StartEx
 };
 
     ProtocolEmul_StartEx
 };
 
-static IInternetProtocolEx Protocol = { &ProtocolVtbl };
+static Protocol *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, Protocol, IUnknown_inner);
+}
+
+static HRESULT WINAPI ProtocolUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    Protocol *This = impl_from_IUnknown(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        trace("QI(IUnknown)\n");
+        *ppv = &This->IUnknown_inner;
+    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
+        trace("QI(InternetProtocol)\n");
+        *ppv = &This->IInternetProtocolEx_iface;
+    }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
+        trace("QI(InternetProtocolEx)\n");
+        if(!impl_protex) {
+            *ppv = NULL;
+            return E_NOINTERFACE;
+        }
+        *ppv = &This->IInternetProtocolEx_iface;
+    }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
+        trace("QI(InternetPriority)\n");
+        *ppv = &This->IInternetPriority_iface;
+    }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
+        trace("QI(IWinInetInfo)\n");
+        CHECK_EXPECT(QueryInterface_IWinInetInfo);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
+        trace("QI(IWinInetHttpInfo)\n");
+        CHECK_EXPECT(QueryInterface_IWinInetHttpInfo);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }else {
+        ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ProtocolUnk_AddRef(IUnknown *iface)
+{
+    Protocol *This = impl_from_IUnknown(iface);
+    return ++This->inner_ref;
+}
+
+static ULONG WINAPI ProtocolUnk_Release(IUnknown *iface)
+{
+    Protocol *This = impl_from_IUnknown(iface);
+    LONG ref = --This->inner_ref;
+    if(!ref) {
+        /* IE9 is broken on redirects. It will cause -1 outer_ref on original protocol handler
+         * and 1 on redirected handler. */
+        ok(!This->outer_ref
+           || broken(test_redirect && (This->outer_ref == -1 || This->outer_ref == 1)),
+           "outer_ref = %d\n", This->outer_ref);
+        if(This->outer_ref)
+            trace("outer_ref %d\n", This->outer_ref);
+        CHECK_EXPECT(Protocol_destructor);
+        heap_free(This);
+    }
+    return ref;
+}
+
+static const IUnknownVtbl ProtocolUnkVtbl = {
+    ProtocolUnk_QueryInterface,
+    ProtocolUnk_AddRef,
+    ProtocolUnk_Release
+};
 
 static HRESULT WINAPI MimeProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
 {
 
 static HRESULT WINAPI MimeProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
 {
@@ -2471,13 +2573,24 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
                                         REFIID riid, void **ppv)
 {
 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
                                         REFIID riid, void **ppv)
 {
+    Protocol *ret;
+
     CHECK_EXPECT(CreateInstance);
 
     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
     ok(ppv != NULL, "ppv == NULL\n");
 
     CHECK_EXPECT(CreateInstance);
 
     ok(pOuter == (IUnknown*)prot_bind_info, "pOuter != protocol_unk\n");
     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
     ok(ppv != NULL, "ppv == NULL\n");
 
-    *ppv = &Protocol;
+    ret = heap_alloc(sizeof(*ret));
+    ret->IUnknown_inner.lpVtbl = &ProtocolUnkVtbl;
+    ret->IInternetProtocolEx_iface.lpVtbl = &ProtocolVtbl;
+    ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
+    ret->outer = pOuter;
+    ret->inner_ref = 1;
+    ret->outer_ref = 0;
+
+    protocol_emul = ret;
+    *ppv = &ret->IUnknown_inner;
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -2591,6 +2704,8 @@ static void init_test(int prot, DWORD flags)
     empty_file = (flags & TEST_EMPTY) != 0;
     bind_from_cache = (flags & TEST_FROMCACHE) != 0;
     file_with_hash = FALSE;
     empty_file = (flags & TEST_EMPTY) != 0;
     bind_from_cache = (flags & TEST_FROMCACHE) != 0;
     file_with_hash = FALSE;
+    security_problem = FALSE;
+    reuse_protocol_thread = FALSE;
 
     bindinfo_options = 0;
     if(flags & TEST_DISABLEAUTOREDIRECT)
 
     bindinfo_options = 0;
     if(flags & TEST_DISABLEAUTOREDIRECT)
@@ -3707,9 +3822,11 @@ static void test_CreateBinding(void)
     SET_EXPECT(SetPriority);
     SET_EXPECT(Start);
 
     SET_EXPECT(SetPriority);
     SET_EXPECT(Start);
 
+    trace("Start >\n");
     expect_hrResult = S_OK;
     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
     ok(hres == S_OK, "Start failed: %08x\n", hres);
     expect_hrResult = S_OK;
     hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bind_info, 0, 0);
     ok(hres == S_OK, "Start failed: %08x\n", hres);
+    trace("Start <\n");
 
     CHECK_CALLED(QueryService_InternetProtocol);
     CHECK_CALLED(CreateInstance);
 
     CHECK_CALLED(QueryService_InternetProtocol);
     CHECK_CALLED(CreateInstance);
@@ -3759,11 +3876,23 @@ static void test_CreateBinding(void)
     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
     CHECK_CALLED(Terminate);
 
     ok(hres == S_OK, "Terminate failed: %08x\n", hres);
     CHECK_CALLED(Terminate);
 
+    ok(protocol_emul->outer_ref == 0, "protocol_outer_ref = %u\n", protocol_emul->outer_ref);
+
     SET_EXPECT(Continue);
     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
     ok(hres == S_OK, "Switch failed: %08x\n", hres);
     CHECK_CALLED(Continue);
 
     SET_EXPECT(Continue);
     hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata);
     ok(hres == S_OK, "Switch failed: %08x\n", hres);
     CHECK_CALLED(Continue);
 
+    SET_EXPECT(Read);
+    read = 0xdeadbeef;
+    hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read);
+    todo_wine
+    ok(hres == E_ABORT, "Read failed: %08x\n", hres);
+    todo_wine
+    ok(read == 0, "read = %d\n", read);
+    todo_wine
+    CHECK_NOT_CALLED(Read);
+
     hres = IInternetProtocolSink_ReportProgress(binding_sink,
             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
     hres = IInternetProtocolSink_ReportProgress(binding_sink,
             BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW);
     ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
@@ -3777,7 +3906,10 @@ static void test_CreateBinding(void)
     IInternetProtocolSink_Release(binding_sink);
     IInternetPriority_Release(priority);
     IInternetBindInfo_Release(prot_bind_info);
     IInternetProtocolSink_Release(binding_sink);
     IInternetPriority_Release(priority);
     IInternetBindInfo_Release(prot_bind_info);
+
+    SET_EXPECT(Protocol_destructor);
     IInternetProtocol_Release(protocol);
     IInternetProtocol_Release(protocol);
+    CHECK_CALLED(Protocol_destructor);
 
     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
 
     hres = IInternetSession_CreateBinding(session, NULL, test_url, NULL, NULL, &protocol, 0);
     ok(hres == S_OK, "CreateBinding failed: %08x\n", hres);
@@ -3949,8 +4081,11 @@ static void test_binding(int prot, DWORD grf_pi, DWORD test_flags)
         IInternetProtocol_Release(filtered_protocol);
     IInternetBindInfo_Release(prot_bind_info);
     IInternetProtocolSink_Release(binding_sink);
         IInternetProtocol_Release(filtered_protocol);
     IInternetBindInfo_Release(prot_bind_info);
     IInternetProtocolSink_Release(binding_sink);
+
+    SET_EXPECT(Protocol_destructor);
     ref = IInternetProtocol_Release(protocol);
     ok(!ref, "ref=%u, expected 0\n", ref);
     ref = IInternetProtocol_Release(protocol);
     ok(!ref, "ref=%u, expected 0\n", ref);
+    CHECK_CALLED(Protocol_destructor);
 
     if(test_flags & TEST_EMULATEPROT) {
         hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, protocol_names[prot]);
 
     if(test_flags & TEST_EMULATEPROT) {
         hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, protocol_names[prot]);
@@ -3960,6 +4095,68 @@ static void test_binding(int prot, DWORD grf_pi, DWORD test_flags)
     IInternetSession_Release(session);
 }
 
     IInternetSession_Release(session);
 }
 
+static const IID outer_test_iid = {0xabcabc00,0,0,{0,0,0,0,0,0,0,0x66}};
+
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(riid, &outer_test_iid)) {
+        CHECK_EXPECT(outer_QI_test);
+        *ppv = (IUnknown*)0xdeadbeef;
+        return S_OK;
+    }
+    ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI outer_AddRef(IUnknown *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI outer_Release(IUnknown *iface)
+{
+    return 1;
+}
+
+static const IUnknownVtbl outer_vtbl = {
+    outer_QueryInterface,
+    outer_AddRef,
+    outer_Release
+};
+
+static void test_com_aggregation(const CLSID *clsid)
+{
+    IUnknown outer = { &outer_vtbl };
+    IClassFactory *class_factory;
+    IUnknown *unk, *unk2, *unk3;
+    HRESULT hres;
+
+    hres = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&class_factory);
+    ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
+
+    hres = IClassFactory_CreateInstance(class_factory, &outer, &IID_IUnknown, (void**)&unk);
+    ok(hres == S_OK, "CreateInstance returned: %08x\n", hres);
+
+    hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&unk2);
+    ok(hres == S_OK, "Could not get IDispatch iface: %08x\n", hres);
+
+    SET_EXPECT(outer_QI_test);
+    hres = IUnknown_QueryInterface(unk2, &outer_test_iid, (void**)&unk3);
+    CHECK_CALLED(outer_QI_test);
+    ok(hres == S_OK, "Could not get IInternetProtocol iface: %08x\n", hres);
+    ok(unk3 == (IUnknown*)0xdeadbeef, "unexpected unk2\n");
+
+    IUnknown_Release(unk2);
+    IUnknown_Release(unk);
+
+    unk = (void*)0xdeadbeef;
+    hres = IClassFactory_CreateInstance(class_factory, &outer, &IID_IInternetProtocol, (void**)&unk);
+    ok(hres == CLASS_E_NOAGGREGATION, "CreateInstance returned: %08x\n", hres);
+    ok(!unk, "unk = %p\n", unk);
+
+    IClassFactory_Release(class_factory);
+}
+
 START_TEST(protocol)
 {
     HMODULE hurlmon;
 START_TEST(protocol)
 {
     HMODULE hurlmon;
@@ -4033,5 +4230,11 @@ START_TEST(protocol)
     CloseHandle(event_continue);
     CloseHandle(event_continue_done);
 
     CloseHandle(event_continue);
     CloseHandle(event_continue_done);
 
+    test_com_aggregation(&CLSID_FileProtocol);
+    test_com_aggregation(&CLSID_HttpProtocol);
+    test_com_aggregation(&CLSID_HttpSProtocol);
+    test_com_aggregation(&CLSID_FtpProtocol);
+    test_com_aggregation(&CLSID_MkProtocol);
+
     OleUninitialize();
 }
     OleUninitialize();
 }
index 70234ff..9fe2385 100644 (file)
@@ -160,7 +160,7 @@ static WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_
 static const WCHAR wszWineHQSite[] =
     {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
 static const WCHAR wszWineHQIP[] =
 static const WCHAR wszWineHQSite[] =
     {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
 static const WCHAR wszWineHQIP[] =
-    {'2','0','9','.','3','2','.','1','4','1','.','3',0};
+    {'4','.','1','5','.','1','8','4','.','7','7',0};
 static const CHAR wszIndexHtmlA[] = "index.html";
 static const WCHAR cache_fileW[] = {'c',':','\\','c','a','c','h','e','.','h','t','m',0};
 static const CHAR dwl_htmlA[] = "dwl.html";
 static const CHAR wszIndexHtmlA[] = "index.html";
 static const WCHAR cache_fileW[] = {'c',':','\\','c','a','c','h','e','.','h','t','m',0};
 static const CHAR dwl_htmlA[] = "dwl.html";
@@ -2413,8 +2413,8 @@ static HRESULT WINAPI ProtocolCF_CreateInstance(IClassFactory *iface, IUnknown *
     if(IsEqualGUID(&IID_IInternetProtocolInfo, riid))
         return E_NOINTERFACE;
 
     if(IsEqualGUID(&IID_IInternetProtocolInfo, riid))
         return E_NOINTERFACE;
 
-    todo_wine ok(outer != NULL, "outer == NULL\n");
-    todo_wine ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
+    ok(outer != NULL, "outer == NULL\n");
+    ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid));
     *ppv = &Protocol;
     return S_OK;
 }
     *ppv = &Protocol;
     return S_OK;
 }
@@ -2902,7 +2902,7 @@ static void init_bind_test(int protocol, DWORD flags, DWORD t)
         url_a = "its:test.chm::/blank.html";
         break;
     case HTTPS_TEST:
         url_a = "its:test.chm::/blank.html";
         break;
     case HTTPS_TEST:
-        url_a = (flags & BINDTEST_INVALID_CN) ? "https://209.46.25.134/favicon.ico" : "https://test.winehq.org/tests/hello.html";
+        url_a = (flags & BINDTEST_INVALID_CN) ? "https://4.15.184.77/favicon.ico" : "https://test.winehq.org/tests/hello.html";
         break;
     case FTP_TEST:
         url_a = "ftp://ftp.winehq.org/welcome.msg";
         break;
     case FTP_TEST:
         url_a = "ftp://ftp.winehq.org/welcome.msg";