mf/session: Forward more events to the application.
[wine/zf.git] / dlls / winhttp / tests / notification.c
blob98e4024867f647df40f100668e0ec73216cb8f51
1 /*
2 * test status notifications
4 * Copyright 2008 Hans Leidekker for CodeWeavers
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.
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.
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
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>
29 #include "wine/test.h"
31 static DWORD (WINAPI *pWinHttpWebSocketClose)(HINTERNET,USHORT,void*,DWORD);
32 static HINTERNET (WINAPI *pWinHttpWebSocketCompleteUpgrade)(HINTERNET,DWORD_PTR);
33 static DWORD (WINAPI *pWinHttpWebSocketQueryCloseStatus)(HINTERNET,USHORT*,void*,DWORD,DWORD*);
34 static DWORD (WINAPI *pWinHttpWebSocketReceive)(HINTERNET,void*,DWORD,DWORD*,WINHTTP_WEB_SOCKET_BUFFER_TYPE*);
35 static DWORD (WINAPI *pWinHttpWebSocketSend)(HINTERNET,WINHTTP_WEB_SOCKET_BUFFER_TYPE,void*,DWORD);
36 static DWORD (WINAPI *pWinHttpWebSocketShutdown)(HINTERNET,USHORT,void*,DWORD);
38 enum api
40 winhttp_connect = 1,
41 winhttp_open_request,
42 winhttp_send_request,
43 winhttp_receive_response,
44 winhttp_websocket_complete_upgrade,
45 winhttp_websocket_send,
46 winhttp_websocket_receive,
47 winhttp_websocket_shutdown,
48 winhttp_websocket_close,
49 winhttp_query_data,
50 winhttp_read_data,
51 winhttp_write_data,
52 winhttp_close_handle
55 struct notification
57 enum api function; /* api responsible for notification */
58 unsigned int status; /* status received */
59 DWORD flags; /* a combination of NF_* flags */
62 #define NF_ALLOW 0x0001 /* notification may or may not happen */
63 #define NF_WINE_ALLOW 0x0002 /* wine sends notification when it should not */
64 #define NF_SIGNAL 0x0004 /* signal wait handle when notified */
66 struct info
68 enum api function;
69 const struct notification *test;
70 unsigned int count;
71 unsigned int index;
72 HANDLE wait;
73 unsigned int line;
76 struct test_request
78 HINTERNET session;
79 HINTERNET connection;
80 HINTERNET request;
83 static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen )
85 BOOL status_ok, function_ok;
86 struct info *info = (struct info *)context;
88 if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED)
90 DWORD size = sizeof(struct info *);
91 WinHttpQueryOption( handle, WINHTTP_OPTION_CONTEXT_VALUE, &info, &size );
93 while (info->index < info->count && info->test[info->index].status != status && (info->test[info->index].flags & NF_ALLOW))
94 info->index++;
95 while (info->index < info->count && (info->test[info->index].flags & NF_WINE_ALLOW))
97 todo_wine ok(info->test[info->index].status != status, "unexpected %x notification\n", status);
98 if (info->test[info->index].status == status) break;
99 info->index++;
101 ok(info->index < info->count, "%u: unexpected notification 0x%08x\n", info->line, status);
102 if (info->index >= info->count) return;
104 status_ok = (info->test[info->index].status == status);
105 function_ok = (info->test[info->index].function == info->function);
106 ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[info->index].status, status);
107 ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function);
109 if (status_ok && function_ok && info->test[info->index++].flags & NF_SIGNAL)
111 SetEvent( info->wait );
115 static const struct notification cache_test[] =
117 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
118 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
119 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME },
120 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED },
121 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER },
122 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER },
123 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
124 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
125 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
126 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
127 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
128 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
129 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL },
130 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
131 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW },
132 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW },
133 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
134 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
135 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
136 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
137 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
138 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
139 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
140 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL },
141 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL },
142 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
143 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
144 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW },
145 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW },
146 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW },
147 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW },
148 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
149 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
150 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
151 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
152 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
153 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
154 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL },
155 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
156 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW },
157 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW },
158 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
159 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
160 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
161 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
162 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
163 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
164 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
165 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL },
166 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
169 static void setup_test( struct info *info, enum api function, unsigned int line )
171 if (info->wait) ResetEvent( info->wait );
172 info->function = function;
173 info->line = line;
174 while (info->index < info->count && info->test[info->index].function != function
175 && (info->test[info->index].flags & (NF_ALLOW | NF_WINE_ALLOW)))
176 info->index++;
177 ok_(__FILE__,line)(info->test[info->index].function == function,
178 "unexpected function %u, expected %u. probably some notifications were missing\n",
179 info->test[info->index].function, function);
182 static void end_test( struct info *info, unsigned int line )
184 ok_(__FILE__,line)(info->index == info->count, "some notifications were missing: %x\n",
185 info->test[info->index].status);
188 static void test_connection_cache( void )
190 HANDLE ses, con, req, event;
191 DWORD size, status, err;
192 BOOL ret, unload = TRUE;
193 struct info info, *context = &info;
195 info.test = cache_test;
196 info.count = ARRAY_SIZE( cache_test );
197 info.index = 0;
198 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
200 ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 );
201 ok(ses != NULL, "failed to open session %u\n", GetLastError());
203 event = CreateEventW( NULL, FALSE, FALSE, NULL );
204 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) );
205 if (!ret)
207 win_skip("Unload event not supported\n");
208 unload = FALSE;
211 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
213 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
214 ok(ret, "failed to set context value %u\n", GetLastError());
216 setup_test( &info, winhttp_connect, __LINE__ );
217 con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 );
218 ok(con != NULL, "failed to open a connection %u\n", GetLastError());
220 setup_test( &info, winhttp_open_request, __LINE__ );
221 req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 );
222 ok(req != NULL, "failed to open a request %u\n", GetLastError());
224 setup_test( &info, winhttp_send_request, __LINE__ );
225 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
226 err = GetLastError();
227 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
229 skip("connection failed, skipping\n");
230 goto done;
232 ok(ret, "failed to send request %u\n", GetLastError());
234 setup_test( &info, winhttp_receive_response, __LINE__ );
235 ret = WinHttpReceiveResponse( req, NULL );
236 ok(ret, "failed to receive response %u\n", GetLastError());
238 size = sizeof(status);
239 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
240 ok(ret, "failed unexpectedly %u\n", GetLastError());
241 ok(status == 200, "request failed unexpectedly %u\n", status);
243 ResetEvent( info.wait );
244 setup_test( &info, winhttp_close_handle, __LINE__ );
245 WinHttpCloseHandle( req );
246 WaitForSingleObject( info.wait, INFINITE );
248 setup_test( &info, winhttp_open_request, __LINE__ );
249 req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 );
250 ok(req != NULL, "failed to open a request %u\n", GetLastError());
252 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
253 ok(ret, "failed to set context value %u\n", GetLastError());
255 setup_test( &info, winhttp_send_request, __LINE__ );
256 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
257 err = GetLastError();
258 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
260 skip("connection failed, skipping\n");
261 goto done;
263 ok(ret, "failed to send request %u\n", GetLastError());
265 setup_test( &info, winhttp_receive_response, __LINE__ );
266 ret = WinHttpReceiveResponse( req, NULL );
267 ok(ret, "failed to receive response %u\n", GetLastError());
269 size = sizeof(status);
270 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
271 ok(ret, "failed unexpectedly %u\n", GetLastError());
272 ok(status == 200, "request failed unexpectedly %u\n", status);
274 ResetEvent( info.wait );
275 setup_test( &info, winhttp_close_handle, __LINE__ );
276 WinHttpCloseHandle( req );
277 WinHttpCloseHandle( req );
278 WinHttpCloseHandle( con );
279 WaitForSingleObject( info.wait, INFINITE );
281 if (unload)
283 status = WaitForSingleObject( event, 0 );
284 ok(status == WAIT_TIMEOUT, "got %08x\n", status);
287 setup_test( &info, winhttp_close_handle, __LINE__ );
288 WinHttpCloseHandle( ses );
289 WaitForSingleObject( info.wait, INFINITE );
291 if (unload)
293 status = WaitForSingleObject( event, 100 );
294 ok(status == WAIT_OBJECT_0, "got %08x\n", status);
298 ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 );
299 ok(ses != NULL, "failed to open session %u\n", GetLastError());
301 if (unload)
303 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) );
304 ok(ret, "failed to set unload option\n");
307 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
309 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
310 ok(ret, "failed to set context value %u\n", GetLastError());
312 setup_test( &info, winhttp_connect, __LINE__ );
313 con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 );
314 ok(con != NULL, "failed to open a connection %u\n", GetLastError());
316 setup_test( &info, winhttp_open_request, __LINE__ );
317 req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 );
318 ok(req != NULL, "failed to open a request %u\n", GetLastError());
320 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
321 ok(ret, "failed to set context value %u\n", GetLastError());
323 setup_test( &info, winhttp_send_request, __LINE__ );
324 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
325 err = GetLastError();
326 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
328 skip("connection failed, skipping\n");
329 goto done;
331 ok(ret, "failed to send request %u\n", GetLastError());
333 setup_test( &info, winhttp_receive_response, __LINE__ );
334 ret = WinHttpReceiveResponse( req, NULL );
335 ok(ret, "failed to receive response %u\n", GetLastError());
337 size = sizeof(status);
338 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
339 ok(ret, "failed unexpectedly %u\n", GetLastError());
340 ok(status == 200, "request failed unexpectedly %u\n", status);
342 ResetEvent( info.wait );
343 setup_test( &info, winhttp_close_handle, __LINE__ );
344 WinHttpCloseHandle( req );
345 WaitForSingleObject( info.wait, INFINITE );
347 setup_test( &info, winhttp_open_request, __LINE__ );
348 req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 );
349 ok(req != NULL, "failed to open a request %u\n", GetLastError());
351 ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
352 ok(ret, "failed to set context value %u\n", GetLastError());
354 setup_test( &info, winhttp_send_request, __LINE__ );
355 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
356 err = GetLastError();
357 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
359 skip("connection failed, skipping\n");
360 goto done;
362 ok(ret, "failed to send request %u\n", GetLastError());
364 setup_test( &info, winhttp_receive_response, __LINE__ );
365 ret = WinHttpReceiveResponse( req, NULL );
366 ok(ret, "failed to receive response %u\n", GetLastError());
368 size = sizeof(status);
369 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
370 ok(ret, "failed unexpectedly %u\n", GetLastError());
371 ok(status == 200, "request failed unexpectedly %u\n", status);
373 setup_test( &info, winhttp_close_handle, __LINE__ );
374 done:
375 WinHttpCloseHandle( req );
376 WinHttpCloseHandle( con );
377 WaitForSingleObject( info.wait, INFINITE );
379 if (unload)
381 status = WaitForSingleObject( event, 0 );
382 ok(status == WAIT_TIMEOUT, "got %08x\n", status);
385 setup_test( &info, winhttp_close_handle, __LINE__ );
386 WinHttpCloseHandle( ses );
387 WaitForSingleObject( info.wait, INFINITE );
388 CloseHandle( info.wait );
389 end_test( &info, __LINE__ );
391 if (unload)
393 status = WaitForSingleObject( event, 100 );
394 ok(status == WAIT_OBJECT_0, "got %08x\n", status);
397 CloseHandle( event );
400 static const struct notification redirect_test[] =
402 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
403 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
404 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW },
405 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW },
406 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW },
407 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW },
408 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
409 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
410 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
411 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
412 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT },
413 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_ALLOW },
414 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_ALLOW },
415 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW },
416 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_ALLOW },
417 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
418 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
419 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
420 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
421 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
422 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
423 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
424 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
425 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
428 static void test_redirect( void )
430 HANDLE ses, con, req;
431 DWORD size, status, err;
432 BOOL ret;
433 struct info info, *context = &info;
435 info.test = redirect_test;
436 info.count = ARRAY_SIZE( redirect_test );
437 info.index = 0;
438 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
440 ses = WinHttpOpen( L"winetest", 0, NULL, NULL, 0 );
441 ok(ses != NULL, "failed to open session %u\n", GetLastError());
443 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
445 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
446 ok(ret, "failed to set context value %u\n", GetLastError());
448 setup_test( &info, winhttp_connect, __LINE__ );
449 con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 );
450 ok(con != NULL, "failed to open a connection %u\n", GetLastError());
452 setup_test( &info, winhttp_open_request, __LINE__ );
453 req = WinHttpOpenRequest( con, NULL, L"/tests/redirect", NULL, NULL, NULL, 0 );
454 ok(req != NULL, "failed to open a request %u\n", GetLastError());
456 setup_test( &info, winhttp_send_request, __LINE__ );
457 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
458 err = GetLastError();
459 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
461 skip("connection failed, skipping\n");
462 goto done;
464 ok(ret, "failed to send request %u\n", GetLastError());
466 setup_test( &info, winhttp_receive_response, __LINE__ );
467 ret = WinHttpReceiveResponse( req, NULL );
468 ok(ret, "failed to receive response %u\n", GetLastError());
470 size = sizeof(status);
471 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
472 ok(ret, "failed unexpectedly %u\n", GetLastError());
473 ok(status == 200, "request failed unexpectedly %u\n", status);
475 setup_test( &info, winhttp_close_handle, __LINE__ );
476 done:
477 WinHttpCloseHandle( req );
478 WinHttpCloseHandle( con );
479 WinHttpCloseHandle( ses );
480 WaitForSingleObject( info.wait, INFINITE );
481 CloseHandle( info.wait );
482 end_test( &info, __LINE__ );
485 static const struct notification async_test[] =
487 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
488 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
489 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, NF_WINE_ALLOW },
490 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, NF_WINE_ALLOW },
491 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_WINE_ALLOW },
492 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, NF_WINE_ALLOW },
493 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
494 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
495 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL },
496 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
497 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
498 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL },
499 { winhttp_query_data, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, NF_SIGNAL },
500 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW },
501 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW },
502 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
503 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
504 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
505 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
508 static void test_async( void )
510 HANDLE ses, con, req, event;
511 DWORD size, status, err;
512 BOOL ret, unload = TRUE;
513 struct info info, *context = &info;
514 char buffer[1024];
516 info.test = async_test;
517 info.count = ARRAY_SIZE( async_test );
518 info.index = 0;
519 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
521 ses = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC );
522 ok(ses != NULL, "failed to open session %u\n", GetLastError());
524 event = CreateEventW( NULL, FALSE, FALSE, NULL );
525 ret = WinHttpSetOption( ses, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) );
526 if (!ret)
528 win_skip("Unload event not supported\n");
529 unload = FALSE;
532 SetLastError( 0xdeadbeef );
533 WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
534 err = GetLastError();
535 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
537 SetLastError( 0xdeadbeef );
538 ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
539 err = GetLastError();
540 ok(ret, "failed to set context value %u\n", err);
541 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
543 setup_test( &info, winhttp_connect, __LINE__ );
544 SetLastError( 0xdeadbeef );
545 con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 );
546 err = GetLastError();
547 ok(con != NULL, "failed to open a connection %u\n", err);
548 ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %u\n", err);
550 setup_test( &info, winhttp_open_request, __LINE__ );
551 SetLastError( 0xdeadbeef );
552 req = WinHttpOpenRequest( con, NULL, L"/tests/hello.html", NULL, NULL, NULL, 0 );
553 err = GetLastError();
554 ok(req != NULL, "failed to open a request %u\n", err);
555 ok(err == ERROR_SUCCESS, "got %u\n", err);
557 setup_test( &info, winhttp_send_request, __LINE__ );
558 SetLastError( 0xdeadbeef );
559 ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
560 err = GetLastError();
561 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
563 skip("connection failed, skipping\n");
564 WinHttpCloseHandle( req );
565 WinHttpCloseHandle( con );
566 WinHttpCloseHandle( ses );
567 CloseHandle( info.wait );
568 return;
570 ok(ret, "failed to send request %u\n", err);
571 ok(err == ERROR_SUCCESS, "got %u\n", err);
573 WaitForSingleObject( info.wait, INFINITE );
575 setup_test( &info, winhttp_receive_response, __LINE__ );
576 SetLastError( 0xdeadbeef );
577 ret = WinHttpReceiveResponse( req, NULL );
578 err = GetLastError();
579 ok(ret, "failed to receive response %u\n", err);
580 ok(err == ERROR_SUCCESS, "got %u\n", err);
582 WaitForSingleObject( info.wait, INFINITE );
584 size = sizeof(status);
585 SetLastError( 0xdeadbeef );
586 ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
587 err = GetLastError();
588 ok(ret, "failed unexpectedly %u\n", err);
589 ok(status == 200, "request failed unexpectedly %u\n", status);
590 ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
592 setup_test( &info, winhttp_query_data, __LINE__ );
593 SetLastError( 0xdeadbeef );
594 ret = WinHttpQueryDataAvailable( req, NULL );
595 err = GetLastError();
596 ok(ret, "failed to query data available %u\n", err);
597 ok(err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
599 WaitForSingleObject( info.wait, INFINITE );
601 setup_test( &info, winhttp_read_data, __LINE__ );
602 ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL );
603 ok(ret, "failed to read data %u\n", err);
605 WaitForSingleObject( info.wait, INFINITE );
607 setup_test( &info, winhttp_close_handle, __LINE__ );
608 WinHttpCloseHandle( req );
609 WinHttpCloseHandle( con );
611 if (unload)
613 status = WaitForSingleObject( event, 0 );
614 ok(status == WAIT_TIMEOUT, "got %08x\n", status);
616 WinHttpCloseHandle( ses );
617 WaitForSingleObject( info.wait, INFINITE );
618 end_test( &info, __LINE__ );
620 if (unload)
622 status = WaitForSingleObject( event, 2000 );
623 ok(status == WAIT_OBJECT_0, "got %08x\n", status);
625 CloseHandle( event );
626 CloseHandle( info.wait );
627 end_test( &info, __LINE__ );
630 static const struct notification websocket_test[] =
632 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
633 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
634 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME },
635 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED },
636 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER },
637 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER },
638 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
639 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
640 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL },
641 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE },
642 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
643 { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL },
644 { winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL },
645 { winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_SIGNAL },
646 { winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
647 { winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_SIGNAL },
648 { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL },
649 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
650 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW },
651 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_WINE_ALLOW },
652 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
653 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
654 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
657 static void test_websocket(void)
659 HANDLE session, connection, request, socket, event;
660 WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
661 DWORD size, status, err;
662 BOOL ret, unload = TRUE;
663 struct info info, *context = &info;
664 char buffer[1024];
665 USHORT close_status;
667 if (!pWinHttpWebSocketCompleteUpgrade)
669 win_skip( "WinHttpWebSocketCompleteUpgrade not supported\n" );
670 return;
673 info.test = websocket_test;
674 info.count = ARRAY_SIZE( websocket_test );
675 info.index = 0;
676 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
678 session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC );
679 ok( session != NULL, "got %u\n", GetLastError() );
681 event = CreateEventW( NULL, FALSE, FALSE, NULL );
682 ret = WinHttpSetOption( session, WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT, &event, sizeof(event) );
683 if (!ret)
685 win_skip( "Unload event not supported\n" );
686 unload = FALSE;
689 SetLastError( 0xdeadbeef );
690 WinHttpSetStatusCallback( session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
691 err = GetLastError();
692 ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err );
694 SetLastError( 0xdeadbeef );
695 ret = WinHttpSetOption( session, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(context) );
696 err = GetLastError();
697 ok( ret, "got %u\n", err );
698 ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err);
700 setup_test( &info, winhttp_connect, __LINE__ );
701 SetLastError( 0xdeadbeef );
702 connection = WinHttpConnect( session, L"echo.websocket.org", 0, 0 );
703 err = GetLastError();
704 ok( connection != NULL, "got %u\n", err);
705 ok( err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %u\n", err );
707 setup_test( &info, winhttp_open_request, __LINE__ );
708 SetLastError( 0xdeadbeef );
709 request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, 0 );
710 err = GetLastError();
711 ok( request != NULL, "got %u\n", err );
712 ok( err == ERROR_SUCCESS, "got %u\n", err );
714 ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 );
715 ok( ret, "got %u\n", GetLastError() );
717 setup_test( &info, winhttp_send_request, __LINE__ );
718 SetLastError( 0xdeadbeef );
719 ret = WinHttpSendRequest( request, NULL, 0, NULL, 0, 0, 0 );
720 err = GetLastError();
721 if (!ret && (err == ERROR_WINHTTP_CANNOT_CONNECT || err == ERROR_WINHTTP_TIMEOUT))
723 skip( "connection failed, skipping\n" );
724 WinHttpCloseHandle( request );
725 WinHttpCloseHandle( connection );
726 WinHttpCloseHandle( session );
727 CloseHandle( info.wait );
728 return;
730 ok( ret, "got %u\n", err );
731 ok( err == ERROR_SUCCESS, "got %u\n", err );
732 WaitForSingleObject( info.wait, INFINITE );
734 setup_test( &info, winhttp_receive_response, __LINE__ );
735 SetLastError( 0xdeadbeef );
736 ret = WinHttpReceiveResponse( request, NULL );
737 err = GetLastError();
738 ok( ret, "got %u\n", err );
739 ok( err == ERROR_SUCCESS, "got %u\n", err );
740 WaitForSingleObject( info.wait, INFINITE );
742 size = sizeof(status);
743 SetLastError( 0xdeadbeef );
744 ret = WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
745 err = GetLastError();
746 ok( ret, "failed unexpectedly %u\n", err );
747 ok( status == 101, "got %u\n", status );
748 ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %u\n", err );
750 setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ );
751 SetLastError( 0xdeadbeef );
752 socket = pWinHttpWebSocketCompleteUpgrade( request, (DWORD_PTR)context );
753 err = GetLastError();
754 ok( socket != NULL, "got %u\n", err );
755 ok( err == ERROR_SUCCESS, "got %u\n", err );
756 WaitForSingleObject( info.wait, INFINITE );
758 setup_test( &info, winhttp_websocket_send, __LINE__ );
759 err = pWinHttpWebSocketSend( socket, 0, (void *)"hello", sizeof("hello") );
760 ok( err == ERROR_SUCCESS, "got %u\n", err );
761 WaitForSingleObject( info.wait, INFINITE );
763 setup_test( &info, winhttp_websocket_receive, __LINE__ );
764 buffer[0] = 0;
765 size = 0xdeadbeef;
766 type = 0xdeadbeef;
767 err = pWinHttpWebSocketReceive( socket, buffer, sizeof(buffer), &size, &type );
768 ok( err == ERROR_SUCCESS, "got %u\n", err );
769 WaitForSingleObject( info.wait, INFINITE );
770 ok( size == 0xdeadbeef, "got %u\n", size );
771 ok( type == 0xdeadbeef, "got %u\n", type );
772 ok( buffer[0], "unexpected data\n" );
774 setup_test( &info, winhttp_websocket_shutdown, __LINE__ );
775 err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") );
776 ok( err == ERROR_SUCCESS, "got %u\n", err );
777 WaitForSingleObject( info.wait, INFINITE );
779 setup_test( &info, winhttp_websocket_close, __LINE__ );
780 ret = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") );
781 ok( err == ERROR_SUCCESS, "got %u\n", err );
782 WaitForSingleObject( info.wait, INFINITE );
784 close_status = 0xdead;
785 size = sizeof(buffer) + 1;
786 err = pWinHttpWebSocketQueryCloseStatus( socket, &close_status, buffer, sizeof(buffer), &size );
787 ok( err == ERROR_SUCCESS, "got %u\n", err );
788 ok( close_status == 1000, "got %u\n", close_status );
789 ok( size <= sizeof(buffer), "got %u\n", size );
791 setup_test( &info, winhttp_close_handle, __LINE__ );
792 WinHttpCloseHandle( socket );
793 WinHttpCloseHandle( request );
794 WinHttpCloseHandle( connection );
796 if (unload)
798 status = WaitForSingleObject( event, 0 );
799 ok( status == WAIT_TIMEOUT, "got %08x\n", status );
801 WinHttpCloseHandle( session );
802 WaitForSingleObject( info.wait, INFINITE );
803 end_test( &info, __LINE__ );
805 if (unload)
807 status = WaitForSingleObject( event, 2000 );
808 ok( status == WAIT_OBJECT_0, "got %08x\n", status );
810 CloseHandle( event );
811 CloseHandle( info.wait );
812 end_test( &info, __LINE__ );
815 static const char okmsg[] =
816 "HTTP/1.1 200 OK\r\n"
817 "Server: winetest\r\n"
818 "\r\n";
820 static const char page1[] =
821 "<HTML>\r\n"
822 "<HEAD><TITLE>winhttp test page</TITLE></HEAD>\r\n"
823 "<BODY>The quick brown fox jumped over the lazy dog<P></BODY>\r\n"
824 "</HTML>\r\n\r\n";
826 struct server_info
828 HANDLE event;
829 int port;
832 static int server_socket;
833 static HANDLE server_socket_available, server_socket_done;
835 static DWORD CALLBACK server_thread(LPVOID param)
837 struct server_info *si = param;
838 int r, c = -1, i, on;
839 SOCKET s;
840 struct sockaddr_in sa;
841 char buffer[0x100];
842 WSADATA wsaData;
843 int last_request = 0;
845 WSAStartup(MAKEWORD(1,1), &wsaData);
847 s = socket(AF_INET, SOCK_STREAM, 0);
848 if (s == INVALID_SOCKET)
849 return 1;
851 on = 1;
852 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof on);
854 memset(&sa, 0, sizeof sa);
855 sa.sin_family = AF_INET;
856 sa.sin_port = htons(si->port);
857 sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
859 r = bind(s, (struct sockaddr *)&sa, sizeof(sa));
860 if (r < 0)
861 return 1;
863 listen(s, 0);
864 SetEvent(si->event);
867 if (c == -1) c = accept(s, NULL, NULL);
869 memset(buffer, 0, sizeof buffer);
870 for(i = 0; i < sizeof buffer - 1; i++)
872 r = recv(c, &buffer[i], 1, 0);
873 if (r != 1)
874 break;
875 if (i < 4) continue;
876 if (buffer[i - 2] == '\n' && buffer[i] == '\n' &&
877 buffer[i - 3] == '\r' && buffer[i - 1] == '\r')
878 break;
880 if (strstr(buffer, "GET /quit"))
882 send(c, okmsg, sizeof okmsg - 1, 0);
883 send(c, page1, sizeof page1 - 1, 0);
884 last_request = 1;
886 else if(strstr(buffer, "GET /socket"))
888 server_socket = c;
889 SetEvent(server_socket_available);
890 WaitForSingleObject(server_socket_done, INFINITE);
891 ResetEvent(server_socket_available);
893 shutdown(c, 2);
894 closesocket(c);
895 c = -1;
896 } while (!last_request);
898 closesocket(s);
899 return 0;
902 static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path)
904 HINTERNET ses, con, req;
905 char buffer[0x100];
906 DWORD count, status, size;
907 BOOL ret;
909 ses = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
910 ok(ses != NULL, "failed to open session %u\n", GetLastError());
912 con = WinHttpConnect(ses, L"localhost", port, 0);
913 ok(con != NULL, "failed to open a connection %u\n", GetLastError());
915 req = WinHttpOpenRequest(con, verb, path, NULL, NULL, NULL, 0);
916 ok(req != NULL, "failed to open a request %u\n", GetLastError());
918 ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
919 ok(ret, "failed to send request %u\n", GetLastError());
921 ret = WinHttpReceiveResponse(req, NULL);
922 ok(ret, "failed to receive response %u\n", GetLastError());
924 status = 0xdeadbeef;
925 size = sizeof(status);
926 ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
927 ok(ret, "failed to query status code %u\n", GetLastError());
928 ok(status == HTTP_STATUS_OK, "request failed unexpectedly %u\n", status);
930 count = 0;
931 memset(buffer, 0, sizeof(buffer));
932 ret = WinHttpReadData(req, buffer, sizeof buffer, &count);
933 ok(ret, "failed to read data %u\n", GetLastError());
934 ok(count == sizeof page1 - 1, "count was wrong\n");
935 ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n");
937 WinHttpCloseHandle(req);
938 WinHttpCloseHandle(con);
939 WinHttpCloseHandle(ses);
942 static const struct notification open_socket_request_test[] =
944 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
945 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
946 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME },
947 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED },
948 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER },
949 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, NF_ALLOW }, /* some versions call it twice. why? */
950 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER },
951 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
952 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
953 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL }
956 static const struct notification reuse_socket_request_test[] =
958 { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
959 { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED },
960 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST },
961 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT },
962 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, NF_SIGNAL },
965 static void open_async_request(int port, struct test_request *req, struct info *info, const WCHAR *path, BOOL reuse_connection)
967 BOOL ret;
969 info->index = 0;
970 if (reuse_connection)
972 info->test = reuse_socket_request_test;
973 info->count = ARRAY_SIZE( reuse_socket_request_test );
975 else
977 info->test = open_socket_request_test;
978 info->count = ARRAY_SIZE( open_socket_request_test );
981 req->session = WinHttpOpen( L"winetest", 0, NULL, NULL, WINHTTP_FLAG_ASYNC );
982 ok(req->session != NULL, "failed to open session %u\n", GetLastError());
984 WinHttpSetOption( req->session, WINHTTP_OPTION_CONTEXT_VALUE, &info, sizeof(struct info *) );
985 WinHttpSetStatusCallback( req->session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
987 setup_test( info, winhttp_connect, __LINE__ );
988 req->connection = WinHttpConnect( req->session, L"localhost", port, 0 );
989 ok(req->connection != NULL, "failed to open a connection %u\n", GetLastError());
991 setup_test( info, winhttp_open_request, __LINE__ );
992 req->request = WinHttpOpenRequest( req->connection, NULL, path, NULL, NULL, NULL, 0 );
993 ok(req->request != NULL, "failed to open a request %u\n", GetLastError());
995 setup_test( info, winhttp_send_request, __LINE__ );
996 ret = WinHttpSendRequest( req->request, NULL, 0, NULL, 0, 0, 0 );
997 ok(ret, "failed to send request %u\n", GetLastError());
1000 static void open_socket_request(int port, struct test_request *req, struct info *info)
1002 ResetEvent( server_socket_done );
1003 open_async_request( port, req, info, L"/socket", FALSE );
1004 WaitForSingleObject( server_socket_available, INFINITE );
1007 static const struct notification server_reply_test[] =
1009 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW },
1010 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW },
1011 { winhttp_send_request, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL }
1014 static void server_send_reply(struct test_request *req, struct info *info, const char *msg)
1016 BOOL ret;
1018 send( server_socket, msg, strlen( msg ), 0 );
1019 WaitForSingleObject( info->wait, INFINITE );
1021 info->test = server_reply_test;
1022 info->count = ARRAY_SIZE( server_reply_test );
1023 info->index = 0;
1024 setup_test( info, winhttp_send_request, __LINE__ );
1025 ret = WinHttpReceiveResponse( req->request, NULL );
1026 ok(ret, "failed to receive response %u\n", GetLastError());
1028 WaitForSingleObject( info->wait, INFINITE );
1029 end_test( info, __LINE__ );
1032 #define server_read_data(a) _server_read_data(a,__LINE__)
1033 static void _server_read_data(const char *expect_prefix, unsigned int line)
1035 char buf[1024];
1036 DWORD size, len;
1038 size = recv( server_socket, buf, sizeof(buf), 0 );
1039 len = strlen( expect_prefix );
1040 ok_(__FILE__,line)(size > len, "data too short\n");
1041 if (size >= len)
1043 buf[len] = 0;
1044 ok_(__FILE__,line)(!strcmp( buf, expect_prefix ), "unexpected data \"%s\"\n", buf);
1048 static const struct notification close_request_test[] =
1050 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
1051 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
1052 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
1055 static const struct notification close_allow_connection_close_request_test[] =
1057 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW },
1058 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW },
1059 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
1060 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING },
1061 { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL }
1064 static void close_request(struct test_request *req, struct info *info, BOOL allow_closing_connection)
1066 BOOL ret;
1068 if (allow_closing_connection)
1070 info->test = close_allow_connection_close_request_test;
1071 info->count = ARRAY_SIZE( close_allow_connection_close_request_test );
1073 else
1075 info->test = close_request_test;
1076 info->count = ARRAY_SIZE( close_request_test );
1078 info->index = 0;
1079 setup_test( info, winhttp_close_handle, __LINE__ );
1081 ret = WinHttpCloseHandle( req->request );
1082 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError());
1083 ret = WinHttpCloseHandle( req->connection );
1084 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError());
1085 ret = WinHttpCloseHandle( req->session );
1086 ok(ret, "WinHttpCloseHandle failed: %u\n", GetLastError());
1088 WaitForSingleObject( info->wait, INFINITE );
1089 end_test( info, __LINE__ );
1092 static const struct notification read_test[] =
1094 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW },
1095 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW },
1096 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }
1099 static const struct notification read_allow_close_test[] =
1101 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NF_ALLOW },
1102 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, NF_ALLOW },
1103 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_ALLOW },
1104 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, NF_ALLOW },
1105 { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL }
1108 #define read_request_data(a,b,c,d) _read_request_data(a,b,c,d,__LINE__)
1109 static void _read_request_data(struct test_request *req, struct info *info, const char *expected_data, BOOL closing_connection, unsigned line)
1111 char buffer[1024];
1112 DWORD len;
1113 BOOL ret;
1115 if (closing_connection)
1117 info->test = read_allow_close_test;
1118 info->count = ARRAY_SIZE( read_allow_close_test );
1120 else
1122 info->test = read_test;
1123 info->count = ARRAY_SIZE( read_test );
1125 info->index = 0;
1127 setup_test( info, winhttp_read_data, line );
1128 memset(buffer, '?', sizeof(buffer));
1129 ret = WinHttpReadData( req->request, buffer, sizeof(buffer), NULL );
1130 ok(ret, "failed to read data %u\n", GetLastError());
1132 WaitForSingleObject( info->wait, INFINITE );
1134 len = strlen(expected_data);
1135 ok(!memcmp(buffer, expected_data, len), "unexpected data\n");
1138 static void test_persistent_connection(int port)
1140 struct test_request req;
1141 struct info info;
1143 trace("Testing persistent connection...\n");
1145 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
1147 open_socket_request( port, &req, &info );
1148 server_send_reply( &req, &info,
1149 "HTTP/1.1 200 OK\r\n"
1150 "Server: winetest\r\n"
1151 "Connection: keep-alive\r\n"
1152 "Content-Length: 1\r\n"
1153 "\r\n"
1154 "X" );
1155 read_request_data( &req, &info, "X", FALSE );
1156 close_request( &req, &info, FALSE );
1158 /* chunked connection test */
1159 open_async_request( port, &req, &info, L"/test", TRUE );
1160 server_read_data( "GET /test HTTP/1.1\r\n" );
1161 server_send_reply( &req, &info,
1162 "HTTP/1.1 200 OK\r\n"
1163 "Server: winetest\r\n"
1164 "Transfer-Encoding: chunked\r\n"
1165 "Connection: keep-alive\r\n"
1166 "\r\n"
1167 "9\r\n123456789\r\n"
1168 "0\r\n\r\n" );
1169 read_request_data( &req, &info, "123456789", FALSE );
1170 close_request( &req, &info, FALSE );
1172 /* HTTP/1.1 connections are persistent by default, no additional header is needed */
1173 open_async_request( port, &req, &info, L"/test", TRUE );
1174 server_read_data( "GET /test HTTP/1.1\r\n" );
1175 server_send_reply( &req, &info,
1176 "HTTP/1.1 200 OK\r\n"
1177 "Server: winetest\r\n"
1178 "Content-Length: 2\r\n"
1179 "\r\n"
1180 "xx" );
1181 read_request_data( &req, &info, "xx", FALSE );
1182 close_request( &req, &info, FALSE );
1184 open_async_request( port, &req, &info, L"/test", TRUE );
1185 server_read_data( "GET /test HTTP/1.1\r\n" );
1186 server_send_reply( &req, &info,
1187 "HTTP/1.1 200 OK\r\n"
1188 "Server: winetest\r\n"
1189 "Content-Length: 2\r\n"
1190 "Connection: close\r\n"
1191 "\r\n"
1192 "yy" );
1193 close_request( &req, &info, TRUE );
1195 SetEvent( server_socket_done );
1196 CloseHandle( info.wait );
1199 START_TEST (notification)
1201 HMODULE mod = GetModuleHandleA( "winhttp.dll" );
1202 struct server_info si;
1203 HANDLE thread;
1204 DWORD ret;
1206 pWinHttpWebSocketClose = (void *)GetProcAddress( mod, "WinHttpWebSocketClose" );
1207 pWinHttpWebSocketCompleteUpgrade = (void *)GetProcAddress( mod, "WinHttpWebSocketCompleteUpgrade" );
1208 pWinHttpWebSocketQueryCloseStatus = (void *)GetProcAddress( mod, "WinHttpWebSocketQueryCloseStatus" );
1209 pWinHttpWebSocketReceive = (void *)GetProcAddress( mod, "WinHttpWebSocketReceive" );
1210 pWinHttpWebSocketSend = (void *)GetProcAddress( mod, "WinHttpWebSocketSend" );
1211 pWinHttpWebSocketShutdown = (void *)GetProcAddress( mod, "WinHttpWebSocketShutdown" );
1213 test_connection_cache();
1214 test_redirect();
1215 test_async();
1216 test_websocket();
1218 si.event = CreateEventW( NULL, 0, 0, NULL );
1219 si.port = 7533;
1221 thread = CreateThread( NULL, 0, server_thread, &si, 0, NULL );
1222 ok(thread != NULL, "failed to create thread %u\n", GetLastError());
1224 server_socket_available = CreateEventW( NULL, 0, 0, NULL );
1225 server_socket_done = CreateEventW( NULL, 0, 0, NULL );
1227 ret = WaitForSingleObject( si.event, 10000 );
1228 ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError());
1229 if (ret != WAIT_OBJECT_0)
1231 CloseHandle(thread);
1232 return;
1235 test_persistent_connection( si.port );
1237 /* send the basic request again to shutdown the server thread */
1238 test_basic_request( si.port, NULL, L"/quit" );
1240 WaitForSingleObject( thread, 3000 );
1241 CloseHandle( thread );
1242 CloseHandle( server_socket_available );
1243 CloseHandle( server_socket_done );