1 /* 2 * Copyright 2015 Zhenbo Li 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #define COBJMACROS 20 21 #include <wine/test.h> 22 #include <stdarg.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "ole2.h" 27 #include "mshtml.h" 28 29 static BSTR a2bstr(const char *str) 30 { 31 BSTR ret; 32 int len; 33 34 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); 35 ret = SysAllocStringLen(NULL, len); 36 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 37 38 return ret; 39 } 40 41 static int strcmp_wa(LPCWSTR strw, const char *stra) 42 { 43 CHAR buf[512]; 44 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); 45 return lstrcmpA(stra, buf); 46 } 47 48 #define DEFINE_EXPECT(func) \ 49 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE 50 51 #define SET_EXPECT(func) \ 52 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) 53 54 #define CHECK_EXPECT2(func) \ 55 do { \ 56 trace(#func "\n"); \ 57 ok(expect_ ##func, "unexpected call " #func "\n"); \ 58 called_ ## func = TRUE; \ 59 }while(0) 60 61 #define CHECK_EXPECT(func) \ 62 do { \ 63 CHECK_EXPECT2(func); \ 64 expect_ ## func = FALSE; \ 65 }while(0) 66 67 #define CHECK_CALLED(func) \ 68 do { \ 69 ok(called_ ## func, "expected " #func "\n"); \ 70 expect_ ## func = called_ ## func = FALSE; \ 71 }while(0) 72 73 static IHTMLXMLHttpRequest *xhr = NULL; 74 static BSTR content_type = NULL; 75 static int loading_cnt = 0; 76 static int readystatechange_cnt = 0; 77 78 DEFINE_EXPECT(xmlhttprequest_onreadystatechange_opened); 79 DEFINE_EXPECT(xmlhttprequest_onreadystatechange_headers_received); 80 DEFINE_EXPECT(xmlhttprequest_onreadystatechange_loading); 81 DEFINE_EXPECT(xmlhttprequest_onreadystatechange_done); 82 83 #define test_disp(u,id) _test_disp(__LINE__,u,id) 84 static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) 85 { 86 IDispatchEx *dispex; 87 ITypeInfo *typeinfo; 88 UINT ticnt; 89 HRESULT hres; 90 91 hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); 92 ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); 93 if(FAILED(hres)) 94 return; 95 96 ticnt = 0xdeadbeef; 97 hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); 98 ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres); 99 ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt); 100 101 hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo); 102 ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres); 103 104 if(SUCCEEDED(hres)) { 105 TYPEATTR *type_attr; 106 107 hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); 108 ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres); 109 ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", 110 wine_dbgstr_guid(&type_attr->guid)); 111 112 ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); 113 ITypeInfo_Release(typeinfo); 114 } 115 116 IDispatchEx_Release(dispex); 117 } 118 119 #define test_event_args(a,b,c,d,e,f,g) _test_event_args(__LINE__,a,b,c,d,e,f,g) 120 static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD wFlags, DISPPARAMS *pdp, 121 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) 122 { 123 ok_(__FILE__,line) (id == DISPID_VALUE, "id = %d\n", id); 124 ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); 125 ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n"); 126 ok_(__FILE__,line) (pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); 127 ok_(__FILE__,line) (pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); 128 ok_(__FILE__,line) (pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", 129 pdp->rgdispidNamedArgs[0]); 130 ok_(__FILE__,line) (V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); 131 ok_(__FILE__,line) (pvarRes != NULL, "pvarRes == NULL\n"); 132 ok_(__FILE__,line) (pei != NULL, "pei == NULL"); 133 ok_(__FILE__,line) (!pspCaller, "pspCaller != NULL\n"); 134 135 if(dispiid) 136 _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid); 137 } 138 139 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) 140 { 141 *ppv = NULL; 142 143 if(IsEqualGUID(riid, &IID_IUnknown) 144 || IsEqualGUID(riid, &IID_IDispatch) 145 || IsEqualGUID(riid, &IID_IDispatchEx)) 146 *ppv = iface; 147 else { 148 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); 149 return E_NOINTERFACE; 150 } 151 152 return S_OK; 153 } 154 155 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) 156 { 157 return 2; 158 } 159 160 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) 161 { 162 return 1; 163 } 164 165 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) 166 { 167 ok(0, "unexpected call\n"); 168 return E_NOTIMPL; 169 } 170 171 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, 172 LCID lcid, ITypeInfo **ppTInfo) 173 { 174 ok(0, "unexpected call\n"); 175 return E_NOTIMPL; 176 } 177 178 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, 179 LPOLESTR *rgszNames, UINT cNames, 180 LCID lcid, DISPID *rgDispId) 181 { 182 ok(0, "unexpected call\n"); 183 return E_NOTIMPL; 184 } 185 186 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, 187 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 188 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 189 { 190 ok(0, "unexpected call\n"); 191 return E_NOTIMPL; 192 } 193 194 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) 195 { 196 ok(0, "unexpected call\n"); 197 return E_NOTIMPL; 198 } 199 200 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) 201 { 202 ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex); 203 return E_NOTIMPL; 204 } 205 206 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) 207 { 208 ok(0, "unexpected call\n"); 209 return E_NOTIMPL; 210 } 211 212 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) 213 { 214 ok(0, "unexpected call\n"); 215 return E_NOTIMPL; 216 } 217 218 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) 219 { 220 ok(0, "unexpected call\n"); 221 return E_NOTIMPL; 222 } 223 224 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) 225 { 226 ok(0, "unexpected call\n"); 227 return E_NOTIMPL; 228 } 229 230 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) 231 { 232 ok(0, "unexpected call\n"); 233 return E_NOTIMPL; 234 } 235 236 static HRESULT WINAPI xmlhttprequest_onreadystatechange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, 237 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) 238 { 239 LONG val; 240 HRESULT hres; 241 242 test_event_args(&DIID_DispHTMLXMLHttpRequest, id, wFlags, pdp, pvarRes, pei, pspCaller); 243 244 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 245 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 246 readystatechange_cnt++; 247 248 switch(val) { 249 case 1: 250 CHECK_EXPECT(xmlhttprequest_onreadystatechange_opened); 251 break; 252 case 2: 253 CHECK_EXPECT(xmlhttprequest_onreadystatechange_headers_received); 254 break; 255 case 3: 256 loading_cnt++; 257 CHECK_EXPECT2(xmlhttprequest_onreadystatechange_loading); 258 break; 259 case 4: 260 CHECK_EXPECT(xmlhttprequest_onreadystatechange_done); 261 break; 262 default: 263 ok(0, "unexpected readyState: %d\n", val); 264 } 265 return S_OK; 266 } 267 268 static IDispatchExVtbl xmlhttprequest_onreadystatechangeFuncVtbl = { 269 DispatchEx_QueryInterface, 270 DispatchEx_AddRef, 271 DispatchEx_Release, 272 DispatchEx_GetTypeInfoCount, 273 DispatchEx_GetTypeInfo, 274 DispatchEx_GetIDsOfNames, 275 DispatchEx_Invoke, 276 DispatchEx_GetDispID, 277 xmlhttprequest_onreadystatechange, 278 DispatchEx_DeleteMemberByName, 279 DispatchEx_DeleteMemberByDispID, 280 DispatchEx_GetMemberProperties, 281 DispatchEx_GetMemberName, 282 DispatchEx_GetNextDispID, 283 DispatchEx_GetNameSpaceParent 284 }; 285 static IDispatchEx xmlhttprequest_onreadystatechange_obj = { &xmlhttprequest_onreadystatechangeFuncVtbl }; 286 287 static BOOL doc_complete; 288 static IHTMLDocument2 *notif_doc; 289 290 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, 291 REFIID riid, void**ppv) 292 { 293 if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) { 294 *ppv = iface; 295 return S_OK; 296 } 297 298 ok(0, "unexpected call\n"); 299 return E_NOINTERFACE; 300 } 301 302 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface) 303 { 304 return 2; 305 } 306 307 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface) 308 { 309 return 1; 310 } 311 312 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID) 313 { 314 if(dispID == DISPID_READYSTATE){ 315 BSTR state; 316 HRESULT hres; 317 318 hres = IHTMLDocument2_get_readyState(notif_doc, &state); 319 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 320 321 if(!strcmp_wa(state, "complete")) 322 doc_complete = TRUE; 323 324 SysFreeString(state); 325 } 326 327 return S_OK; 328 } 329 330 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID) 331 { 332 ok(0, "unexpected call\n"); 333 return E_NOTIMPL; 334 } 335 336 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = { 337 PropertyNotifySink_QueryInterface, 338 PropertyNotifySink_AddRef, 339 PropertyNotifySink_Release, 340 PropertyNotifySink_OnChanged, 341 PropertyNotifySink_OnRequestEdit 342 }; 343 344 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl }; 345 346 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise) 347 { 348 IConnectionPointContainer *container; 349 IConnectionPoint *cp; 350 DWORD cookie; 351 HRESULT hres; 352 353 hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); 354 ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); 355 356 hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp); 357 IConnectionPointContainer_Release(container); 358 ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); 359 360 hres = IConnectionPoint_Advise(cp, unk_advise, &cookie); 361 IConnectionPoint_Release(cp); 362 ok(hres == S_OK, "Advise failed: %08x\n", hres); 363 } 364 365 static void pump_msgs(BOOL *b) 366 { 367 MSG msg; 368 369 if(b) { 370 while(!*b && GetMessageW(&msg, NULL, 0, 0)) { 371 TranslateMessage(&msg); 372 DispatchMessageW(&msg); 373 } 374 }else { 375 while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { 376 TranslateMessage(&msg); 377 DispatchMessageW(&msg); 378 } 379 } 380 } 381 382 383 struct HEADER_TYPE { 384 const char *key; 385 const char *value; 386 }; 387 388 static void create_xmlhttprequest(IHTMLDocument2 *doc) 389 { 390 IHTMLWindow2 *window; 391 IHTMLWindow5 *window5; 392 VARIANT var; 393 IHTMLXMLHttpRequestFactory *factory; 394 HRESULT hres; 395 396 hres = IHTMLDocument2_get_parentWindow(doc, &window); 397 ok(hres == S_OK, "get_parentWindow failed: %08x\n", hres); 398 ok(window != NULL, "window == NULL\n"); 399 400 hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow5, (void**)&window5); 401 IHTMLWindow2_Release(window); 402 if(FAILED(hres)) { 403 win_skip("IHTMLWindow5 not supported\n"); 404 return; 405 } 406 407 VariantInit(&var); 408 hres = IHTMLWindow5_get_XMLHttpRequest(window5, &var); 409 IHTMLWindow5_Release(window5); 410 ok(hres == S_OK, "get_XMLHttpRequest failed: %08x\n", hres); 411 ok(V_VT(&var) == VT_DISPATCH, "V_VT(&var) is %08x, expected VT_DISPATCH\n", V_VT(&var)); 412 413 hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLXMLHttpRequestFactory, (void**)&factory); 414 VariantClear(&var); 415 ok(hres == S_OK, "QueryInterface(IID_IHTMLXMLHttpRequestFactory) failed: %08x\n", hres); 416 ok(factory != NULL, "factory == NULL\n"); 417 418 hres = IHTMLXMLHttpRequestFactory_create(factory, &xhr); 419 IHTMLXMLHttpRequestFactory_Release(factory); 420 ok(hres == S_OK, "create failed: %08x\n", hres); 421 ok(xhr != NULL, "xhr == NULL\n"); 422 } 423 424 static void test_header(const struct HEADER_TYPE expect[], int num) 425 { 426 int i; 427 BSTR key, text, all_header; 428 HRESULT hres; 429 char all[4096], buf[512]; 430 431 all_header = NULL; 432 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &all_header); 433 ok(hres == S_OK, "getAllResponseHeader failed: %08x\n", hres); 434 ok(all_header != NULL, "all_header == NULL\n"); 435 436 WideCharToMultiByte(CP_UTF8, 0, all_header, -1, all, sizeof(all), NULL, NULL); 437 SysFreeString(all_header); 438 439 for(i = 0; i < num; ++i) { 440 text = NULL; 441 key = a2bstr(expect[i].key); 442 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, key, &text); 443 ok(hres == S_OK, "getResponseHeader failed, got %08x\n", hres); 444 ok(text != NULL, "text == NULL\n"); 445 ok(!strcmp_wa(text, expect[i].value), 446 "Expect %s: %s, got %s\n", expect[i].key, expect[i].value, wine_dbgstr_w(text)); 447 SysFreeString(key); 448 SysFreeString(text); 449 450 strcpy(buf, expect[i].key); 451 strcat(buf, ": "); 452 strcat(buf, expect[i].value); 453 ok(strstr(all, buf) != NULL, "AllResponseHeaders(%s) don't have expected substr(%s)\n", all, buf); 454 } 455 } 456 457 static void test_sync_xhr(IHTMLDocument2 *doc, const char *xml_url, const char *expect_text) 458 { 459 VARIANT vbool, vempty, var; 460 BSTR method, url; 461 BSTR text; 462 LONG val; 463 HRESULT hres; 464 static const struct HEADER_TYPE expect_headers[] = { 465 {"Server", "Apache"}, 466 {"Accept-Ranges", "bytes"}, 467 {"Content-Length", "51"}, 468 {"Content-Type", "application/xml"} 469 }; 470 471 create_xmlhttprequest(doc); 472 if(!xhr) 473 return; 474 475 V_VT(&var) = VT_EMPTY; 476 hres = IHTMLXMLHttpRequest_get_onreadystatechange(xhr, &var); 477 ok(hres == S_OK, "get_onreadystatechange failed: %08x\n", hres); 478 ok(V_VT(&var) == VT_NULL, "V_VT(onreadystatechange) = %d\n", V_VT(&var)); 479 480 V_VT(&var) = VT_DISPATCH; 481 V_DISPATCH(&var) = (IDispatch*)&xmlhttprequest_onreadystatechange_obj; 482 hres = IHTMLXMLHttpRequest_put_onreadystatechange(xhr, var); 483 ok(hres == S_OK, "put_onreadystatechange failed: %08x\n", hres); 484 485 V_VT(&var) = VT_EMPTY; 486 hres = IHTMLXMLHttpRequest_get_onreadystatechange(xhr, &var); 487 ok(hres == S_OK, "get_onreadystatechange failed: %08x\n", hres); 488 ok(V_VT(&var) == VT_DISPATCH, "V_VT(onreadystatechange) = %d\n", V_VT(&var)); 489 ok(V_DISPATCH(&var) == (IDispatch*)&xmlhttprequest_onreadystatechange_obj, "unexpected onreadystatechange value\n"); 490 491 hres = IHTMLXMLHttpRequest_get_readyState(xhr, NULL); 492 ok(hres == E_POINTER, "Expect E_POINTER, got %08x\n", hres); 493 494 val = 0xdeadbeef; 495 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 496 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 497 ok(val == 0, "Expect UNSENT, got %d\n", val); 498 499 hres = IHTMLXMLHttpRequest_get_status(xhr, NULL); 500 ok(hres == E_POINTER, "Expect E_POINTER, got %08x\n", hres); 501 502 val = 0xdeadbeef; 503 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 504 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 505 ok(val == 0, "Expect 0, got %d\n", val); 506 507 hres = IHTMLXMLHttpRequest_get_statusText(xhr, NULL); 508 ok(hres == E_POINTER, "Expect E_POINTER, got %08x\n", hres); 509 510 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 511 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 512 ok(text == NULL, "Expect NULL, got %p\n", text); 513 514 text = (BSTR)0xdeadbeef; 515 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &text); 516 ok(hres == E_FAIL, "got %08x\n", hres); 517 ok(text == NULL, "text = %p\n", text); 518 519 text = (BSTR)0xdeadbeef; 520 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, &text); 521 ok(hres == E_FAIL, "got %08x\n", hres); 522 ok(text == NULL, "text = %p\n", text); 523 524 method = a2bstr("GET"); 525 url = a2bstr(xml_url); 526 V_VT(&vbool) = VT_BOOL; 527 V_BOOL(&vbool) = VARIANT_FALSE; 528 V_VT(&vempty) = VT_EMPTY; 529 530 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 531 hres = IHTMLXMLHttpRequest_open(xhr, method, url, vbool, vempty, vempty); 532 todo_wine ok(hres == S_OK, "open failed: %08x\n", hres); /* Gecko 30+ only supports async */ 533 todo_wine CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 534 535 SysFreeString(method); 536 SysFreeString(url); 537 538 if(FAILED(hres)) { 539 IHTMLXMLHttpRequest_Release(xhr); 540 xhr = NULL; 541 return; 542 } 543 544 text = (BSTR)0xdeadbeef; 545 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &text); 546 ok(hres == E_FAIL, "got %08x\n", hres); 547 ok(text == NULL, "text = %p\n", text); 548 549 text = (BSTR)0xdeadbeef; 550 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, &text); 551 ok(hres == E_FAIL, "got %08x\n", hres); 552 ok(text == NULL, "text = %p\n", text); 553 554 val = 0xdeadbeef; 555 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 556 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 557 ok(val == 0, "Expect 0, got %d\n", val); 558 559 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 560 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 561 ok(text == NULL, "Expect NULL, got %p\n", text); 562 563 val = 0xdeadbeef; 564 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 565 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 566 ok(val == 1, "Expect OPENED, got %d\n", val); 567 568 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 569 SET_EXPECT(xmlhttprequest_onreadystatechange_headers_received); 570 SET_EXPECT(xmlhttprequest_onreadystatechange_loading); 571 SET_EXPECT(xmlhttprequest_onreadystatechange_done); 572 loading_cnt = 0; 573 hres = IHTMLXMLHttpRequest_send(xhr, vempty); 574 ok(hres == S_OK, "send failed: %08x\n", hres); 575 CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 576 CHECK_CALLED(xmlhttprequest_onreadystatechange_headers_received); 577 CHECK_CALLED(xmlhttprequest_onreadystatechange_loading); 578 CHECK_CALLED(xmlhttprequest_onreadystatechange_done); 579 ok(loading_cnt == 1, "loading_cnt = %d\n", loading_cnt); 580 581 text = NULL; 582 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, &text); 583 ok(hres == S_OK, "getResponseHeader failed, got %08x\n", hres); 584 ok(text != NULL, "text == NULL\n"); 585 SysFreeString(text); 586 587 if(expect_text) 588 test_header(expect_headers, sizeof(expect_headers)/sizeof(expect_headers[0])); 589 590 val = 0xdeadbeef; 591 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 592 ok(hres == S_OK, "get_status failed: %08x\n", hres); 593 ok(val == 200, "Expect 200, got %d\n", val); 594 595 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 596 ok(hres == S_OK, "get_statusText failed: %08x\n", hres); 597 ok(text != NULL, "text == NULL\n"); 598 ok(!strcmp_wa(text, "OK"), 599 "Expected \"OK\", got %s\n", wine_dbgstr_w(text)); 600 SysFreeString(text); 601 602 val = 0xdeadbeef; 603 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 604 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 605 ok(val == 4, "Expect DONE, got %d\n", val); 606 607 hres = IHTMLXMLHttpRequest_get_responseText(xhr, &text); 608 ok(hres == S_OK, "get_responseText failed: %08x\n", hres); 609 ok(text != NULL, "test == NULL\n"); 610 if(expect_text) 611 ok(!strcmp_wa(text, expect_text), "expect %s, got %s\n", 612 expect_text, wine_dbgstr_w(text)); 613 SysFreeString(text); 614 615 IHTMLXMLHttpRequest_Release(xhr); 616 xhr = NULL; 617 } 618 619 static void test_async_xhr(IHTMLDocument2 *doc, const char *xml_url, const char *expect_text) 620 { 621 VARIANT vbool, vempty, var; 622 BSTR method, url; 623 BSTR text; 624 LONG val; 625 HRESULT hres; 626 static const struct HEADER_TYPE expect_headers[] = { 627 {"Content-Length", "51"}, 628 {"Content-Type", "application/xml"} 629 }; 630 631 create_xmlhttprequest(doc); 632 if(!xhr) 633 return; 634 635 V_VT(&var) = VT_DISPATCH; 636 V_DISPATCH(&var) = (IDispatch*)&xmlhttprequest_onreadystatechange_obj; 637 hres = IHTMLXMLHttpRequest_put_onreadystatechange(xhr, var); 638 ok(hres == S_OK, "put_onreadystatechange failed: %08x\n", hres); 639 640 V_VT(&var) = VT_EMPTY; 641 hres = IHTMLXMLHttpRequest_get_onreadystatechange(xhr, &var); 642 ok(hres == S_OK, "get_onreadystatechange failed: %08x\n", hres); 643 ok(V_VT(&var) == VT_DISPATCH, "V_VT(onreadystatechange) = %d\n", V_VT(&var)); 644 ok(V_DISPATCH(&var) == (IDispatch*)&xmlhttprequest_onreadystatechange_obj, "unexpected onreadystatechange value\n"); 645 646 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, NULL, &text); 647 ok(hres == E_INVALIDARG, "Expect E_INVALIDARG, got %08x\n", hres); 648 649 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, NULL); 650 ok(hres == E_POINTER, "Expect E_POINTER, got %08x\n", hres); 651 652 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, NULL, NULL); 653 ok(hres == E_POINTER || broken(hres == E_INVALIDARG), /* Vista and before */ 654 "Expect E_POINTER, got %08x\n", hres); 655 656 text = (BSTR)0xdeadbeef; 657 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, &text); 658 ok(hres == E_FAIL, "got %08x\n", hres); 659 ok(text == NULL, "text = %p\n", text); 660 661 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, NULL); 662 ok(hres == E_POINTER, "Expect E_POINTER, got %08x\n", hres); 663 664 text = (BSTR)0xdeadbeef; 665 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &text); 666 ok(hres == E_FAIL, "got %08x\n", hres); 667 ok(text == NULL, "text = %p\n", text); 668 669 val = 0xdeadbeef; 670 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 671 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 672 ok(val == 0, "Expect 0, got %d\n", val); 673 674 text = (BSTR)0xdeadbeef; 675 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 676 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 677 ok(text == NULL, "Expect NULL, got %p\n", text); 678 679 val = 0xdeadbeef; 680 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 681 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 682 ok(val == 0, "Expect UNSENT, got %d\n", val); 683 684 method = a2bstr("GET"); 685 url = a2bstr(xml_url); 686 V_VT(&vbool) = VT_BOOL; 687 V_BOOL(&vbool) = VARIANT_TRUE; 688 V_VT(&vempty) = VT_EMPTY; 689 690 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 691 hres = IHTMLXMLHttpRequest_open(xhr, method, url, vbool, vempty, vempty); 692 ok(hres == S_OK, "open failed: %08x\n", hres); 693 CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 694 695 SysFreeString(method); 696 SysFreeString(url); 697 698 if(FAILED(hres)) { 699 IHTMLXMLHttpRequest_Release(xhr); 700 xhr = NULL; 701 return; 702 } 703 704 text = (BSTR)0xdeadbeef; 705 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &text); 706 ok(hres == E_FAIL, "got %08x\n", hres); 707 ok(text == NULL, "text = %p\n", text); 708 709 text = (BSTR)0xdeadbeef; 710 hres = IHTMLXMLHttpRequest_getResponseHeader(xhr, content_type, &text); 711 ok(hres == E_FAIL, "got %08x\n", hres); 712 ok(text == NULL, "text = %p\n", text); 713 714 val = 0xdeadbeef; 715 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 716 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 717 ok(val == 0, "Expect 0, got %d\n", val); 718 719 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 720 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 721 ok(text == NULL, "Expect NULL, got %p\n", text); 722 723 val = 0xdeadbeef; 724 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 725 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 726 ok(val == 1, "Expect OPENED, got %d\n", val); 727 728 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 729 SET_EXPECT(xmlhttprequest_onreadystatechange_headers_received); 730 SET_EXPECT(xmlhttprequest_onreadystatechange_loading); 731 SET_EXPECT(xmlhttprequest_onreadystatechange_done); 732 loading_cnt = 0; 733 hres = IHTMLXMLHttpRequest_send(xhr, vempty); 734 735 ok(hres == S_OK, "send failed: %08x\n", hres); 736 if(SUCCEEDED(hres)) 737 pump_msgs(&called_xmlhttprequest_onreadystatechange_done); 738 todo_wine CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 739 CHECK_CALLED(xmlhttprequest_onreadystatechange_headers_received); 740 CHECK_CALLED(xmlhttprequest_onreadystatechange_loading); 741 CHECK_CALLED(xmlhttprequest_onreadystatechange_done); 742 /* Workaround for loading large files */ 743 if(expect_text) 744 ok(loading_cnt == 1, "loading_cnt = %d\n", loading_cnt); 745 else 746 todo_wine ok(loading_cnt == 1, "loading_cnt = %d\n", loading_cnt); 747 748 if(FAILED(hres)) { 749 IHTMLXMLHttpRequest_Release(xhr); 750 xhr = NULL; 751 return; 752 } 753 754 text = NULL; 755 hres = IHTMLXMLHttpRequest_getAllResponseHeaders(xhr, &text); 756 ok(hres == S_OK, "getAllResponseHeader failed, got %08x\n", hres); 757 ok(text != NULL, "text == NULL\n"); 758 SysFreeString(text); 759 760 if(expect_text) 761 test_header(expect_headers, sizeof(expect_headers)/sizeof(expect_headers[0])); 762 763 val = 0xdeadbeef; 764 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 765 ok(hres == S_OK, "get_status failed: %08x\n", hres); 766 ok(val == 200, "Expect 200, got %d\n", val); 767 768 text = NULL; 769 hres = IHTMLXMLHttpRequest_get_statusText(xhr, &text); 770 ok(hres == S_OK, "get_statusText failed: %08x\n", hres); 771 ok(text != NULL, "text == NULL\n"); 772 ok(!strcmp_wa(text, "OK"), "Expected \"OK\", got %s\n", wine_dbgstr_w(text)); 773 SysFreeString(text); 774 775 val = 0xdeadbeef; 776 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 777 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 778 ok(val == 4, "Expect DONE, got %d\n", val); 779 780 text = NULL; 781 hres = IHTMLXMLHttpRequest_get_responseText(xhr, &text); 782 ok(hres == S_OK, "get_responseText failed: %08x\n", hres); 783 ok(text != NULL, "test == NULL\n"); 784 if(expect_text) 785 ok(!strcmp_wa(text, expect_text), "expect %s, got %s\n", 786 expect_text, wine_dbgstr_w(text)); 787 SysFreeString(text); 788 789 IHTMLXMLHttpRequest_Release(xhr); 790 xhr = NULL; 791 } 792 793 static void test_async_xhr_abort(IHTMLDocument2 *doc, const char *xml_url) 794 { 795 VARIANT vbool, vempty, var; 796 BSTR method, url; 797 LONG val; 798 HRESULT hres; 799 800 method = a2bstr("GET"); 801 url = a2bstr(xml_url); 802 V_VT(&vbool) = VT_BOOL; 803 V_BOOL(&vbool) = VARIANT_TRUE; 804 V_VT(&vempty) = VT_EMPTY; 805 806 trace("abort before send() is fired\n"); 807 create_xmlhttprequest(doc); 808 if(!xhr) 809 return; 810 811 V_VT(&var) = VT_DISPATCH; 812 V_DISPATCH(&var) = (IDispatch*)&xmlhttprequest_onreadystatechange_obj; 813 hres = IHTMLXMLHttpRequest_put_onreadystatechange(xhr, var); 814 815 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 816 hres = IHTMLXMLHttpRequest_open(xhr, method, url, vbool, vempty, vempty); 817 ok(hres == S_OK, "open failed: %08x\n", hres); 818 CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 819 820 hres = IHTMLXMLHttpRequest_abort(xhr); 821 ok(hres == S_OK, "abort failed: %08x\n", hres); 822 823 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 824 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 825 ok(val == 0, "Expect 0, got %d\n", val); 826 827 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 828 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 829 ok(val == 0, "Expect UNSENT, got %d\n", val); 830 831 IHTMLXMLHttpRequest_Release(xhr); 832 xhr = NULL; 833 834 trace("abort after send() is fired\n"); 835 create_xmlhttprequest(doc); 836 V_VT(&var) = VT_DISPATCH; 837 V_DISPATCH(&var) = (IDispatch*)&xmlhttprequest_onreadystatechange_obj; 838 hres = IHTMLXMLHttpRequest_put_onreadystatechange(xhr, var); 839 840 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 841 hres = IHTMLXMLHttpRequest_open(xhr, method, url, vbool, vempty, vempty); 842 ok(hres == S_OK, "open failed: %08x\n", hres); 843 CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 844 845 loading_cnt = 0; 846 readystatechange_cnt = 0; 847 SET_EXPECT(xmlhttprequest_onreadystatechange_opened); 848 SET_EXPECT(xmlhttprequest_onreadystatechange_done); 849 hres = IHTMLXMLHttpRequest_send(xhr, vempty); 850 ok(hres == S_OK, "send failed: %08x\n", hres); 851 todo_wine CHECK_CALLED(xmlhttprequest_onreadystatechange_opened); 852 853 hres = IHTMLXMLHttpRequest_abort(xhr); 854 ok(hres == S_OK, "abort failed: %08x\n", hres); 855 CHECK_CALLED(xmlhttprequest_onreadystatechange_done); 856 857 hres = IHTMLXMLHttpRequest_get_readyState(xhr, &val); 858 ok(hres == S_OK, "get_readyState failed: %08x\n", hres); 859 ok(val == 0, "Expect UNSENT, got %d\n", val); 860 861 hres = IHTMLXMLHttpRequest_get_status(xhr, &val); 862 ok(hres == E_FAIL, "Expect E_FAIL, got: %08x\n", hres); 863 ok(val == 0, "Expect 0, got %d\n", val); 864 865 ok(loading_cnt == 0, "loading_cnt = %d, expect 0, loading_cnt\n", loading_cnt); 866 todo_wine ok(readystatechange_cnt == 2, "readystatechange_cnt = %d, expect 2\n", readystatechange_cnt); 867 868 IHTMLXMLHttpRequest_Release(xhr); 869 xhr = NULL; 870 871 SysFreeString(method); 872 SysFreeString(url); 873 } 874 875 static IHTMLDocument2 *create_doc_from_url(const char *start_url) 876 { 877 BSTR url; 878 IBindCtx *bc; 879 IMoniker *url_mon; 880 IPersistMoniker *persist_mon; 881 IHTMLDocument2 *doc; 882 HRESULT hres; 883 884 hres = CreateBindCtx(0, &bc); 885 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres); 886 887 url = a2bstr(start_url); 888 hres = CreateURLMoniker(NULL, url, &url_mon); 889 ok(hres == S_OK, "CreateURLMoniker failed: 0x%08x\n", hres); 890 891 hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, 892 CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, &IID_IHTMLDocument2, 893 (void**)&doc); 894 ok(hres == S_OK, "CoCreateInstance failed: 0x%08x\n", hres); 895 896 hres = IHTMLDocument2_QueryInterface(doc, &IID_IPersistMoniker, 897 (void**)&persist_mon); 898 ok(hres == S_OK, "IHTMLDocument2_QueryInterface failed: 0x%08x\n", hres); 899 900 hres = IPersistMoniker_Load(persist_mon, FALSE, url_mon, bc, 901 STGM_SHARE_EXCLUSIVE | STGM_READWRITE); 902 ok(hres == S_OK, "IPersistMoniker_Load failed: 0x%08x\n", hres); 903 904 IPersistMoniker_Release(persist_mon); 905 IMoniker_Release(url_mon); 906 IBindCtx_Release(bc); 907 SysFreeString(url); 908 909 doc_complete = FALSE; 910 notif_doc = doc; 911 do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); 912 pump_msgs(&doc_complete); 913 914 return doc; 915 } 916 917 START_TEST(xmlhttprequest) 918 { 919 IHTMLDocument2 *doc; 920 static const char start_url[] = "http://test.winehq.org/tests/hello.html"; 921 static const char xml_url[] = "http://test.winehq.org/tests/xmltest.xml"; 922 static const char large_page_url[] = "http://test.winehq.org/tests/data.php"; 923 static const char expect_response_text[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<a>TEST</a>\n"; 924 925 CoInitialize(NULL); 926 927 content_type = a2bstr("Content-Type"); 928 doc = create_doc_from_url(start_url); 929 if(doc) { 930 test_sync_xhr(doc, xml_url, expect_response_text); 931 test_sync_xhr(doc, large_page_url, NULL); 932 test_async_xhr(doc, xml_url, expect_response_text); 933 test_async_xhr(doc, large_page_url, NULL); 934 test_async_xhr_abort(doc, large_page_url); 935 IHTMLDocument2_Release(doc); 936 } 937 SysFreeString(content_type); 938 939 CoUninitialize(); 940 } 941