[WINHTTP_WINETEST] Skip test_persistent_connection due to hang. CORE-14056 ROSTESTS-295
[reactos.git] / modules / rostests / winetests / winhttp / notification.c
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), "unexpeceted 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 return;
1037
1038 #ifdef __REACTOS__
1039 if (!winetest_interactive)
1040 {
1041 skip("Skipping test_persistent_connection due to hang. See ROSTESTS-295.\n");
1042 }
1043 else
1044 #endif
1045 test_persistent_connection( si.port );
1046
1047 /* send the basic request again to shutdown the server thread */
1048 test_basic_request( si.port, NULL, quitW );
1049
1050 WaitForSingleObject( thread, 3000 );
1051 CloseHandle( thread );
1052 CloseHandle( server_socket_available );
1053 CloseHandle( server_socket_done );
1054 }