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
check_notification(HINTERNET handle,DWORD_PTR context,DWORD status,LPVOID buffer,DWORD buflen)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
setup_test(struct info * info,enum api function,unsigned int line)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
end_test(struct info * info,unsigned int line)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
test_connection_cache(void)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 = ARRAY_SIZE( cache_test );
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
test_redirect(void)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 = ARRAY_SIZE( redirect_test );
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
test_async(void)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 = ARRAY_SIZE( async_test );
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
server_thread(LPVOID param)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
test_basic_request(int port,const WCHAR * verb,const WCHAR * path)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
open_async_request(int port,struct test_request * req,struct info * info,const WCHAR * path,BOOL reuse_connection)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 = ARRAY_SIZE( reuse_socket_request_test );
783 }
784 else
785 {
786 info->test = open_socket_request_test;
787 info->count = ARRAY_SIZE( open_socket_request_test );
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
open_socket_request(int port,struct test_request * req,struct info * info)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
server_send_reply(struct test_request * req,struct info * info,const char * msg)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 = ARRAY_SIZE( server_reply_test );
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__)
_server_read_data(const char * expect_prefix,unsigned int 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
close_request(struct test_request * req,struct info * info,BOOL allow_closing_connection)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 = ARRAY_SIZE( close_allow_connection_close_request_test );
883 }
884 else
885 {
886 info->test = close_request_test;
887 info->count = ARRAY_SIZE( 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__)
_read_request_data(struct test_request * req,struct info * info,const char * expected_data,BOOL closing_connection,unsigned 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 len;
924 BOOL ret;
925
926 if (closing_connection)
927 {
928 info->test = read_allow_close_test;
929 info->count = ARRAY_SIZE( read_allow_close_test );
930 }
931 else
932 {
933 info->test = read_test;
934 info->count = ARRAY_SIZE( read_test );
935 }
936 info->index = 0;
937
938 setup_test( info, winhttp_read_data, line );
939 memset(buffer, '?', sizeof(buffer));
940 ret = WinHttpReadData( req->request, buffer, sizeof(buffer), NULL );
941 ok(ret, "failed to read data %u\n", GetLastError());
942
943 WaitForSingleObject( info->wait, INFINITE );
944
945 len = strlen(expected_data);
946 ok(!memcmp(buffer, expected_data, len), "unexpected data\n");
947 }
948
test_persistent_connection(int port)949 static void test_persistent_connection(int port)
950 {
951 struct test_request req;
952 struct info info;
953
954 static const WCHAR testW[] = {'/','t','e','s','t',0};
955
956 trace("Testing persistent connection...\n");
957
958 info.wait = CreateEventW( NULL, FALSE, FALSE, NULL );
959
960 open_socket_request( port, &req, &info );
961 server_send_reply( &req, &info,
962 "HTTP/1.1 200 OK\r\n"
963 "Server: winetest\r\n"
964 "Connection: keep-alive\r\n"
965 "Content-Length: 1\r\n"
966 "\r\n"
967 "X" );
968 read_request_data( &req, &info, "X", FALSE );
969 close_request( &req, &info, FALSE );
970
971 /* chunked connection test */
972 open_async_request( port, &req, &info, testW, TRUE );
973 server_read_data( "GET /test HTTP/1.1\r\n" );
974 server_send_reply( &req, &info,
975 "HTTP/1.1 200 OK\r\n"
976 "Server: winetest\r\n"
977 "Transfer-Encoding: chunked\r\n"
978 "Connection: keep-alive\r\n"
979 "\r\n"
980 "9\r\n123456789\r\n"
981 "0\r\n\r\n" );
982 read_request_data( &req, &info, "123456789", FALSE );
983 close_request( &req, &info, FALSE );
984
985 /* HTTP/1.1 connections are persistent by default, no additional header is needed */
986 open_async_request( port, &req, &info, testW, TRUE );
987 server_read_data( "GET /test HTTP/1.1\r\n" );
988 server_send_reply( &req, &info,
989 "HTTP/1.1 200 OK\r\n"
990 "Server: winetest\r\n"
991 "Content-Length: 2\r\n"
992 "\r\n"
993 "xx" );
994 read_request_data( &req, &info, "xx", FALSE );
995 close_request( &req, &info, FALSE );
996
997 open_async_request( port, &req, &info, testW, TRUE );
998 server_read_data( "GET /test HTTP/1.1\r\n" );
999 server_send_reply( &req, &info,
1000 "HTTP/1.1 200 OK\r\n"
1001 "Server: winetest\r\n"
1002 "Content-Length: 2\r\n"
1003 "Connection: close\r\n"
1004 "\r\n"
1005 "yy" );
1006 close_request( &req, &info, TRUE );
1007
1008 SetEvent( server_socket_done );
1009 CloseHandle( info.wait );
1010 }
1011
START_TEST(notification)1012 START_TEST (notification)
1013 {
1014 static const WCHAR quitW[] = {'/','q','u','i','t',0};
1015 struct server_info si;
1016 HANDLE thread;
1017 DWORD ret;
1018
1019 test_connection_cache();
1020 test_redirect();
1021 test_async();
1022
1023 si.event = CreateEventW( NULL, 0, 0, NULL );
1024 si.port = 7533;
1025
1026 thread = CreateThread( NULL, 0, server_thread, &si, 0, NULL );
1027 ok(thread != NULL, "failed to create thread %u\n", GetLastError());
1028
1029 server_socket_available = CreateEventW( NULL, 0, 0, NULL );
1030 server_socket_done = CreateEventW( NULL, 0, 0, NULL );
1031
1032 ret = WaitForSingleObject( si.event, 10000 );
1033 ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError());
1034 if (ret != WAIT_OBJECT_0)
1035 {
1036 CloseHandle(thread);
1037 return;
1038 }
1039
1040 test_persistent_connection( si.port );
1041
1042 /* send the basic request again to shutdown the server thread */
1043 test_basic_request( si.port, NULL, quitW );
1044
1045 WaitForSingleObject( thread, 3000 );
1046 CloseHandle( thread );
1047 CloseHandle( server_socket_available );
1048 CloseHandle( server_socket_done );
1049 }
1050