From d79463a8b33ad246fa310bf1590d3b246ade2cb4 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 9 Sep 2020 12:37:05 +1000 Subject: [PATCH] Added msxml3-FreeThreadedXMLHTTP60 patchset --- ...Use-msxml6-header-for-defining-GUIDs.patch | 40 + ...l3-tests-Use-msxml6.h-where-required.patch | 45 + ...nterfaces-already-define-in-msxml6.i.patch | 196 ++++ ...de-Add-IXMLHTTPRequest2-3-interfaces.patch | 151 +++ ...xml3-Implement-FreeThreadedXMLHTTP60.patch | 1024 +++++++++++++++++ .../msxml3-FreeThreadedXMLHTTP60/definition | 1 + patches/patchinstall.sh | 22 + 7 files changed, 1479 insertions(+) create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/0001-msxml3-Use-msxml6-header-for-defining-GUIDs.patch create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/0002-msxml3-tests-Use-msxml6.h-where-required.patch create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/0003-include-Remove-interfaces-already-define-in-msxml6.i.patch create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/0004-include-Add-IXMLHTTPRequest2-3-interfaces.patch create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/0005-msxml3-Implement-FreeThreadedXMLHTTP60.patch create mode 100644 patches/msxml3-FreeThreadedXMLHTTP60/definition diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/0001-msxml3-Use-msxml6-header-for-defining-GUIDs.patch b/patches/msxml3-FreeThreadedXMLHTTP60/0001-msxml3-Use-msxml6-header-for-defining-GUIDs.patch new file mode 100644 index 00000000..1e77a8da --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/0001-msxml3-Use-msxml6-header-for-defining-GUIDs.patch @@ -0,0 +1,40 @@ +From 1b9bde927b65e034acde1a3cdca1aac6afcab854 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Sep 2020 17:58:53 +1000 +Subject: [PATCH 1/5] msxml3: Use msxml6 header for defining GUIDs. + +Signed-off-by: Alistair Leslie-Hughes +--- + dlls/msxml3/factory.c | 2 +- + dlls/msxml3/uuid.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c +index 445cfbf730..3be974c58a 100644 +--- a/dlls/msxml3/factory.c ++++ b/dlls/msxml3/factory.c +@@ -34,7 +34,7 @@ + #include "winuser.h" + #include "ole2.h" + #include "msxml.h" +-#include "msxml2.h" ++#include "msxml6.h" + #include "xmlparser.h" + + /* undef the #define in msxml2 so that we can access the v.2 version +diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c +index 4abbe5e476..7403b27c72 100644 +--- a/dlls/msxml3/uuid.c ++++ b/dlls/msxml3/uuid.c +@@ -39,7 +39,7 @@ + + /* Now we can initialize the rest of the uuids */ + #include "initguid.h" +-#include "msxml2.h" ++#include "msxml6.h" + + /* + * Note that because of a #define in msxml2.h, we end up initializing +-- +2.28.0 + diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/0002-msxml3-tests-Use-msxml6.h-where-required.patch b/patches/msxml3-FreeThreadedXMLHTTP60/0002-msxml3-tests-Use-msxml6.h-where-required.patch new file mode 100644 index 00000000..6a03040b --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/0002-msxml3-tests-Use-msxml6.h-where-required.patch @@ -0,0 +1,45 @@ +From 904a06e52cb70dd9821b6aea99bc646f9c573d12 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Sep 2020 17:59:01 +1000 +Subject: [PATCH 2/5] msxml3/tests: Use msxml6.h where required + +Signed-off-by: Alistair Leslie-Hughes +--- + dlls/msxml3/tests/saxreader.c | 4 ++-- + dlls/msxml3/tests/schema.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c +index 986f429cc1..5c5fa8075d 100644 +--- a/dlls/msxml3/tests/saxreader.c ++++ b/dlls/msxml3/tests/saxreader.c +@@ -28,8 +28,8 @@ + + #include "windows.h" + #include "ole2.h" +-#include "msxml2.h" +-#include "msxml2did.h" ++#include "msxml6.h" ++#include "msxml6did.h" + #include "ocidl.h" + #include "dispex.h" + +diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c +index 4637d62f8b..fc0329bd10 100644 +--- a/dlls/msxml3/tests/schema.c ++++ b/dlls/msxml3/tests/schema.c +@@ -26,9 +26,9 @@ + #include "initguid.h" + #include "windows.h" + #include "ole2.h" +-#include "msxml2.h" ++#include "msxml6.h" + #undef CLSID_DOMDocument +-#include "msxml2did.h" ++#include "msxml6did.h" + #include "dispex.h" + #include "cguid.h" + +-- +2.28.0 + diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/0003-include-Remove-interfaces-already-define-in-msxml6.i.patch b/patches/msxml3-FreeThreadedXMLHTTP60/0003-include-Remove-interfaces-already-define-in-msxml6.i.patch new file mode 100644 index 00000000..30391a82 --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/0003-include-Remove-interfaces-already-define-in-msxml6.i.patch @@ -0,0 +1,196 @@ +From 87f6f9640a5590ae216c4f863d34826122e4914a Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Sep 2020 17:59:06 +1000 +Subject: [PATCH 3/5] include: Remove interfaces already define in msxml6.idl + +Signed-off-by: Alistair Leslie-Hughes +--- + include/msxml2.idl | 109 --------------------------------------------- + 1 file changed, 109 deletions(-) + +diff --git a/include/msxml2.idl b/include/msxml2.idl +index cfafc42133..a2d72d2063 100644 +--- a/include/msxml2.idl ++++ b/include/msxml2.idl +@@ -1605,15 +1605,6 @@ coclass FreeThreadedDOMDocument40 + [default, source] dispinterface XMLDOMDocumentEvents; + } + +-[ +- uuid(88d96a06-f192-11d4-a65f-0040963251e5), +-] +-coclass FreeThreadedDOMDocument60 +-{ +- [default] interface IXMLDOMDocument3; +- [default, source] dispinterface XMLDOMDocumentEvents; +-} +- + [ + helpstring("Free threaded XML DOM Document"), + progid("Msxml2.FreeThreadedDOMDocument"), +@@ -1655,14 +1646,6 @@ coclass XMLHTTP40 + [default] interface IXMLHTTPRequest; + } + +-[ +- uuid(88d96a0a-f192-11d4-a65f-0040963251e5) +-] +-coclass XMLHTTP60 +-{ +- [default] interface IXMLHTTPRequest; +-} +- + [ + helpstring("XML HTTP"), + progid("Msxml2.XMLHTTP"), +@@ -1695,14 +1678,6 @@ coclass ServerXMLHTTP40 + [default] interface IServerXMLHTTPRequest2; + } + +-[ +- uuid(88d96a0b-f192-11d4-a65f-0040963251e5) +-] +-coclass ServerXMLHTTP60 +-{ +- [default] interface IServerXMLHTTPRequest2; +-} +- + [ + helpstring("Server XML HTTP"), + progid("Msxml2.ServerXMLHTTP"), +@@ -1743,14 +1718,6 @@ coclass XMLSchemaCache40 + [default] interface IXMLDOMSchemaCollection2; + } + +-[ +- uuid(88d96a07-f192-11d4-a65f-0040963251e5) +-] +-coclass XMLSchemaCache60 +-{ +- [default] interface IXMLDOMSchemaCollection2; +-} +- + [ + helpstring("XML Schema Cache"), + progid("Msxml2.XMLSchemaCache"), +@@ -1791,14 +1758,6 @@ coclass XSLTemplate40 + [default] interface IXSLTemplate; + } + +-[ +- uuid(88d96a08-f192-11d4-a65f-0040963251e5) +-] +-coclass XSLTemplate60 +-{ +- [default] interface IXSLTemplate; +-} +- + [ + helpstring("XSL Template"), + progid("Msxml2.XSLTemplate"), +@@ -3290,15 +3249,6 @@ coclass SAXXMLReader40 + interface ISAXXMLReader; + } + +-[ +- uuid(88d96a0c-f192-11d4-a65f-0040963251e5) +-] +-coclass SAXXMLReader60 +-{ +- [default] interface IVBSAXXMLReader; +- interface ISAXXMLReader; +-} +- + [ + helpstring("SAX XML Reader"), + progid("Msxml2.SAXXMLReader"), +@@ -3373,26 +3323,6 @@ coclass MXHTMLWriter40 + interface IVBSAXLexicalHandler; + } + +-[ +- uuid(88d96a10-f192-11d4-a65f-0040963251e5) +-] +-coclass MXHTMLWriter60 +-{ +- [default] interface IMXWriter; +- +- interface ISAXContentHandler; +- interface ISAXDeclHandler; +- interface ISAXDTDHandler; +- interface ISAXErrorHandler; +- interface ISAXLexicalHandler; +- +- interface IVBSAXContentHandler; +- interface IVBSAXDeclHandler; +- interface IVBSAXDTDHandler; +- interface IVBSAXErrorHandler; +- interface IVBSAXLexicalHandler; +-} +- + [ + helpstring("MXXMLWriter 3.0"), + progid("Msxml2.MXXMLWriter.3.0"), +@@ -3437,26 +3367,6 @@ coclass MXXMLWriter40 + interface IVBSAXLexicalHandler; + } + +-[ +- uuid(88d96a0f-f192-11d4-a65f-0040963251e5) +-] +-coclass MXXMLWriter60 +-{ +- [default] interface IMXWriter; +- +- interface ISAXContentHandler; +- interface ISAXDeclHandler; +- interface ISAXDTDHandler; +- interface ISAXErrorHandler; +- interface ISAXLexicalHandler; +- +- interface IVBSAXContentHandler; +- interface IVBSAXDeclHandler; +- interface IVBSAXDTDHandler; +- interface IVBSAXErrorHandler; +- interface IVBSAXLexicalHandler; +-} +- + [ + helpstring("MXXMLWriter"), + progid("Msxml2.MXXMLWriter"), +@@ -3499,15 +3409,6 @@ coclass MXNamespaceManager40 + interface IMXNamespaceManager; + } + +-[ +- uuid(88d96a11-f192-11d4-a65f-0040963251e5) +-] +-coclass MXNamespaceManager60 +-{ +- [default] interface IVBMXNamespaceManager; +- interface IMXNamespaceManager; +-} +- + [ + helpstring("SAXAttributes 3.0"), + progid("Msxml2.SAXAttributes.3.0"), +@@ -3532,16 +3433,6 @@ coclass SAXAttributes40 + interface ISAXAttributes; + } + +-[ +- uuid(88d96a0e-f192-11d4-a65f-0040963251e5) +-] +-coclass SAXAttributes60 +-{ +- [default] interface IMXAttributes; +- interface IVBSAXAttributes; +- interface ISAXAttributes; +-} +- + [ + helpstring("SAXAttributes"), + progid("Msxml2.SAXAttributes"), +-- +2.28.0 + diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/0004-include-Add-IXMLHTTPRequest2-3-interfaces.patch b/patches/msxml3-FreeThreadedXMLHTTP60/0004-include-Add-IXMLHTTPRequest2-3-interfaces.patch new file mode 100644 index 00000000..821f4fef --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/0004-include-Add-IXMLHTTPRequest2-3-interfaces.patch @@ -0,0 +1,151 @@ +From e46f6e920f9f41f7f5ab5b0bb5254dec7d0c0dc2 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Thu, 3 Sep 2020 17:59:10 +1000 +Subject: [PATCH 4/5] include: Add IXMLHTTPRequest2/3 interfaces + +Signed-off-by: Alistair Leslie-Hughes +--- + include/msxml6.idl | 106 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 106 insertions(+) + +diff --git a/include/msxml6.idl b/include/msxml6.idl +index 1f657a8cde..b837e42477 100644 +--- a/include/msxml6.idl ++++ b/include/msxml6.idl +@@ -109,6 +109,8 @@ interface ISchemaAny; + interface ISchemaIdentityConstraint; + interface ISchemaNotation; + ++interface IXMLHTTPRequest2Callback; ++interface IXMLHTTPRequest3Callback; + + cpp_quote("#define DOMDocument DOMDocument2") + cpp_quote("#define CLSID_DOMDocument CLSID_DOMDocument2") +@@ -261,6 +263,35 @@ typedef enum _SCHEMATYPEVARIETY + SCHEMATYPEVARIETY_UNION = 2, + } SCHEMATYPEVARIETY; + ++typedef struct tagXHR_COOKIE ++{ ++ [ref, string] WCHAR *pwszUrl; ++ [ref, string] WCHAR *pwszName; ++ [unique, string] WCHAR *pwszValue; ++ [unique, string] WCHAR *pwszP3PPolicy; ++ FILETIME ftExpires; ++ DWORD dwFlags; ++} XHR_COOKIE; ++ ++typedef [v1_enum] enum _XHR_PROPERTY ++{ ++ XHR_PROP_NO_CRED_PROMPT = 0x0, ++ XHR_PROP_NO_AUTH = 0x1, ++ XHR_PROP_TIMEOUT = 0x2, ++ XHR_PROP_NO_DEFAULT_HEADERS = 0x3, ++ XHR_PROP_REPORT_REDIRECT_STATUS = 0x4, ++ XHR_PROP_NO_CACHE = 0x5, ++ XHR_PROP_EXTENDED_ERROR = 0x6, ++ XHR_PROP_QUERY_STRING_UTF8 = 0x7, ++ XHR_PROP_IGNORE_CERT_ERRORS = 0x8, ++} XHR_PROPERTY; ++ ++typedef struct tagXHR_CERT ++{ ++ DWORD cbCert; ++ [ref, size_is(cbCert)] BYTE *pbCert; ++} XHR_CERT; ++ + [ + local, + object, +@@ -1265,6 +1296,70 @@ interface IXMLHTTPRequest : IDispatch + HRESULT onreadystatechange([in] IDispatch *pReadyStateSink); + } + ++[ ++ object, ++ uuid(e5d37dc0-552a-4d52-9cc0-a14d546fbd04), ++ helpstring("IXMLHTTPRequest2 Interface") ++] ++interface IXMLHTTPRequest2 : IUnknown ++{ ++ HRESULT Open([in, string, ref] const WCHAR *method, [in, string, ref] const WCHAR *url, ++ [in] IXMLHTTPRequest2Callback *callback, ++ [in, string, unique] const WCHAR *username, [in, string, unique] const WCHAR *password, ++ [in, string, unique] const WCHAR *proxy_username, [in, string, unique] const WCHAR *proxy_password); ++ HRESULT Send([in] ISequentialStream *body, [in] ULONGLONG body_size); ++ HRESULT Abort(); ++ HRESULT SetCookie([in, ref] const XHR_COOKIE *cookie, [out] DWORD *state); ++ HRESULT SetCustomResponseStream([in] ISequentialStream *stream); ++ HRESULT SetProperty([in] XHR_PROPERTY property, [in] ULONGLONG value); ++ HRESULT SetRequestHeader([in, string, ref] const WCHAR *header, [in, string, unique] const WCHAR *value); ++ HRESULT GetAllResponseHeaders([out, string] WCHAR **headers); ++ HRESULT GetCookie([in, ref, string] const WCHAR *url, [in, unique, string] const WCHAR *name, [in] DWORD dwFlags, ++ [out] ULONG *cookies_count, [out, size_is(,*cookies_count)] XHR_COOKIE **cookies); ++ HRESULT GetResponseHeader([in, string, ref] const WCHAR *header, [out, string] WCHAR **value); ++} ++ ++[ ++ object, ++ uuid(a1c9feee-0617-4f23-9d58-8961ea43567c), ++ helpstring("IXMLHttpRequest3 Interface") ++] ++interface IXMLHTTPRequest3 : IXMLHTTPRequest2 ++{ ++ HRESULT SetClientCertificate([in] DWORD hash_size, [in, unique, size_is(hash_size)] const BYTE *hash, ++ [in, string, unique] const WCHAR *pin); ++} ++ ++[ ++ object, ++ uuid(a44a9299-e321-40de-8866-341b41669162), ++ helpstring("IXMLHTTPRequest2Callback Interface"), ++ pointer_default(ref) ++] ++interface IXMLHTTPRequest2Callback : IUnknown ++{ ++ HRESULT OnRedirect([in] IXMLHTTPRequest2 *request, [in, string] const WCHAR* redirect_url); ++ HRESULT OnHeadersAvailable([in] IXMLHTTPRequest2 *request, [in] DWORD status, [in, string] const WCHAR *status_str); ++ HRESULT OnDataAvailable([in] IXMLHTTPRequest2 *request, [in] ISequentialStream *response); ++ HRESULT OnResponseReceived([in] IXMLHTTPRequest2 *request, [in] ISequentialStream *response); ++ HRESULT OnError([in] IXMLHTTPRequest2 *request, [in] HRESULT error); ++} ++ ++[ ++ object, ++ uuid(b9e57830-8c6c-4a6f-9c13-47772bb047bb), ++ helpstring("IXMLHttpRequest3Callback Interface") ++] ++interface IXMLHTTPRequest3Callback : IXMLHTTPRequest2Callback ++{ ++ HRESULT OnServerCertificateReceived([in] IXMLHTTPRequest3 *request, [in] DWORD errors, ++ [in] DWORD chain_size, ++ [in, unique,size_is(chain_size)] const XHR_CERT *chain); ++ HRESULT OnClientCertificateRequested([in] IXMLHTTPRequest3 *request, [in] DWORD issuers_size, ++ [in, string, unique, size_is(issuers_size)] const WCHAR **issuers); ++}; ++ ++ + [ + object, + dual, +@@ -1554,6 +1649,17 @@ coclass XMLHTTP60 + [default] interface IXMLHTTPRequest; + } + ++[ ++ helpstring("Free Threaded XML HTTP Request class 6.0"), ++ progid("Msxml2.FreeThreadedXMLHTTP60.6.0"), ++ threading(both), ++ uuid(88d96a09-f192-11d4-a65f-0040963251e5) ++] ++coclass FreeThreadedXMLHTTP60 ++{ ++ interface IXMLHTTPRequest2; ++} ++ + [ + uuid(afba6b42-5692-48ea-8141-dc517dcf0ef1) + ] +-- +2.28.0 + diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/0005-msxml3-Implement-FreeThreadedXMLHTTP60.patch b/patches/msxml3-FreeThreadedXMLHTTP60/0005-msxml3-Implement-FreeThreadedXMLHTTP60.patch new file mode 100644 index 00000000..81d0cd99 --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/0005-msxml3-Implement-FreeThreadedXMLHTTP60.patch @@ -0,0 +1,1024 @@ +From 02147fc13eefc56391549102082759b85c282510 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 8 Sep 2020 18:43:52 +0200 +Subject: [PATCH 5/5] msxml3: Implement FreeThreadedXMLHTTP60. + +--- + dlls/msxml3/Makefile.in | 2 +- + dlls/msxml3/factory.c | 5 + + dlls/msxml3/httprequest.c | 493 +++++++++++++++++++++++++++++++++++- + dlls/msxml3/msxml_private.h | 1 + + dlls/msxml3/tests/httpreq.c | 395 ++++++++++++++++++++++++++++- + 5 files changed, 891 insertions(+), 5 deletions(-) + +diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in +index 936c745895..f9e629f89b 100644 +--- a/dlls/msxml3/Makefile.in ++++ b/dlls/msxml3/Makefile.in +@@ -1,5 +1,5 @@ + MODULE = msxml3.dll +-IMPORTS = uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 ++IMPORTS = uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 rtworkq + EXTRALIBS = $(XML2_LIBS) + EXTRAINCL = $(XML2_CFLAGS) $(XSLT_CFLAGS) + +diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c +index 3be974c58a..8608e238ee 100644 +--- a/dlls/msxml3/factory.c ++++ b/dlls/msxml3/factory.c +@@ -280,6 +280,7 @@ static HRESULT DOMClassFactory_Create(const GUID *clsid, REFIID riid, void **ppv + + static ClassFactory xmldoccf = { { &ClassFactoryVtbl }, XMLDocument_create }; + static ClassFactory httpreqcf = { { &ClassFactoryVtbl }, XMLHTTPRequest_create }; ++static ClassFactory httpreqcf2 = { { &ClassFactoryVtbl }, XMLHTTPRequest2_create }; + static ClassFactory serverhttp = { { &ClassFactoryVtbl }, ServerXMLHTTP_create }; + static ClassFactory xsltemplatecf = { { &ClassFactoryVtbl }, XSLTemplate_create }; + static ClassFactory mxnsmanagercf = { {&ClassFactoryVtbl }, MXNamespaceManager_create }; +@@ -341,6 +342,10 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) + { + cf = &httpreqcf.IClassFactory_iface; + } ++ else if( IsEqualCLSID( rclsid, &CLSID_FreeThreadedXMLHTTP60 )) ++ { ++ cf = &httpreqcf2.IClassFactory_iface; ++ } + else if( IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP ) || + IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP30 ) || + IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP40 ) || +diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c +index 7286eb97bb..ad74260193 100644 +--- a/dlls/msxml3/httprequest.c ++++ b/dlls/msxml3/httprequest.c +@@ -44,13 +44,16 @@ + #include "docobj.h" + #include "shlwapi.h" + ++#include "initguid.h" ++#include "rtworkq.h" ++ + #include "msxml_private.h" + + #include "wine/debug.h" + + #ifdef HAVE_LIBXML2 + +-WINE_DEFAULT_DEBUG_CHANNEL(msxml); ++WINE_DEFAULT_DEBUG_CHANNEL(xmlhttp); + + static const WCHAR colspaceW[] = {':',' ',0}; + static const WCHAR crlfW[] = {'\r','\n',0}; +@@ -2031,6 +2034,458 @@ static const struct IServerXMLHTTPRequestVtbl ServerXMLHTTPRequestVtbl = + ServerXMLHTTPRequest_setOption + }; + ++static DWORD xhr2_work_queue; ++ ++struct xml_http_request_2 ++{ ++ httprequest req; ++ IXMLHTTPRequest2 IXMLHTTPRequest2_iface; ++ IRtwqAsyncCallback IRtwqAsyncCallback_iface; ++ IDispatch IDispatch_iface; ++ ++ IXMLHTTPRequest2Callback *callback; ++ IXMLHTTPRequest3Callback *callback3; ++ ISequentialStream *response_body; ++ ISequentialStream *request_body; ++ ULONGLONG request_body_size; ++}; ++ ++static inline struct xml_http_request_2 *impl_from_IXMLHTTPRequest2(IXMLHTTPRequest2 *iface) ++{ ++ return CONTAINING_RECORD(iface, struct xml_http_request_2, IXMLHTTPRequest2_iface); ++} ++ ++static inline struct xml_http_request_2 *xml_http_request_2_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) ++{ ++ return CONTAINING_RECORD(iface, struct xml_http_request_2, IRtwqAsyncCallback_iface); ++} ++ ++static inline struct xml_http_request_2 *xml_http_request_2_from_IDispatch(IDispatch *iface) ++{ ++ return CONTAINING_RECORD(iface, struct xml_http_request_2, IDispatch_iface); ++} ++ ++static HRESULT WINAPI xml_http_request_2_QueryInterface(IXMLHTTPRequest2 *iface, REFIID riid, void **obj) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ ++ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); ++ ++ if (IsEqualGUID(riid, &IID_IXMLHTTPRequest2) || IsEqualGUID(riid, &IID_IUnknown)) ++ { ++ IXMLHTTPRequest2_AddRef(iface); ++ *obj = iface; ++ return S_OK; ++ } ++ ++ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); ++ *obj = NULL; ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI xml_http_request_2_AddRef(IXMLHTTPRequest2 *iface) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ ULONG ref = InterlockedIncrement(&This->req.ref); ++ TRACE("(%p)->(%u)\n", This, ref); ++ return ref; ++} ++ ++static ULONG WINAPI xml_http_request_2_Release(IXMLHTTPRequest2 *iface) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ ULONG ref = InterlockedDecrement(&This->req.ref); ++ ++ TRACE("(%p)->(%u)\n", This, ref); ++ ++ if (ref == 0) ++ { ++ /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ ++ This->req.sink = NULL; ++ if (This->response_body) ISequentialStream_Release(This->response_body); ++ if (This->request_body) ISequentialStream_Release(This->request_body); ++ if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); ++ if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); ++ heap_free(This); ++ RtwqShutdown(); ++ } ++ ++ return ref; ++} ++ ++static HRESULT WINAPI xml_http_request_2_Open(IXMLHTTPRequest2 *iface, const WCHAR *method, ++ const WCHAR *url, IXMLHTTPRequest2Callback *callback, ++ const WCHAR *username, const WCHAR *password, ++ const WCHAR *proxy_username, const WCHAR *proxy_password) ++{ ++ static const WCHAR accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; ++ static const WCHAR empty = 0; ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ VARIANT async_v, username_v, password_v; ++ HRESULT hr; ++ ++ TRACE("(%p)->(%s %s %p %s %s %s %s)\n", This, debugstr_w(method), debugstr_w(url), callback, ++ debugstr_w(username), debugstr_w(password), debugstr_w(proxy_username), debugstr_w(proxy_password)); ++ ++ if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); ++ if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); ++ IXMLHTTPRequest2Callback_AddRef(callback); ++ This->callback = callback; ++ if (FAILED(IXMLHTTPRequest2Callback_QueryInterface(callback, &IID_IXMLHTTPRequest3Callback, (void **)&This->callback3))) ++ This->callback3 = NULL; ++ ++ if (proxy_username || proxy_password) FIXME("proxy credentials not implemented\n"); ++ ++ VariantInit(&async_v); ++ V_VT(&async_v) = VT_BOOL; ++ V_BOOL(&async_v) = FALSE; /* FIXME: TRUE needs a RTWQ_WINDOW_WORKQUEUE */ ++ ++ VariantInit(&username_v); ++ V_VT(&username_v) = VT_BSTR; ++ if (username) V_BSTR(&username_v) = SysAllocString(username); ++ else V_BSTR(&username_v) = SysAllocString(&empty); ++ ++ VariantInit(&password_v); ++ V_VT(&password_v) = VT_BSTR; ++ if (password) V_BSTR(&password_v) = SysAllocString(password); ++ else V_BSTR(&password_v) = SysAllocString(&empty); ++ ++ if (FAILED(hr = httprequest_open(&This->req, (BSTR)method, (BSTR)url, async_v, username_v, password_v))) ++ return hr; ++ return httprequest_setRequestHeader(&This->req, (BSTR)accept_encoding, (BSTR)&empty); ++} ++ ++static HRESULT WINAPI xml_http_request_2_Send(IXMLHTTPRequest2 *iface, ISequentialStream *body, ULONGLONG body_size) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ IRtwqAsyncResult *result; ++ HRESULT hr; ++ ++ TRACE("(%p)->(%p %s)\n", This, body, wine_dbgstr_longlong( body_size )); ++ ++ if (body_size) ++ { ++ ISequentialStream_AddRef(body); ++ This->request_body = body; ++ This->request_body_size = body_size; ++ } ++ ++ if (FAILED(hr = RtwqCreateAsyncResult(NULL, &This->IRtwqAsyncCallback_iface, NULL, &result))) ++ return hr; ++ // IRtwqAsyncCallback_Invoke(&This->IRtwqAsyncCallback_iface, result); ++ hr = RtwqPutWorkItem(xhr2_work_queue, 0, result); ++ if (result) IRtwqAsyncResult_Release(result); ++ ++ return hr; ++} ++ ++static HRESULT WINAPI xml_http_request_2_Abort(IXMLHTTPRequest2 *iface) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ TRACE("(%p) stub!\n", This); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_SetCookie(IXMLHTTPRequest2 *iface, const XHR_COOKIE *cookie, DWORD *state) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ FIXME("(%p)->(%p %p) stub!\n", This, cookie, state); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest2 *iface, ISequentialStream *stream) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ FIXME("(%p)->(%p) stub!\n", This, stream); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest2 *iface, XHR_PROPERTY property, ULONGLONG value) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest2 *iface, ++ const WCHAR *header, const WCHAR *value) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value)); ++ return httprequest_setRequestHeader(&This->req, (BSTR)header, (BSTR)value); ++} ++ ++static HRESULT WINAPI xml_http_request_2_GetAllResponseHeaders(IXMLHTTPRequest2 *iface, WCHAR **headers) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ FIXME("(%p)->(%p) stub!\n", This, headers); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_GetCookie(IXMLHTTPRequest2 *iface, const WCHAR *url, ++ const WCHAR *name, DWORD flags, ++ ULONG *cookies_count, XHR_COOKIE **cookies) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ FIXME("(%p)->(%s %s %d %p %p) stub!\n", This, debugstr_w(url), debugstr_w(name), flags, cookies_count, cookies); ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest2 *iface, ++ const WCHAR *header, WCHAR **value) ++{ ++ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest2(iface); ++ HRESULT hr; ++ ++ TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); ++ ++ if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) ++ return hr; ++ ++#define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) ++ ++ if (hr == S_FALSE) ++ { ++ *value = NULL; ++ return E_FILE_NOT_FOUND; ++ } ++ ++ return hr; ++} ++ ++static const struct IXMLHTTPRequest2Vtbl XMLHTTPRequest2Vtbl = { ++ /* IUnknown methods */ ++ xml_http_request_2_QueryInterface, ++ xml_http_request_2_AddRef, ++ xml_http_request_2_Release, ++ /* IXMLHTTPRequest2 methods */ ++ xml_http_request_2_Open, ++ xml_http_request_2_Send, ++ xml_http_request_2_Abort, ++ xml_http_request_2_SetCookie, ++ xml_http_request_2_SetCustomResponseStream, ++ xml_http_request_2_SetProperty, ++ xml_http_request_2_SetRequestHeader, ++ xml_http_request_2_GetAllResponseHeaders, ++ xml_http_request_2_GetCookie, ++ xml_http_request_2_GetResponseHeader, ++}; ++ ++static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); ++ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); ++ ++ if (IsEqualGUID(riid, &IID_IRtwqAsyncCallback) || IsEqualGUID(riid, &IID_IUnknown)) ++ { ++ IRtwqAsyncCallback_AddRef(iface); ++ *obj = iface; ++ return S_OK; ++ } ++ ++ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); ++ *obj = NULL; ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_AddRef(IRtwqAsyncCallback *iface) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); ++ TRACE("(%p)\n", This); ++ return xml_http_request_2_AddRef(&This->IXMLHTTPRequest2_iface); ++} ++ ++static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_Release(IRtwqAsyncCallback *iface) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); ++ TRACE("(%p)\n", This); ++ return xml_http_request_2_Release(&This->IXMLHTTPRequest2_iface); ++} ++ ++static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_GetParameters(IRtwqAsyncCallback *iface, ++ DWORD *flags, DWORD *queue) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); ++ ++ TRACE("(%p)->(%p %p)\n", This, flags, queue); ++ ++ *flags = 0; ++ *queue = xhr2_work_queue; ++ return S_OK; ++} ++ ++static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCallback *iface, ++ IRtwqAsyncResult *result) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); ++ VARIANT body_v; ++ HRESULT hr; ++ ULONG read; ++ ++ TRACE("(%p)->(%p)\n", This, result); ++ ++ VariantInit(&body_v); ++ ++ if (This->request_body) ++ { ++ V_VT(&body_v) = VT_BSTR; ++ V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); ++ ++ if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || ++ read < This->request_body_size) ++ { ++ ERR("Failed to allocate request body memory, hr %#x\n", hr); ++ CoTaskMemFree(V_BSTR(&body_v)); ++ goto done; ++ } ++ ++ ISequentialStream_Release(This->request_body); ++ This->request_body = NULL; ++ } ++ ++ hr = httprequest_send(&This->req, body_v); ++ ++done: ++ return IRtwqAsyncResult_SetStatus(result, hr); ++} ++ ++static const struct IRtwqAsyncCallbackVtbl xml_http_request_2_IRtwqAsyncCallbackVtbl = { ++ /* IUnknown methods */ ++ xml_http_request_2_IRtwqAsyncCallback_QueryInterface, ++ xml_http_request_2_IRtwqAsyncCallback_AddRef, ++ xml_http_request_2_IRtwqAsyncCallback_Release, ++ /* IRtwqAsyncCallback methods */ ++ xml_http_request_2_IRtwqAsyncCallback_GetParameters, ++ xml_http_request_2_IRtwqAsyncCallback_Invoke, ++}; ++ ++static HRESULT WINAPI xml_http_request_2_IDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); ++ ++ if (IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) ++ { ++ IDispatch_AddRef(iface); ++ *obj = iface; ++ return S_OK; ++ } ++ ++ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); ++ *obj = NULL; ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI xml_http_request_2_IDispatch_AddRef(IDispatch *iface) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ TRACE("(%p)\n", This); ++ return xml_http_request_2_AddRef(&This->IXMLHTTPRequest2_iface); ++} ++ ++static ULONG WINAPI xml_http_request_2_IDispatch_Release(IDispatch *iface) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ TRACE("(%p)\n", This); ++ return xml_http_request_2_Release(&This->IXMLHTTPRequest2_iface); ++} ++ ++static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfoCount(IDispatch *iface, UINT *value) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ FIXME("(%p)->(%p) stub!\n", This, value); ++ *value = 0; ++ return S_OK; ++} ++ ++static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfo(IDispatch *iface, UINT index, ++ LCID lcid, ITypeInfo **value) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ FIXME("(%p)->(%d %u %p) stub!\n", This, index, lcid, value); ++ *value = NULL; ++ return S_OK; ++} ++ ++static HRESULT WINAPI xml_http_request_2_IDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, ++ OLECHAR **names, UINT names_count, ++ LCID lcid, DISPID *disp_ids) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ FIXME("(%p)->(%s %p %d %u %p) stub!\n", This, debugstr_guid(riid), names, names_count, lcid, disp_ids); ++ return S_OK; ++} ++ ++static HRESULT WINAPI xml_http_request_2_IDispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, ++ LCID lcid, WORD flags, DISPPARAMS *params, ++ VARIANT *result, EXCEPINFO *exception, UINT *arg_err) ++{ ++ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); ++ IXMLHTTPRequest2 *xhr2_iface = &This->IXMLHTTPRequest2_iface; ++ HRESULT hr; ++ LONG status; ++ BSTR status_str = NULL; ++ ++ TRACE("(%p)->(%d %s %u %d %p %p %p %p) stub!\n", This, id, debugstr_guid(riid), lcid, flags, ++ params, result, exception, arg_err); ++ ++ if (This->req.state == READYSTATE_COMPLETE) ++ { ++ VARIANT body_v; ++ VariantInit(&body_v); ++ ++ IXMLHTTPRequest2Callback_AddRef(This->callback); ++ if (This->callback3) ++ { ++ IXMLHTTPRequest3Callback_AddRef(This->callback3); ++ IXMLHTTPRequest3Callback_OnServerCertificateReceived(This->callback3, (IXMLHTTPRequest3 *)xhr2_iface, 0, 1, NULL); ++ IXMLHTTPRequest3Callback_Release(This->callback3); ++ } ++ ++ if (FAILED(hr = httprequest_get_status(&This->req, &status)) || ++ FAILED(hr = httprequest_get_statusText(&This->req, &status_str))) ++ { ++ WARN("failed to get response status, error %#x\n", hr); ++ IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); ++ IXMLHTTPRequest2Callback_Release(This->callback); ++ return S_OK; ++ } ++ ++ IXMLHTTPRequest2Callback_OnHeadersAvailable(This->callback, xhr2_iface, status, status_str); ++ SysFreeString(status_str); ++ ++ if (This->response_body) ISequentialStream_Release(This->response_body); ++ This->response_body = NULL; ++ ++ if (FAILED(hr = httprequest_get_responseStream(&This->req, &body_v)) || ++ FAILED(hr = IUnknown_QueryInterface(V_UNKNOWN(&body_v), &IID_ISequentialStream, (void **)&This->response_body))) ++ { ++ WARN("failed to get response stream, error %#x\n", hr); ++ IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); ++ IXMLHTTPRequest2Callback_Release(This->callback); ++ return S_OK; ++ } ++ ++ IXMLHTTPRequest2Callback_OnDataAvailable(This->callback, xhr2_iface, This->response_body); ++ IXMLHTTPRequest2Callback_OnResponseReceived(This->callback, xhr2_iface, This->response_body); ++ IXMLHTTPRequest2Callback_Release(This->callback); ++ } ++ ++ return S_OK; ++} ++ ++static const struct IDispatchVtbl xml_http_request_2_IDispatchVtbl = { ++ /* IUnknown methods */ ++ xml_http_request_2_IDispatch_QueryInterface, ++ xml_http_request_2_IDispatch_AddRef, ++ xml_http_request_2_IDispatch_Release, ++ /* IDispatch methods */ ++ xml_http_request_2_IDispatch_GetTypeInfoCount, ++ xml_http_request_2_IDispatch_GetTypeInfo, ++ xml_http_request_2_IDispatch_GetIDsOfNames, ++ xml_http_request_2_IDispatch_Invoke, ++}; ++ + static void init_httprequest(httprequest *req) + { + req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl; +@@ -2080,6 +2535,35 @@ HRESULT XMLHTTPRequest_create(void **obj) + return S_OK; + } + ++HRESULT XMLHTTPRequest2_create(void **obj) ++{ ++ struct xml_http_request_2 *xhr2; ++ TRACE("(%p)\n", obj); ++ ++ if (!(xhr2 = heap_alloc(sizeof(*xhr2)))) return E_OUTOFMEMORY; ++ ++ init_httprequest(&xhr2->req); ++ xhr2->IXMLHTTPRequest2_iface.lpVtbl = &XMLHTTPRequest2Vtbl; ++ xhr2->IRtwqAsyncCallback_iface.lpVtbl = &xml_http_request_2_IRtwqAsyncCallbackVtbl; ++ xhr2->IDispatch_iface.lpVtbl = &xml_http_request_2_IDispatchVtbl; ++ ++ /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ ++ xhr2->req.sink = &xhr2->IDispatch_iface; ++ ++ xhr2->callback = NULL; ++ xhr2->callback3 = NULL; ++ xhr2->request_body = NULL; ++ xhr2->response_body = NULL; ++ ++ /* for async http requests we need window message queue */ ++ RtwqStartup(); ++ if (!xhr2_work_queue) RtwqAllocateWorkQueue(RTWQ_MULTITHREADED_WORKQUEUE, &xhr2_work_queue); ++ ++ *obj = &xhr2->IXMLHTTPRequest2_iface; ++ TRACE("returning iface %p\n", *obj); ++ return S_OK; ++} ++ + HRESULT ServerXMLHTTP_create(void **obj) + { + serverhttp *req; +@@ -2109,6 +2593,13 @@ HRESULT XMLHTTPRequest_create(void **ppObj) + return E_NOTIMPL; + } + ++HRESULT XMLHTTPRequest2_create(void **ppObj) ++{ ++ MESSAGE("This program tried to use a XMLHTTPRequest object, but\n" ++ "libxml2 support was not present at compile time.\n"); ++ return E_NOTIMPL; ++} ++ + HRESULT ServerXMLHTTP_create(void **obj) + { + MESSAGE("This program tried to use a ServerXMLHTTP object, but\n" +diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h +index 5fce060985..f25a4a8268 100644 +--- a/dlls/msxml3/msxml_private.h ++++ b/dlls/msxml3/msxml_private.h +@@ -498,6 +498,7 @@ extern HRESULT XMLDocument_create(void**) DECLSPEC_HIDDEN; + extern HRESULT SAXXMLReader_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; + extern HRESULT SAXAttributes_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; + extern HRESULT XMLHTTPRequest_create(void **) DECLSPEC_HIDDEN; ++extern HRESULT XMLHTTPRequest2_create(void **) DECLSPEC_HIDDEN; + extern HRESULT ServerXMLHTTP_create(void **) DECLSPEC_HIDDEN; + extern HRESULT XSLTemplate_create(void**) DECLSPEC_HIDDEN; + extern HRESULT MXWriter_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; +diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c +index 74c302d5eb..f22c9831a1 100644 +--- a/dlls/msxml3/tests/httpreq.c ++++ b/dlls/msxml3/tests/httpreq.c +@@ -27,8 +27,8 @@ + + #include "windows.h" + +-#include "msxml2.h" +-#include "msxml2did.h" ++#include "msxml6.h" ++#include "msxml6did.h" + #include "dispex.h" + + #include "initguid.h" +@@ -1334,6 +1334,17 @@ static IXMLHttpRequest *create_xhr(void) + return SUCCEEDED(hr) ? ret : NULL; + } + ++static IXMLHTTPRequest2 *create_xhr2(void) ++{ ++ IXMLHTTPRequest2 *ret; ++ HRESULT hr; ++ ++ hr = CoCreateInstance(&CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_INPROC_SERVER, ++ &IID_IXMLHTTPRequest2, (void**)&ret); ++ ++ return SUCCEEDED(hr) ? ret : NULL; ++} ++ + static IServerXMLHTTPRequest *create_server_xhr(void) + { + IServerXMLHTTPRequest *ret; +@@ -1893,11 +1904,388 @@ static void test_supporterrorinfo(void) + IServerXMLHTTPRequest_Release(server_xhr); + } + ++struct xhr3_callback ++{ ++ IXMLHTTPRequest3Callback IXMLHTTPRequest3Callback_iface; ++ LONG ref; ++ HANDLE event; ++}; ++ ++static inline struct xhr3_callback *xhr3_callback_from_IXMLHTTPRequest3Callback(IXMLHTTPRequest3Callback *iface) ++{ ++ return CONTAINING_RECORD(iface, struct xhr3_callback, IXMLHTTPRequest3Callback_iface); ++} ++ ++static HRESULT WINAPI xhr3_callback_QueryInterface(IXMLHTTPRequest3Callback *iface, REFIID riid, void **obj) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); ++ ++ if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3Callback) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2Callback) || IsEqualGUID(riid, &IID_IUnknown)) ++ { ++ IXMLHTTPRequest3Callback_AddRef(iface); ++ *obj = iface; ++ return S_OK; ++ } ++ ++ ok(0, "unexpected interface %s\n", debugstr_guid(riid)); ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI xhr3_callback_AddRef(IXMLHTTPRequest3Callback *iface) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ ULONG ref = InterlockedIncrement(&This->ref); ++ trace("(%p)->(%u)\n", This, ref); ++ return ref; ++} ++ ++static ULONG WINAPI xhr3_callback_Release(IXMLHTTPRequest3Callback *iface) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ ULONG ref = InterlockedDecrement(&This->ref); ++ trace("(%p)->(%u)\n", This, ref); ++ if (ref == 0) HeapFree(GetProcessHeap(), 0, This); ++ return ref; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnRedirect(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest2 *request, const WCHAR* redirect_url) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%p %s)\n", This, request, debugstr_w(redirect_url)); ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnHeadersAvailable(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest2 *request, DWORD status, const WCHAR *status_str) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ WCHAR *header = NULL; ++ HRESULT hr; ++ ++ trace("(%p)->(%p %d %s)\n", This, request, status, debugstr_w(status_str)); ++ ++ header = (void *)0xdeadbeef; ++ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Length", &header); ++ trace("Content-Length: %p (%s), hr %#x\n", header, debugstr_w(header), hr); ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnDataAvailable(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest2 *request, ISequentialStream *response) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%p %p)\n", This, request, response); ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnResponseReceived(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest2 *request, ISequentialStream *response) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ WCHAR *header = NULL; ++ char *buffer = HeapAlloc( GetProcessHeap(), 0, 256 ); ++ ULONG read_size = 0; ++ HRESULT hr; ++ ++ memset(buffer, '?', 256); ++ buffer[255] = 0; ++ ++ trace("(%p)->(%p %p)\n", This, request, response); ++ ++ header = (void *)0xdeadbeef; ++ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Cache-Control", &header); ++ trace("Cache-Control: %p (%s), hr %#x\n", header, debugstr_w(header), hr); ++ ++ header = (void *)0xdeadbeef; ++ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Expires", &header); ++ trace("Expires: %p (%s), hr %#x\n", header, debugstr_w(header), hr); ++ ++ header = (void *)0xdeadbeef; ++ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Type", &header); ++ trace("Content-Type: %p (%s), hr %#x\n", header, debugstr_w(header), hr); ++ ++ read_size = 0xdeadbeef; ++ hr = ISequentialStream_Read(response, buffer, 214, &read_size); ++ trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); ++ ++ read_size = 0xdeadbeef; ++ hr = ISequentialStream_Read(response, buffer, 1, &read_size); ++ trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); ++ ++ HeapFree( GetProcessHeap(), 0, buffer ); ++ SetEvent(This->event); ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnError(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest2 *request, HRESULT error) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%p %#x)\n", This, request, error); ++ SetEvent(This->event); ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnServerCertificateReceived(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest3 *request, DWORD errors, DWORD chain_size, const XHR_CERT *chain) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%p %u %u %p)\n", This, request, errors, chain_size, chain); ++ return S_OK; ++} ++ ++static HRESULT WINAPI xhr3_callback_OnClientCertificateRequested(IXMLHTTPRequest3Callback *iface, ++ IXMLHTTPRequest3 *request, DWORD issuers_size, const WCHAR **issuers) ++{ ++ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); ++ trace("(%p)->(%p %u %p)\n", This, request, issuers_size, issuers); ++ return S_OK; ++} ++ ++static const IXMLHTTPRequest3CallbackVtbl xhr3_callback_vtbl = ++{ ++ xhr3_callback_QueryInterface, ++ xhr3_callback_AddRef, ++ xhr3_callback_Release, ++ /* IXMLHTTPRequest2Callback methods */ ++ xhr3_callback_OnRedirect, ++ xhr3_callback_OnHeadersAvailable, ++ xhr3_callback_OnDataAvailable, ++ xhr3_callback_OnResponseReceived, ++ xhr3_callback_OnError, ++ /* IXMLHTTPRequest3Callback methods */ ++ xhr3_callback_OnServerCertificateReceived, ++ xhr3_callback_OnClientCertificateRequested, ++}; ++ ++static IXMLHTTPRequest2Callback* xhr3_callback_create(HANDLE event) ++{ ++ struct xhr3_callback *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); ++ ok(This != NULL, "failed to allocate object\n"); ++ if (!This) return NULL; ++ ++ This->IXMLHTTPRequest3Callback_iface.lpVtbl = &xhr3_callback_vtbl; ++ This->ref = 1; ++ This->event = event; ++ ++ return (IXMLHTTPRequest2Callback*)&This->IXMLHTTPRequest3Callback_iface; ++} ++ ++struct xhr2_stream ++{ ++ IStream IStream_iface; ++ LONG ref; ++ IStream *stream; ++}; ++ ++static inline struct xhr2_stream *xhr2_stream_from_IStream(IStream *iface) ++{ ++ return CONTAINING_RECORD(iface, struct xhr2_stream, IStream_iface); ++} ++ ++static HRESULT WINAPI xhr2_stream_QueryInterface(IStream *iface, REFIID riid, void **obj) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); ++ ++ if (IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_ISequentialStream) || IsEqualGUID(riid, &IID_IUnknown)) ++ { ++ IStream_AddRef(iface); ++ *obj = iface; ++ return S_OK; ++ } ++ ++ ok(0, "unexpected interface %s\n", debugstr_guid(riid)); ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI xhr2_stream_AddRef(IStream *iface) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ ULONG ref = InterlockedIncrement(&This->ref); ++ trace("(%p)->(%u)\n", This, ref); ++ return ref; ++} ++ ++static ULONG WINAPI xhr2_stream_Release(IStream *iface) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ ULONG ref = InterlockedDecrement(&This->ref); ++ trace("(%p)->(%u)\n", This, ref); ++ if (ref == 0) ++ { ++ IStream_Release(This->stream); ++ HeapFree(GetProcessHeap(), 0, This); ++ } ++ return ref; ++} ++ ++static HRESULT WINAPI xhr2_stream_Read(IStream *iface, void *pv, ULONG cb, ++ ULONG *pcbRead) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); ++ return IStream_Read(This->stream, pv, cb, pcbRead); ++} ++ ++static HRESULT WINAPI xhr2_stream_Write(IStream *iface, const void *pv, ++ ULONG cb, ULONG *pcbWritten) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbWritten); ++ return IStream_Write(This->stream, pv, cb, pcbWritten); ++} ++ ++static HRESULT WINAPI xhr2_stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, ++ DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%lu, %u %p)\n", This, dlibMove.QuadPart, dwOrigin, plibNewPosition); ++ return IStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); ++} ++ ++static HRESULT WINAPI xhr2_stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%lu)\n", This, libNewSize.QuadPart); ++ return IStream_SetSize(This->stream, libNewSize); ++} ++ ++static HRESULT WINAPI xhr2_stream_CopyTo(IStream *iface, IStream *pstm, ++ ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%p %lu %p %p)\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); ++ return IStream_CopyTo(This->stream, pstm, cb, pcbRead, pcbWritten); ++} ++ ++static HRESULT WINAPI xhr2_stream_Commit(IStream *iface, DWORD grfCommitFlags) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%#x)\n", This, grfCommitFlags); ++ return IStream_Commit(This->stream, grfCommitFlags); ++} ++ ++static HRESULT WINAPI xhr2_stream_Revert(IStream *iface) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->()\n", This); ++ return IStream_Revert(This->stream); ++} ++ ++static HRESULT WINAPI xhr2_stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, ++ ULARGE_INTEGER cb, DWORD dwLockType) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); ++ return IStream_LockRegion(This->stream, libOffset, cb, dwLockType); ++} ++ ++static HRESULT WINAPI xhr2_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, ++ ULARGE_INTEGER cb, DWORD dwLockType) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); ++ return IStream_UnlockRegion(This->stream, libOffset, cb, dwLockType); ++} ++ ++static HRESULT WINAPI xhr2_stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%p %#x)\n", This, pstatstg, grfStatFlag); ++ return IStream_Stat(This->stream, pstatstg, grfStatFlag); ++} ++ ++static HRESULT WINAPI xhr2_stream_Clone(IStream *iface, IStream **ppstm) ++{ ++ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); ++ trace("(%p)->(%p)\n", This, ppstm); ++ return IStream_Clone(This->stream, ppstm); ++} ++ ++static const IStreamVtbl xhr2_stream_vtbl = ++{ ++ xhr2_stream_QueryInterface, ++ xhr2_stream_AddRef, ++ xhr2_stream_Release, ++ /* IStream methods */ ++ xhr2_stream_Read, ++ xhr2_stream_Write, ++ xhr2_stream_Seek, ++ xhr2_stream_SetSize, ++ xhr2_stream_CopyTo, ++ xhr2_stream_Commit, ++ xhr2_stream_Revert, ++ xhr2_stream_LockRegion, ++ xhr2_stream_UnlockRegion, ++ xhr2_stream_Stat, ++ xhr2_stream_Clone ++}; ++ ++static ISequentialStream *xhr2_stream_create(void) ++{ ++ struct xhr2_stream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); ++ ok(This != NULL, "failed to allocate object\n"); ++ if (!This) return NULL; ++ ++ This->IStream_iface.lpVtbl = &xhr2_stream_vtbl; ++ This->ref = 1; ++ CreateStreamOnHGlobal(NULL, TRUE, &This->stream); ++ ++ return (ISequentialStream*)&This->IStream_iface; ++} ++ ++static void test_IXMLHTTPRequest2(void) ++{ ++ IXMLHTTPRequest2 *xhr2[16]; ++ IXMLHTTPRequest2Callback *xhr3_callback; ++ ISequentialStream *stream; ++ HANDLE events[16]; ++ HRESULT hr; ++ int i = 0; ++ ++ if (!(xhr2[i] = create_xhr2())) ++ { ++ win_skip("IXMLHTTPRequest2 is not available\n"); ++ return; ++ } ++ ++ events[i] = CreateEventW(NULL, FALSE, FALSE, NULL); ++ if (!(xhr3_callback = xhr3_callback_create(events[i]))) ++ return; ++ ++ trace("IXMLHTTPRequest2_Open (%p)->(L\"GET\", L\"http://test.winehq.org/\", xhr3_callback, NULL, NULL, NULL, NULL)\n", GetCurrentThreadId(), xhr2[i]); ++ hr = IXMLHTTPRequest2_Open(xhr2[i], L"GET", L"http://test.winehq.org/", xhr3_callback, NULL, NULL, NULL, NULL); ++ ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); ++ ++ if ((stream = xhr2_stream_create())) ++ { ++ trace("IXMLHTTPRequest2_Send (%p)->(%p 0)\n", GetCurrentThreadId(), xhr2[i], stream); ++ hr = IXMLHTTPRequest2_Send(xhr2[i], stream, 0); ++ ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); ++ ++ ISequentialStream_Release(stream); ++ } ++ ++ IXMLHTTPRequest2Callback_Release(xhr3_callback); ++ i++; ++ ++ while (i--) ++ { ++ WaitForSingleObject(events[i], INFINITE); ++ IXMLHTTPRequest2_Release(xhr2[i]); ++ } ++} ++ + START_TEST(httpreq) + { + IXMLHttpRequest *xhr; + +- CoInitialize(NULL); ++ CoInitializeEx(NULL, COINIT_MULTITHREADED); + + if (!(xhr = create_xhr())) + { +@@ -1912,6 +2300,7 @@ START_TEST(httpreq) + test_server_xhr(); + test_safe_httpreq(); + test_supporterrorinfo(); ++ test_IXMLHTTPRequest2(); + + CoUninitialize(); + } +-- +2.28.0 + diff --git a/patches/msxml3-FreeThreadedXMLHTTP60/definition b/patches/msxml3-FreeThreadedXMLHTTP60/definition new file mode 100644 index 00000000..0fa4c19e --- /dev/null +++ b/patches/msxml3-FreeThreadedXMLHTTP60/definition @@ -0,0 +1 @@ +Fixes: [49740] msxml3: Implement FreeThreadedXMLHTTP60. diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 022bd7fe..d66bd38c 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -157,6 +157,7 @@ patch_enable_all () enable_mshtml_TranslateAccelerator="$1" enable_msi_msi_vcl_get_cost="$1" enable_msvcrt_Math_Precision="$1" + enable_msxml3_FreeThreadedXMLHTTP60="$1" enable_netutils_dll="$1" enable_ntdll_APC_Performance="$1" enable_ntdll_Activation_Context="$1" @@ -567,6 +568,9 @@ patch_enable () msvcrt-Math_Precision) enable_msvcrt_Math_Precision="$2" ;; + msxml3-FreeThreadedXMLHTTP60) + enable_msxml3_FreeThreadedXMLHTTP60="$2" + ;; netutils-dll) enable_netutils_dll="$2" ;; @@ -2858,6 +2862,24 @@ if test "$enable_msvcrt_Math_Precision" -eq 1; then patch_apply msvcrt-Math_Precision/0001-msvcrt-Calculate-sinh-cosh-exp-pow-with-higher-preci.patch fi +# Patchset msxml3-FreeThreadedXMLHTTP60 +# | +# | This patchset fixes the following Wine bugs: +# | * [#49740] msxml3: Implement FreeThreadedXMLHTTP60. +# | +# | Modified files: +# | * dlls/msxml3/Makefile.in, dlls/msxml3/factory.c, dlls/msxml3/httprequest.c, dlls/msxml3/msxml_private.h, +# | dlls/msxml3/tests/httpreq.c, dlls/msxml3/tests/saxreader.c, dlls/msxml3/tests/schema.c, dlls/msxml3/uuid.c, +# | include/msxml2.idl, include/msxml6.idl +# | +if test "$enable_msxml3_FreeThreadedXMLHTTP60" -eq 1; then + patch_apply msxml3-FreeThreadedXMLHTTP60/0001-msxml3-Use-msxml6-header-for-defining-GUIDs.patch + patch_apply msxml3-FreeThreadedXMLHTTP60/0002-msxml3-tests-Use-msxml6.h-where-required.patch + patch_apply msxml3-FreeThreadedXMLHTTP60/0003-include-Remove-interfaces-already-define-in-msxml6.i.patch + patch_apply msxml3-FreeThreadedXMLHTTP60/0004-include-Add-IXMLHTTPRequest2-3-interfaces.patch + patch_apply msxml3-FreeThreadedXMLHTTP60/0005-msxml3-Implement-FreeThreadedXMLHTTP60.patch +fi + # Patchset netutils-dll # | # | This patchset fixes the following Wine bugs: