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
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
);
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
,
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 */
69 const struct notification
*test
;
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
))
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;
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
;
174 while (info
->index
< info
->count
&& info
->test
[info
->index
].function
!= function
175 && (info
->test
[info
->index
].flags
& (NF_ALLOW
| NF_WINE_ALLOW
)))
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
);
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
) );
207 win_skip("Unload event not supported\n");
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");
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");
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
);
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
);
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());
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");
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");
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__
);
375 WinHttpCloseHandle( req
);
376 WinHttpCloseHandle( con
);
377 WaitForSingleObject( info
.wait
, INFINITE
);
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__
);
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
;
433 struct info info
, *context
= &info
;
435 info
.test
= redirect_test
;
436 info
.count
= ARRAY_SIZE( redirect_test
);
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");
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__
);
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
;
516 info
.test
= async_test
;
517 info
.count
= ARRAY_SIZE( async_test
);
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
) );
528 win_skip("Unload event not supported\n");
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
);
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
);
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__
);
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
;
667 if (!pWinHttpWebSocketCompleteUpgrade
)
669 win_skip( "WinHttpWebSocketCompleteUpgrade not supported\n" );
673 info
.test
= websocket_test
;
674 info
.count
= ARRAY_SIZE( websocket_test
);
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
) );
685 win_skip( "Unload event not supported\n" );
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
);
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__
);
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
);
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__
);
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"
820 static const char page1
[] =
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"
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
;
840 struct sockaddr_in sa
;
843 int last_request
= 0;
845 WSAStartup(MAKEWORD(1,1), &wsaData
);
847 s
= socket(AF_INET
, SOCK_STREAM
, 0);
848 if (s
== INVALID_SOCKET
)
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
));
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);
876 if (buffer
[i
- 2] == '\n' && buffer
[i
] == '\n' &&
877 buffer
[i
- 3] == '\r' && buffer
[i
- 1] == '\r')
880 if (strstr(buffer
, "GET /quit"))
882 send(c
, okmsg
, sizeof okmsg
- 1, 0);
883 send(c
, page1
, sizeof page1
- 1, 0);
886 else if(strstr(buffer
, "GET /socket"))
889 SetEvent(server_socket_available
);
890 WaitForSingleObject(server_socket_done
, INFINITE
);
891 ResetEvent(server_socket_available
);
896 } while (!last_request
);
902 static void test_basic_request(int port
, const WCHAR
*verb
, const WCHAR
*path
)
904 HINTERNET ses
, con
, req
;
906 DWORD count
, status
, size
;
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());
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
);
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
)
970 if (reuse_connection
)
972 info
->test
= reuse_socket_request_test
;
973 info
->count
= ARRAY_SIZE( reuse_socket_request_test
);
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
)
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
);
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
)
1038 size
= recv( server_socket
, buf
, sizeof(buf
), 0 );
1039 len
= strlen( expect_prefix
);
1040 ok_(__FILE__
,line
)(size
> len
, "data too short\n");
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
)
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
);
1075 info
->test
= close_request_test
;
1076 info
->count
= ARRAY_SIZE( close_request_test
);
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
)
1115 if (closing_connection
)
1117 info
->test
= read_allow_close_test
;
1118 info
->count
= ARRAY_SIZE( read_allow_close_test
);
1122 info
->test
= read_test
;
1123 info
->count
= ARRAY_SIZE( read_test
);
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
;
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"
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"
1167 "9\r\n123456789\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"
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"
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
;
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();
1218 si
.event
= CreateEventW( NULL
, 0, 0, NULL
);
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
);
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
);