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