1 /* 2 * test status notifications 3 * 4 * Copyright 2008 Hans Leidekker for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #include <stdlib.h> 23 #include <windef.h> 24 #include <winbase.h> 25 #include <winsock2.h> 26 #include <ws2tcpip.h> 27 #include <winhttp.h> 28 29 #include "wine/test.h" 30 31 static const WCHAR user_agent[] = {'w','i','n','e','t','e','s','t',0}; 32 static const WCHAR test_winehq[] = {'t','e','s','t','.','w','i','n','e','h','q','.','o','r','g',0}; 33 static const WCHAR tests_hello_html[] = {'/','t','e','s','t','s','/','h','e','l','l','o','.','h','t','m','l',0}; 34 static const WCHAR tests_redirect[] = {'/','t','e','s','t','s','/','r','e','d','i','r','e','c','t',0}; 35 static const WCHAR localhostW[] = {'l','o','c','a','l','h','o','s','t',0}; 36 37 enum api 38 { 39 winhttp_connect = 1, 40 winhttp_open_request, 41 winhttp_send_request, 42 winhttp_receive_response, 43 winhttp_query_data, 44 winhttp_read_data, 45 winhttp_write_data, 46 winhttp_close_handle 47 }; 48 49 struct notification 50 { 51 enum api function; /* api responsible for notification */ 52 unsigned int status; /* status received */ 53 DWORD flags; /* a combination of NF_* flags */ 54 }; 55 56 #define NF_ALLOW 0x0001 /* notification may or may not happen */ 57 #define NF_WINE_ALLOW 0x0002 /* wine sends notification when it should not */ 58 #define NF_SIGNAL 0x0004 /* signal wait handle when notified */ 59 60 struct info 61 { 62 enum api function; 63 const struct notification *test; 64 unsigned int count; 65 unsigned int index; 66 HANDLE wait; 67 unsigned int line; 68 }; 69 70 struct test_request 71 { 72 HINTERNET session; 73 HINTERNET connection; 74 HINTERNET request; 75 }; 76 77 static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen ) 78 { 79 BOOL status_ok, function_ok; 80 struct info *info = (struct info *)context; 81 82 if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) 83 { 84 DWORD size = sizeof(struct info *); 85 WinHttpQueryOption( handle, WINHTTP_OPTION_CONTEXT_VALUE, &info, &size ); 86 } 87 while (info->index < info->count && info->test[info->index].status != status && (info->test[info->index].flags & NF_ALLOW)) 88 info->index++; 89 while (info->index < info->count && (info->test[info->index].flags & NF_WINE_ALLOW)) 90 { 91 todo_wine ok(info->test[info->index].status != status, "unexpected %x notification\n", status); 92 if (info->test[info->index].status == status) break; 93 info->index++; 94 } 95 ok(info->index < info->count, "%u: unexpected notification 0x%08x\n", info->line, status); 96 if (info->index >= info->count) return; 97 98 status_ok = (info->test[info->index].status == status); 99 function_ok = (info->test[info->index].function == info->function); 100 ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[info->index].status, status); 101 ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function); 102 103 if (status_ok && function_ok && info->test[info->index++].flags & NF_SIGNAL) 104 { 105 SetEvent( info->wait ); 106 } 107 } 108 109 static const struct notification cache_test[] = 110 { 111 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 112 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 113 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME }, 114 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED }, 115 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, 116 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, 117 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 118 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 119 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 120 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 121 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, 122 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, 123 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, 124 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 125 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, 126 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, 127 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 128 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 129 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 130 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 131 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, 132 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, 133 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 134 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, 135 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, 136 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 137 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 138 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, 139 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, 140 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, 141 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, 142 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 143 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 144 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 145 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 146 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, 147 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, 148 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, 149 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 150 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, 151 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, 152 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 153 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 154 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 155 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 156 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, 157 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, 158 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 159 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }, 160 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } 161 }; 162 163 static void setup_test( struct info *info, enum api function, unsigned int line ) 164 { 165 if (info->wait) ResetEvent( info->wait ); 166 info->function = function; 167 info->line = line; 168 while (info->index < info->count && info->test[info->index].function != function 169 && (info->test[info->index].flags & (NF_ALLOW | NF_WINE_ALLOW))) 170 info->index++; 171 ok_(__FILE__,line)(info->test[info->index].function == function, 172 "unexpected function %u, expected %u. probably some notifications were missing\n", 173 info->test[info->index].function, function); 174 } 175 176 static void end_test( struct info *info, unsigned int line ) 177 { 178 ok_(__FILE__,line)(info->index == info->count, "some notifications were missing: %x\n", 179 info->test[info->index].status); 180 } 181 182 static void test_connection_cache( void ) 183 { 184 HANDLE ses, con, req, event; 185 DWORD size, status, err; 186 BOOL ret, unload = TRUE; 187 struct info info, *context = &info; 188 189 info.test = cache_test; 190 info.count = sizeof(cache_test) / sizeof(cache_test[0]); 191 info.index = 0; 192 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); 193 194 ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); 195 ok(ses != NULL, "failed to open session %u\n", GetLastError()); 196 197 event = CreateEventW( NULL, FALSE, FALSE, NULL ); 198 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); 199 if (!ret) 200 { 201 win_skip("Unload event not supported\n"); 202 unload = FALSE; 203 } 204 205 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); 206 207 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 208 ok(ret, "failed to set context value %u\n", GetLastError()); 209 210 setup_test( &info, winhttp_connect, __LINE__ ); 211 con = WinHttpConnect( ses, test_winehq, 0, 0 ); 212 ok(con != NULL, "failed to open a connection %u\n", GetLastError()); 213 214 setup_test( &info, winhttp_open_request, __LINE__ ); 215 req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); 216 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 217 218 setup_test( &info, winhttp_send_request, __LINE__ ); 219 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 220 err = GetLastError(); 221 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 222 { 223 skip("connection failed, skipping\n"); 224 goto done; 225 } 226 ok(ret, "failed to send request %u\n", GetLastError()); 227 228 setup_test( &info, winhttp_receive_response, __LINE__ ); 229 ret = WinHttpReceiveResponse( req, NULL ); 230 ok(ret, "failed to receive response %u\n", GetLastError()); 231 232 size = sizeof(status); 233 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 234 ok(ret, "failed unexpectedly %u\n", GetLastError()); 235 ok(status == 200, "request failed unexpectedly %u\n", status); 236 237 ResetEvent( info.wait ); 238 setup_test( &info, winhttp_close_handle, __LINE__ ); 239 WinHttpCloseHandle( req ); 240 WaitForSingleObject( info.wait, INFINITE ); 241 242 setup_test( &info, winhttp_open_request, __LINE__ ); 243 req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); 244 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 245 246 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 247 ok(ret, "failed to set context value %u\n", GetLastError()); 248 249 setup_test( &info, winhttp_send_request, __LINE__ ); 250 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 251 err = GetLastError(); 252 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 253 { 254 skip("connection failed, skipping\n"); 255 goto done; 256 } 257 ok(ret, "failed to send request %u\n", GetLastError()); 258 259 setup_test( &info, winhttp_receive_response, __LINE__ ); 260 ret = WinHttpReceiveResponse( req, NULL ); 261 ok(ret, "failed to receive response %u\n", GetLastError()); 262 263 size = sizeof(status); 264 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 265 ok(ret, "failed unexpectedly %u\n", GetLastError()); 266 ok(status == 200, "request failed unexpectedly %u\n", status); 267 268 ResetEvent( info.wait ); 269 setup_test( &info, winhttp_close_handle, __LINE__ ); 270 WinHttpCloseHandle( req ); 271 WinHttpCloseHandle( req ); 272 WinHttpCloseHandle( con ); 273 WaitForSingleObject( info.wait, INFINITE ); 274 275 if (unload) 276 { 277 status = WaitForSingleObject( event, 0 ); 278 ok(status == WAIT_TIMEOUT, "got %08x\n", status); 279 } 280 281 setup_test( &info, winhttp_close_handle, __LINE__ ); 282 WinHttpCloseHandle( ses ); 283 WaitForSingleObject( info.wait, INFINITE ); 284 285 if (unload) 286 { 287 status = WaitForSingleObject( event, 100 ); 288 ok(status == WAIT_OBJECT_0, "got %08x\n", status); 289 } 290 291 292 ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); 293 ok(ses != NULL, "failed to open session %u\n", GetLastError()); 294 295 if (unload) 296 { 297 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); 298 ok(ret, "failed to set unload option\n"); 299 } 300 301 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); 302 303 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 304 ok(ret, "failed to set context value %u\n", GetLastError()); 305 306 setup_test( &info, winhttp_connect, __LINE__ ); 307 con = WinHttpConnect( ses, test_winehq, 0, 0 ); 308 ok(con != NULL, "failed to open a connection %u\n", GetLastError()); 309 310 setup_test( &info, winhttp_open_request, __LINE__ ); 311 req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); 312 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 313 314 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 315 ok(ret, "failed to set context value %u\n", GetLastError()); 316 317 setup_test( &info, winhttp_send_request, __LINE__ ); 318 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 319 err = GetLastError(); 320 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 321 { 322 skip("connection failed, skipping\n"); 323 goto done; 324 } 325 ok(ret, "failed to send request %u\n", GetLastError()); 326 327 setup_test( &info, winhttp_receive_response, __LINE__ ); 328 ret = WinHttpReceiveResponse( req, NULL ); 329 ok(ret, "failed to receive response %u\n", GetLastError()); 330 331 size = sizeof(status); 332 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 333 ok(ret, "failed unexpectedly %u\n", GetLastError()); 334 ok(status == 200, "request failed unexpectedly %u\n", status); 335 336 ResetEvent( info.wait ); 337 setup_test( &info, winhttp_close_handle, __LINE__ ); 338 WinHttpCloseHandle( req ); 339 WaitForSingleObject( info.wait, INFINITE ); 340 341 setup_test( &info, winhttp_open_request, __LINE__ ); 342 req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); 343 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 344 345 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 346 ok(ret, "failed to set context value %u\n", GetLastError()); 347 348 setup_test( &info, winhttp_send_request, __LINE__ ); 349 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 350 err = GetLastError(); 351 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 352 { 353 skip("connection failed, skipping\n"); 354 goto done; 355 } 356 ok(ret, "failed to send request %u\n", GetLastError()); 357 358 setup_test( &info, winhttp_receive_response, __LINE__ ); 359 ret = WinHttpReceiveResponse( req, NULL ); 360 ok(ret, "failed to receive response %u\n", GetLastError()); 361 362 size = sizeof(status); 363 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 364 ok(ret, "failed unexpectedly %u\n", GetLastError()); 365 ok(status == 200, "request failed unexpectedly %u\n", status); 366 367 setup_test( &info, winhttp_close_handle, __LINE__ ); 368 done: 369 WinHttpCloseHandle( req ); 370 WinHttpCloseHandle( con ); 371 WaitForSingleObject( info.wait, INFINITE ); 372 373 if (unload) 374 { 375 status = WaitForSingleObject( event, 0 ); 376 ok(status == WAIT_TIMEOUT, "got %08x\n", status); 377 } 378 379 setup_test( &info, winhttp_close_handle, __LINE__ ); 380 WinHttpCloseHandle( ses ); 381 WaitForSingleObject( info.wait, INFINITE ); 382 CloseHandle( info.wait ); 383 end_test( &info, __LINE__ ); 384 385 if (unload) 386 { 387 status = WaitForSingleObject( event, 100 ); 388 ok(status == WAIT_OBJECT_0, "got %08x\n", status); 389 } 390 391 CloseHandle( event ); 392 } 393 394 static const struct notification redirect_test[] = 395 { 396 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 397 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 398 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, 399 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, 400 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, 401 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, 402 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 403 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 404 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 405 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 406 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT }, 407 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW }, 408 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW }, 409 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, 410 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW }, 411 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 412 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 413 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 414 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 415 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, 416 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW }, 417 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 418 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 419 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } 420 }; 421 422 static void test_redirect( void ) 423 { 424 HANDLE ses, con, req; 425 DWORD size, status, err; 426 BOOL ret; 427 struct info info, *context = &info; 428 429 info.test = redirect_test; 430 info.count = sizeof(redirect_test) / sizeof(redirect_test[0]); 431 info.index = 0; 432 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); 433 434 ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); 435 ok(ses != NULL, "failed to open session %u\n", GetLastError()); 436 437 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); 438 439 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 440 ok(ret, "failed to set context value %u\n", GetLastError()); 441 442 setup_test( &info, winhttp_connect, __LINE__ ); 443 con = WinHttpConnect( ses, test_winehq, 0, 0 ); 444 ok(con != NULL, "failed to open a connection %u\n", GetLastError()); 445 446 setup_test( &info, winhttp_open_request, __LINE__ ); 447 req = WinHttpOpenRequest( con, NULL, tests_redirect, NULL, NULL, NULL, 0 ); 448 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 449 450 setup_test( &info, winhttp_send_request, __LINE__ ); 451 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 452 err = GetLastError(); 453 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 454 { 455 skip("connection failed, skipping\n"); 456 goto done; 457 } 458 ok(ret, "failed to send request %u\n", GetLastError()); 459 460 setup_test( &info, winhttp_receive_response, __LINE__ ); 461 ret = WinHttpReceiveResponse( req, NULL ); 462 ok(ret, "failed to receive response %u\n", GetLastError()); 463 464 size = sizeof(status); 465 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 466 ok(ret, "failed unexpectedly %u\n", GetLastError()); 467 ok(status == 200, "request failed unexpectedly %u\n", status); 468 469 setup_test( &info, winhttp_close_handle, __LINE__ ); 470 done: 471 WinHttpCloseHandle( req ); 472 WinHttpCloseHandle( con ); 473 WinHttpCloseHandle( ses ); 474 WaitForSingleObject( info.wait, INFINITE ); 475 CloseHandle( info.wait ); 476 end_test( &info, __LINE__ ); 477 } 478 479 static const struct notification async_test[] = 480 { 481 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 482 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 483 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW }, 484 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW }, 485 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW }, 486 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW }, 487 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 488 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 489 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, 490 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE }, 491 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED }, 492 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }, 493 { winhttp_query_data, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, NF_SIGNAL }, 494 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, 495 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, 496 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }, 497 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 498 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 499 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } 500 }; 501 502 static void test_async( void ) 503 { 504 HANDLE ses, con, req, event; 505 DWORD size, status, err; 506 BOOL ret, unload = TRUE; 507 struct info info, *context = &info; 508 char buffer[1024]; 509 510 info.test = async_test; 511 info.count = sizeof(async_test) / sizeof(async_test[0]); 512 info.index = 0; 513 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); 514 515 ses = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); 516 ok(ses != NULL, "failed to open session %u\n", GetLastError()); 517 518 event = CreateEventW( NULL, FALSE, FALSE, NULL ); 519 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) ); 520 if (!ret) 521 { 522 win_skip("Unload event not supported\n"); 523 unload = FALSE; 524 } 525 526 SetLastError( 0xdeadbeef ); 527 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); 528 err = GetLastError(); 529 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); 530 531 SetLastError( 0xdeadbeef ); 532 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); 533 err = GetLastError(); 534 ok(ret, "failed to set context value %u\n", err); 535 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); 536 537 setup_test( &info, winhttp_connect, __LINE__ ); 538 SetLastError( 0xdeadbeef ); 539 con = WinHttpConnect( ses, test_winehq, 0, 0 ); 540 err = GetLastError(); 541 ok(con != NULL, "failed to open a connection %u\n", err); 542 ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %u\n", err); 543 544 setup_test( &info, winhttp_open_request, __LINE__ ); 545 SetLastError( 0xdeadbeef ); 546 req = WinHttpOpenRequest( con, NULL, tests_hello_html, NULL, NULL, NULL, 0 ); 547 err = GetLastError(); 548 ok(req != NULL, "failed to open a request %u\n", err); 549 ok(err == ERROR_SUCCESS, "got %u\n", err); 550 551 setup_test( &info, winhttp_send_request, __LINE__ ); 552 SetLastError( 0xdeadbeef ); 553 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); 554 err = GetLastError(); 555 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT)) 556 { 557 skip("connection failed, skipping\n"); 558 WinHttpCloseHandle( req ); 559 WinHttpCloseHandle( con ); 560 WinHttpCloseHandle( ses ); 561 CloseHandle( info.wait ); 562 return; 563 } 564 ok(ret, "failed to send request %u\n", err); 565 ok(err == ERROR_SUCCESS, "got %u\n", err); 566 567 WaitForSingleObject( info.wait, INFINITE ); 568 569 setup_test( &info, winhttp_receive_response, __LINE__ ); 570 SetLastError( 0xdeadbeef ); 571 ret = WinHttpReceiveResponse( req, NULL ); 572 err = GetLastError(); 573 ok(ret, "failed to receive response %u\n", err); 574 ok(err == ERROR_SUCCESS, "got %u\n", err); 575 576 WaitForSingleObject( info.wait, INFINITE ); 577 578 size = sizeof(status); 579 SetLastError( 0xdeadbeef ); 580 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); 581 err = GetLastError(); 582 ok(ret, "failed unexpectedly %u\n", err); 583 ok(status == 200, "request failed unexpectedly %u\n", status); 584 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); 585 586 setup_test( &info, winhttp_query_data, __LINE__ ); 587 SetLastError( 0xdeadbeef ); 588 ret = WinHttpQueryDataAvailable( req, NULL ); 589 err = GetLastError(); 590 ok(ret, "failed to query data available %u\n", err); 591 ok(err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err); 592 593 WaitForSingleObject( info.wait, INFINITE ); 594 595 setup_test( &info, winhttp_read_data, __LINE__ ); 596 ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL ); 597 ok(ret, "failed to read data %u\n", err); 598 599 WaitForSingleObject( info.wait, INFINITE ); 600 601 setup_test( &info, winhttp_close_handle, __LINE__ ); 602 WinHttpCloseHandle( req ); 603 WinHttpCloseHandle( con ); 604 605 if (unload) 606 { 607 status = WaitForSingleObject( event, 0 ); 608 ok(status == WAIT_TIMEOUT, "got %08x\n", status); 609 } 610 WinHttpCloseHandle( ses ); 611 WaitForSingleObject( info.wait, INFINITE ); 612 end_test( &info, __LINE__ ); 613 614 if (unload) 615 { 616 status = WaitForSingleObject( event, 2000 ); 617 ok(status == WAIT_OBJECT_0, "got %08x\n", status); 618 } 619 CloseHandle( event ); 620 CloseHandle( info.wait ); 621 end_test( &info, __LINE__ ); 622 } 623 624 static const char okmsg[] = 625 "HTTP/1.1 200 OK\r\n" 626 "Server: winetest\r\n" 627 "\r\n"; 628 629 static const char page1[] = 630 "<HTML>\r\n" 631 "<HEAD><TITLE>winhttp test page</TITLE></HEAD>\r\n" 632 "<BODY>The quick brown fox jumped over the lazy dog<P></BODY>\r\n" 633 "</HTML>\r\n\r\n"; 634 635 struct server_info 636 { 637 HANDLE event; 638 int port; 639 }; 640 641 static int server_socket; 642 static HANDLE server_socket_available, server_socket_done; 643 644 static DWORD CALLBACK server_thread(LPVOID param) 645 { 646 struct server_info *si = param; 647 int r, c = -1, i, on; 648 SOCKET s; 649 struct sockaddr_in sa; 650 char buffer[0x100]; 651 WSADATA wsaData; 652 int last_request = 0; 653 654 WSAStartup(MAKEWORD(1,1), &wsaData); 655 656 s = socket(AF_INET, SOCK_STREAM, 0); 657 if (s == INVALID_SOCKET) 658 return 1; 659 660 on = 1; 661 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof on); 662 663 memset(&sa, 0, sizeof sa); 664 sa.sin_family = AF_INET; 665 sa.sin_port = htons(si->port); 666 sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 667 668 r = bind(s, (struct sockaddr *)&sa, sizeof(sa)); 669 if (r < 0) 670 return 1; 671 672 listen(s, 0); 673 SetEvent(si->event); 674 do 675 { 676 if (c == -1) c = accept(s, NULL, NULL); 677 678 memset(buffer, 0, sizeof buffer); 679 for(i = 0; i < sizeof buffer - 1; i++) 680 { 681 r = recv(c, &buffer[i], 1, 0); 682 if (r != 1) 683 break; 684 if (i < 4) continue; 685 if (buffer[i - 2] == '\n' && buffer[i] == '\n' && 686 buffer[i - 3] == '\r' && buffer[i - 1] == '\r') 687 break; 688 } 689 if (strstr(buffer, "GET /quit")) 690 { 691 send(c, okmsg, sizeof okmsg - 1, 0); 692 send(c, page1, sizeof page1 - 1, 0); 693 last_request = 1; 694 } 695 else if(strstr(buffer, "GET /socket")) 696 { 697 server_socket = c; 698 SetEvent(server_socket_available); 699 WaitForSingleObject(server_socket_done, INFINITE); 700 ResetEvent(server_socket_available); 701 } 702 shutdown(c, 2); 703 closesocket(c); 704 c = -1; 705 } while (!last_request); 706 707 closesocket(s); 708 return 0; 709 } 710 711 static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path) 712 { 713 HINTERNET ses, con, req; 714 char buffer[0x100]; 715 DWORD count, status, size; 716 BOOL ret; 717 718 ses = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); 719 ok(ses != NULL, "failed to open session %u\n", GetLastError()); 720 721 con = WinHttpConnect(ses, localhostW, port, 0); 722 ok(con != NULL, "failed to open a connection %u\n", GetLastError()); 723 724 req = WinHttpOpenRequest(con, verb, path, NULL, NULL, NULL, 0); 725 ok(req != NULL, "failed to open a request %u\n", GetLastError()); 726 727 ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); 728 ok(ret, "failed to send request %u\n", GetLastError()); 729 730 ret = WinHttpReceiveResponse(req, NULL); 731 ok(ret, "failed to receive response %u\n", GetLastError()); 732 733 status = 0xdeadbeef; 734 size = sizeof(status); 735 ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); 736 ok(ret, "failed to query status code %u\n", GetLastError()); 737 ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status); 738 739 count = 0; 740 memset(buffer, 0, sizeof(buffer)); 741 ret = WinHttpReadData(req, buffer, sizeof buffer, &count); 742 ok(ret, "failed to read data %u\n", GetLastError()); 743 ok(count == sizeof page1 - 1, "count was wrong\n"); 744 ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n"); 745 746 WinHttpCloseHandle(req); 747 WinHttpCloseHandle(con); 748 WinHttpCloseHandle(ses); 749 } 750 751 static const struct notification open_socket_request_test[] = 752 { 753 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 754 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 755 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME }, 756 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED }, 757 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER }, 758 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, /* some versions call it twice. why? */ 759 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER }, 760 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 761 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 762 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL } 763 }; 764 765 static const struct notification reuse_socket_request_test[] = 766 { 767 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 768 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED }, 769 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST }, 770 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT }, 771 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }, 772 }; 773 774 static void open_async_request(int port, struct test_request *req, struct info *info, const WCHAR *path, BOOL reuse_connection) 775 { 776 BOOL ret; 777 778 info->index = 0; 779 if (reuse_connection) 780 { 781 info->test = reuse_socket_request_test; 782 info->count = sizeof(reuse_socket_request_test) / sizeof(reuse_socket_request_test[0]); 783 } 784 else 785 { 786 info->test = open_socket_request_test; 787 info->count = sizeof(open_socket_request_test) / sizeof(open_socket_request_test[0]); 788 } 789 790 req->session = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); 791 ok(req->session != NULL, "failed to open session %u\n", GetLastError()); 792 793 WinHttpSetOption( req->session, WINHTTP_OPTION_CONTEXT_VALUE, &info, sizeof(struct info *) ); 794 WinHttpSetStatusCallback( req->session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); 795 796 setup_test( info, winhttp_connect, __LINE__ ); 797 req->connection = WinHttpConnect( req->session, localhostW, port, 0 ); 798 ok(req->connection != NULL, "failed to open a connection %u\n", GetLastError()); 799 800 setup_test( info, winhttp_open_request, __LINE__ ); 801 req->request = WinHttpOpenRequest( req->connection, NULL, path, NULL, NULL, NULL, 0 ); 802 ok(req->request != NULL, "failed to open a request %u\n", GetLastError()); 803 804 setup_test( info, winhttp_send_request, __LINE__ ); 805 ret = WinHttpSendRequest( req->request, NULL, 0, NULL, 0, 0, 0 ); 806 ok(ret, "failed to send request %u\n", GetLastError()); 807 } 808 809 static void open_socket_request(int port, struct test_request *req, struct info *info) 810 { 811 static const WCHAR socketW[] = {'/','s','o','c','k','e','t',0}; 812 813 ResetEvent( server_socket_done ); 814 open_async_request( port, req, info, socketW, FALSE ); 815 WaitForSingleObject( server_socket_available, INFINITE ); 816 } 817 818 static const struct notification server_reply_test[] = 819 { 820 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, 821 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, 822 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL } 823 }; 824 825 static void server_send_reply(struct test_request *req, struct info *info, const char *msg) 826 { 827 BOOL ret; 828 829 send( server_socket, msg, strlen( msg ), 0 ); 830 WaitForSingleObject( info->wait, INFINITE ); 831 832 info->test = server_reply_test; 833 info->count = sizeof(server_reply_test) / sizeof(server_reply_test[0]); 834 info->index = 0; 835 setup_test( info, winhttp_send_request, __LINE__ ); 836 ret = WinHttpReceiveResponse( req->request, NULL ); 837 ok(ret, "failed to receive response %u\n", GetLastError()); 838 839 WaitForSingleObject( info->wait, INFINITE ); 840 end_test( info, __LINE__ ); 841 } 842 843 #define server_read_data(a) _server_read_data(a,__LINE__) 844 static void _server_read_data(const char *expect_prefix, unsigned int line) 845 { 846 char buf[1024]; 847 DWORD size, len; 848 849 size = recv( server_socket, buf, sizeof(buf), 0 ); 850 len = strlen( expect_prefix ); 851 ok_(__FILE__,line)(size > len, "data too short\n"); 852 if (size >= len) 853 { 854 buf[len] = 0; 855 ok_(__FILE__,line)(!strcmp( buf, expect_prefix ), "unexpected data \"%s\"\n", buf); 856 } 857 } 858 859 static const struct notification close_request_test[] = 860 { 861 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 862 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 863 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } 864 }; 865 866 static const struct notification close_allow_connection_close_request_test[] = 867 { 868 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW }, 869 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW }, 870 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 871 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, 872 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } 873 }; 874 875 static void close_request(struct test_request *req, struct info *info, BOOL allow_closing_connection) 876 { 877 BOOL ret; 878 879 if (allow_closing_connection) 880 { 881 info->test = close_allow_connection_close_request_test; 882 info->count = sizeof(close_allow_connection_close_request_test)/sizeof(*close_allow_connection_close_request_test); 883 } 884 else 885 { 886 info->test = close_request_test; 887 info->count = sizeof(close_request_test)/sizeof(*close_request_test); 888 } 889 info->index = 0; 890 setup_test( info, winhttp_close_handle, __LINE__ ); 891 892 ret = WinHttpCloseHandle( req->request ); 893 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); 894 ret = WinHttpCloseHandle( req->connection ); 895 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); 896 ret = WinHttpCloseHandle( req->session ); 897 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError()); 898 899 WaitForSingleObject( info->wait, INFINITE ); 900 end_test( info, __LINE__ ); 901 } 902 903 static const struct notification read_test[] = 904 { 905 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, 906 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, 907 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL } 908 }; 909 910 static const struct notification read_allow_close_test[] = 911 { 912 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW }, 913 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW }, 914 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW }, 915 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW }, 916 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL } 917 }; 918 919 #define read_request_data(a,b,c,d) _read_request_data(a,b,c,d,__LINE__) 920 static void _read_request_data(struct test_request *req, struct info *info, const char *expected_data, BOOL closing_connection, unsigned line) 921 { 922 char buffer[1024]; 923 DWORD read, len; 924 BOOL ret; 925 926 if (closing_connection) 927 { 928 info->test = read_allow_close_test; 929 info->count = sizeof(read_allow_close_test)/sizeof(*read_allow_close_test); 930 } 931 else 932 { 933 info->test = read_test; 934 info->count = sizeof(read_test)/sizeof(*read_test); 935 } 936 info->index = 0; 937 938 setup_test( info, winhttp_read_data, line ); 939 memset(buffer, '?', sizeof(buffer)); 940 read = 0xdeadbeef; 941 ret = WinHttpReadData( req->request, buffer, sizeof(buffer), &read ); 942 ok(ret, "failed to read data %u\n", GetLastError()); 943 944 WaitForSingleObject( info->wait, INFINITE ); 945 946 len = strlen(expected_data); 947 ok(!memcmp(buffer, expected_data, len), "unexpected data\n"); 948 } 949 950 static void test_persistent_connection(int port) 951 { 952 struct test_request req; 953 struct info info; 954 955 static const WCHAR testW[] = {'/','t','e','s','t',0}; 956 957 trace("Testing persistent connection...\n"); 958 959 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL ); 960 961 open_socket_request( port, &req, &info ); 962 server_send_reply( &req, &info, 963 "HTTP/1.1 200 OK\r\n" 964 "Server: winetest\r\n" 965 "Connection: keep-alive\r\n" 966 "Content-Length: 1\r\n" 967 "\r\n" 968 "X" ); 969 read_request_data( &req, &info, "X", FALSE ); 970 close_request( &req, &info, FALSE ); 971 972 /* chunked connection test */ 973 open_async_request( port, &req, &info, testW, TRUE ); 974 server_read_data( "GET /test HTTP/1.1\r\n" ); 975 server_send_reply( &req, &info, 976 "HTTP/1.1 200 OK\r\n" 977 "Server: winetest\r\n" 978 "Transfer-Encoding: chunked\r\n" 979 "Connection: keep-alive\r\n" 980 "\r\n" 981 "9\r\n123456789\r\n" 982 "0\r\n\r\n" ); 983 read_request_data( &req, &info, "123456789", FALSE ); 984 close_request( &req, &info, FALSE ); 985 986 /* HTTP/1.1 connections are persistent by default, no additional header is needed */ 987 open_async_request( port, &req, &info, testW, TRUE ); 988 server_read_data( "GET /test HTTP/1.1\r\n" ); 989 server_send_reply( &req, &info, 990 "HTTP/1.1 200 OK\r\n" 991 "Server: winetest\r\n" 992 "Content-Length: 2\r\n" 993 "\r\n" 994 "xx" ); 995 read_request_data( &req, &info, "xx", FALSE ); 996 close_request( &req, &info, FALSE ); 997 998 open_async_request( port, &req, &info, testW, TRUE ); 999 server_read_data( "GET /test HTTP/1.1\r\n" ); 1000 server_send_reply( &req, &info, 1001 "HTTP/1.1 200 OK\r\n" 1002 "Server: winetest\r\n" 1003 "Content-Length: 2\r\n" 1004 "Connection: close\r\n" 1005 "\r\n" 1006 "yy" ); 1007 close_request( &req, &info, TRUE ); 1008 1009 SetEvent( server_socket_done ); 1010 CloseHandle( info.wait ); 1011 } 1012 1013 START_TEST (notification) 1014 { 1015 static const WCHAR quitW[] = {'/','q','u','i','t',0}; 1016 struct server_info si; 1017 HANDLE thread; 1018 DWORD ret; 1019 1020 test_connection_cache(); 1021 test_redirect(); 1022 test_async(); 1023 1024 si.event = CreateEventW( NULL, 0, 0, NULL ); 1025 si.port = 7533; 1026 1027 thread = CreateThread( NULL, 0, server_thread, (LPVOID)&si, 0, NULL ); 1028 ok(thread != NULL, "failed to create thread %u\n", GetLastError()); 1029 1030 server_socket_available = CreateEventW( NULL, 0, 0, NULL ); 1031 server_socket_done = CreateEventW( NULL, 0, 0, NULL ); 1032 1033 ret = WaitForSingleObject( si.event, 10000 ); 1034 ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError()); 1035 if (ret != WAIT_OBJECT_0) 1036 { 1037 CloseHandle(thread); 1038 return; 1039 } 1040 1041 #ifdef __REACTOS__ 1042 if (!winetest_interactive) 1043 { 1044 skip("Skipping test_persistent_connection due to hang. See ROSTESTS-295.\n"); 1045 } 1046 else 1047 { 1048 test_persistent_connection( si.port ); 1049 } 1050 #else 1051 test_persistent_connection( si.port ); 1052 #endif 1053 1054 /* send the basic request again to shutdown the server thread */ 1055 test_basic_request( si.port, NULL, quitW ); 1056 1057 WaitForSingleObject( thread, 3000 ); 1058 CloseHandle( thread ); 1059 CloseHandle( server_socket_available ); 1060 CloseHandle( server_socket_done ); 1061 } 1062