winhttp: Add a partial implementation of WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT.
[wine] / dlls / winhttp / tests / winhttp.c
1 /*
2  * WinHTTP - tests
3  *
4  * Copyright 2008 Google (Zac Brown)
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 <winhttp.h>
26 #include <wincrypt.h>
27 #include <winreg.h>
28 #include <winsock.h>
29
30 #include "wine/test.h"
31
32 static const WCHAR test_useragent[] =
33     {'W','i','n','e',' ','R','e','g','r','e','s','s','i','o','n',' ','T','e','s','t',0};
34 static const WCHAR test_server[] = {'w','i','n','e','h','q','.','o','r','g',0};
35 static const WCHAR localhostW[] = {'l','o','c','a','l','h','o','s','t',0};
36
37 static void test_QueryOption(void)
38 {
39     BOOL ret;
40     HINTERNET session, request, connection;
41     DWORD feature, size;
42
43     SetLastError(0xdeadbeef);
44     session = WinHttpOpen(test_useragent, 0, 0, 0, 0);
45     ok(session != NULL, "WinHttpOpen failed to open session, error %u\n", GetLastError());
46
47     SetLastError(0xdeadbeef);
48     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, NULL);
49     ok(!ret, "should fail to set redirect policy %u\n", GetLastError());
50     ok(GetLastError() == ERROR_INVALID_PARAMETER,
51        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
52
53     size = 0xdeadbeef;
54     SetLastError(0xdeadbeef);
55     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, &size);
56     ok(!ret, "should fail to query option\n");
57     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
58        "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
59     ok(size == 4, "expected 4, got %u\n", size);
60
61     feature = 0xdeadbeef;
62     size = sizeof(feature) - 1;
63     SetLastError(0xdeadbeef);
64     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size);
65     ok(!ret, "should fail to query option\n");
66     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
67        "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
68     ok(size == 4, "expected 4, got %u\n", size);
69
70     feature = 0xdeadbeef;
71     size = sizeof(feature) + 1;
72     SetLastError(0xdeadbeef);
73     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size);
74     ok(ret, "failed to query option %u\n", GetLastError());
75     ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %u\n", size);
76     ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP,
77        "expected WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, got %#x\n", feature);
78
79     SetLastError(0xdeadbeef);
80     ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, sizeof(feature));
81     ok(!ret, "should fail to set redirect policy %u\n", GetLastError());
82     ok(GetLastError() == ERROR_INVALID_PARAMETER,
83        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
84
85     feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
86     SetLastError(0xdeadbeef);
87     ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) - 1);
88     ok(!ret, "should fail to set redirect policy %u\n", GetLastError());
89     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
90        "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
91
92     feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
93     SetLastError(0xdeadbeef);
94     ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) + 1);
95     ok(!ret, "should fail to set redirect policy %u\n", GetLastError());
96     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
97        "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
98
99     feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
100     SetLastError(0xdeadbeef);
101     ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature));
102     ok(ret, "failed to set redirect policy %u\n", GetLastError());
103
104     feature = 0xdeadbeef;
105     size = sizeof(feature);
106     SetLastError(0xdeadbeef);
107     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size);
108     ok(ret, "failed to query option %u\n", GetLastError());
109     ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS,
110        "expected WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, got %#x\n", feature);
111
112     feature = WINHTTP_DISABLE_COOKIES;
113     SetLastError(0xdeadbeef);
114     ret = WinHttpSetOption(session, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature));
115     ok(!ret, "should fail to set disable feature for a session\n");
116     ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
117        "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError());
118
119     SetLastError(0xdeadbeef);
120     connection = WinHttpConnect(session, test_server, INTERNET_DEFAULT_HTTP_PORT, 0);
121     ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u\n", GetLastError());
122
123     feature = WINHTTP_DISABLE_COOKIES;
124     SetLastError(0xdeadbeef);
125     ret = WinHttpSetOption(connection, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature));
126     ok(!ret, "should fail to set disable feature for a connection\n");
127     ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
128        "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError());
129
130     SetLastError(0xdeadbeef);
131     request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER,
132                                  WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
133     if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED)
134     {
135         skip("Network unreachable, skipping the test\n");
136         goto done;
137     }
138
139     feature = 0xdeadbeef;
140     size = sizeof(feature);
141     SetLastError(0xdeadbeef);
142     ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, &size);
143     ok(!ret, "should fail to query disable feature for a request\n");
144     ok(GetLastError() == ERROR_INVALID_PARAMETER,
145        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
146
147     feature = 0;
148     size = sizeof(feature);
149     SetLastError(0xdeadbeef);
150     ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature));
151     ok(ret, "failed to set feature %u\n", GetLastError());
152
153     feature = 0xffffffff;
154     size = sizeof(feature);
155     SetLastError(0xdeadbeef);
156     ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature));
157     ok(ret, "failed to set feature %u\n", GetLastError());
158
159     feature = WINHTTP_DISABLE_COOKIES;
160     size = sizeof(feature);
161     SetLastError(0xdeadbeef);
162     ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature));
163     ok(ret, "failed to set feature %u\n", GetLastError());
164
165     size = 0;
166     SetLastError(0xdeadbeef);
167     ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, NULL, &size);
168     ok(!ret, "should fail to query disable feature for a request\n");
169     ok(GetLastError() == ERROR_INVALID_PARAMETER,
170        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
171
172     SetLastError(0xdeadbeef);
173     ret = WinHttpCloseHandle(request);
174     ok(ret, "WinHttpCloseHandle failed on closing request: %u\n", GetLastError());
175
176 done:
177     SetLastError(0xdeadbeef);
178     ret = WinHttpCloseHandle(connection);
179     ok(ret, "WinHttpCloseHandle failed on closing connection: %u\n", GetLastError());
180     SetLastError(0xdeadbeef);
181     ret = WinHttpCloseHandle(session);
182     ok(ret, "WinHttpCloseHandle failed on closing session: %u\n", GetLastError());
183 }
184
185 static void test_OpenRequest (void)
186 {
187     BOOL ret;
188     HINTERNET session, request, connection;
189
190     session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
191         WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
192     ok(session != NULL, "WinHttpOpen failed to open session.\n");
193
194     /* Test with a bad server name */
195     SetLastError(0xdeadbeef);
196     connection = WinHttpConnect(session, NULL, INTERNET_DEFAULT_HTTP_PORT, 0);
197     ok (connection == NULL, "WinHttpConnect succeeded in opening connection to NULL server argument.\n");
198     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError());
199
200     /* Test with a valid server name */
201     connection = WinHttpConnect (session, test_server, INTERNET_DEFAULT_HTTP_PORT, 0);
202     ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError());
203
204     request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER,
205         WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
206     if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED)
207     {
208         skip("Network unreachable, skipping.\n");
209         goto done;
210     }
211     ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError());
212
213     ret = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0);
214     if (!ret && GetLastError() == ERROR_WINHTTP_CANNOT_CONNECT)
215     {
216         skip("Connection failed, skipping.\n");
217         goto done;
218     }
219     ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError());
220     ret = WinHttpCloseHandle(request);
221     ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret);
222
223  done:
224     ret = WinHttpCloseHandle(connection);
225     ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret);
226     ret = WinHttpCloseHandle(session);
227     ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret);
228
229 }
230
231 static void test_empty_headers_param(void)
232 {
233     static const WCHAR winehq[] = {'w','i','n','e','h','q','.','o','r','g',0};
234     static const WCHAR empty[]  = {0};
235     HINTERNET ses, con, req;
236     BOOL ret;
237
238     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
239     ok(ses != NULL, "failed to open session %u\n", GetLastError());
240
241     con = WinHttpConnect(ses, winehq, 80, 0);
242     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
243
244     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
245     ok(req != NULL, "failed to open a request %u\n", GetLastError());
246
247     ret = WinHttpSendRequest(req, empty, 0, NULL, 0, 0, 0);
248     ok(ret, "failed to send request %u\n", GetLastError());
249
250     WinHttpCloseHandle(req);
251     WinHttpCloseHandle(con);
252     WinHttpCloseHandle(ses);
253 }
254
255 static void test_SendRequest (void)
256 {
257     HINTERNET session, request, connection;
258     DWORD header_len, optional_len, total_len, bytes_rw, size;
259     DWORD_PTR context;
260     BOOL ret;
261     CHAR buffer[256];
262     int i;
263
264     static const WCHAR test_site[] = {'c','r','o','s','s','o','v','e','r','.',
265                                 'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
266     static const WCHAR content_type[] =
267         {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t','i','o','n',
268          '/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d',0};
269     static const WCHAR test_file[] = {'/','p','o','s','t','t','e','s','t','.','p','h','p',0};
270     static const WCHAR test_verb[] = {'P','O','S','T',0};
271     static CHAR post_data[] = "mode=Test";
272     static CHAR test_post[] = "mode => Test\\0\n";
273
274     header_len = -1L;
275     total_len = optional_len = sizeof(post_data);
276     memset(buffer, 0xff, sizeof(buffer));
277
278     session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
279         WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
280     ok(session != NULL, "WinHttpOpen failed to open session.\n");
281
282     connection = WinHttpConnect (session, test_site, INTERNET_DEFAULT_HTTP_PORT, 0);
283     ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError());
284
285     request = WinHttpOpenRequest(connection, test_verb, test_file, NULL, WINHTTP_NO_REFERER,
286         WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE);
287     if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED)
288     {
289         skip("Network unreachable, skipping.\n");
290         goto done;
291     }
292     ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError());
293     if (!request) goto done;
294
295     context = 0xdeadbeef;
296     ret = WinHttpSetOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(context));
297     ok(ret, "WinHttpSetOption failed: %u\n", GetLastError());
298
299     context++;
300     ret = WinHttpSendRequest(request, content_type, header_len, post_data, optional_len, total_len, context);
301     ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError());
302
303     context = 0;
304     size = sizeof(context);
305     ret = WinHttpQueryOption(request, WINHTTP_OPTION_CONTEXT_VALUE, &context, &size);
306     ok(ret, "WinHttpQueryOption failed: %u\n", GetLastError());
307     ok(context == 0xdeadbef0, "expected 0xdeadbef0, got %lx\n", context);
308
309     for (i = 3; post_data[i]; i++)
310     {
311         bytes_rw = -1;
312         ret = WinHttpWriteData(request, &post_data[i], 1, &bytes_rw);
313         if (ret)
314           ok(bytes_rw == 1, "WinHttpWriteData failed, wrote %u bytes instead of 1 byte.\n", bytes_rw);
315         else /* Since we already passed all optional data in WinHttpSendRequest Win7 fails our WinHttpWriteData call */
316         {
317           ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER got %u.\n", GetLastError());
318           ok(bytes_rw == -1, "Expected bytes_rw to remain unchanged.\n");
319         }
320     }
321
322     ret = WinHttpReceiveResponse(request, NULL);
323     ok(ret == TRUE, "WinHttpReceiveResponse failed: %u.\n", GetLastError());
324
325     bytes_rw = -1;
326     ret = WinHttpReadData(request, buffer, sizeof(buffer) - 1, &bytes_rw);
327     ok(ret == TRUE, "WinHttpReadData failed: %u.\n", GetLastError());
328
329     ok(bytes_rw == strlen(test_post), "Read %u bytes instead of %d.\n", bytes_rw, lstrlen(test_post));
330     ok(strncmp(buffer, test_post, bytes_rw) == 0, "Data read did not match, got '%s'.\n", buffer);
331
332     ret = WinHttpCloseHandle(request);
333     ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret);
334  done:
335     ret = WinHttpCloseHandle(connection);
336     ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret);
337     ret = WinHttpCloseHandle(session);
338     ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret);
339 }
340
341 static void test_WinHttpTimeFromSystemTime(void)
342 {
343     BOOL ret;
344     static const SYSTEMTIME time = {2008, 7, 1, 28, 10, 5, 52, 0};
345     static const WCHAR expected_string[] =
346         {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ',
347          '1','0',':','0','5',':','5','2',' ','G','M','T',0};
348     WCHAR time_string[WINHTTP_TIME_FORMAT_BUFSIZE+1];
349
350     ret = WinHttpTimeFromSystemTime(&time, time_string);
351     ok(ret == TRUE, "WinHttpTimeFromSystemTime failed: %u\n", GetLastError());
352     ok(memcmp(time_string, expected_string, sizeof(expected_string)) == 0,
353         "Time string returned did not match expected time string.\n");
354 }
355
356 static void test_WinHttpTimeToSystemTime(void)
357 {
358     BOOL ret;
359     SYSTEMTIME time;
360     static const SYSTEMTIME expected_time = {2008, 7, 1, 28, 10, 5, 52, 0};
361     static const WCHAR time_string1[] =
362         {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ',
363          +          '1','0',':','0','5',':','5','2',' ','G','M','T','\n',0};
364     static const WCHAR time_string2[] =
365         {' ','m','o','n',' ','2','8',' ','j','u','l',' ','2','0','0','8',' ',
366          '1','0',' ','0','5',' ','5','2','\n',0};
367
368     ret = WinHttpTimeToSystemTime(time_string1, &time);
369     ok(ret == TRUE, "WinHttpTimeToSystemTime failed: %u\n", GetLastError());
370     ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0,
371         "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n");
372
373     ret = WinHttpTimeToSystemTime(time_string2, &time);
374     ok(ret == TRUE, "WinHttpTimeToSystemTime failed: %u\n", GetLastError());
375     ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0,
376         "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n");
377 }
378
379 static void test_WinHttpAddHeaders(void)
380 {
381     HINTERNET session, request, connection;
382     BOOL ret, reverse;
383     WCHAR buffer[MAX_PATH];
384     WCHAR check_buffer[MAX_PATH];
385     DWORD index, len, oldlen;
386
387     static const WCHAR test_site[] = {'c','r','o','s','s','o','v','e','r','.',
388                                 'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
389     static const WCHAR test_file[] = {'/','p','o','s','t','t','e','s','t','.','p','h','p',0};
390     static const WCHAR test_verb[] = {'P','O','S','T',0};
391
392     static const WCHAR test_header_begin[] =
393         {'P','O','S','T',' ','/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'};
394     static const WCHAR full_path_test_header_begin[] =
395         {'P','O','S','T',' ','h','t','t','p',':','/','/','c','r','o','s','s','o','v','e','r','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',':','8','0','/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'};
396     static const WCHAR test_header_end[] = {'\r','\n','\r','\n',0};
397     static const WCHAR test_header_name[] = {'W','a','r','n','i','n','g',0};
398
399     static const WCHAR test_flag_coalesce[] = {'t','e','s','t','2',',',' ','t','e','s','t','4',0};
400     static const WCHAR test_flag_coalesce_reverse[] = {'t','e','s','t','3',',',' ','t','e','s','t','4',0};
401     static const WCHAR test_flag_coalesce_comma[] =
402         {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',0};
403     static const WCHAR test_flag_coalesce_comma_reverse[] =
404         {'t','e','s','t','3',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',0};
405     static const WCHAR test_flag_coalesce_semicolon[] =
406         {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0};
407     static const WCHAR test_flag_coalesce_semicolon_reverse[] =
408         {'t','e','s','t','3',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0};
409
410     static const WCHAR field[] = {'f','i','e','l','d',0};
411     static const WCHAR value[] = {'v','a','l','u','e',' ',0};
412     static const WCHAR value_nospace[] = {'v','a','l','u','e',0};
413
414     static const WCHAR test_headers[][14] =
415         {
416             {'W','a','r','n','i','n','g',':','t','e','s','t','1',0},
417             {'W','a','r','n','i','n','g',':','t','e','s','t','2',0},
418             {'W','a','r','n','i','n','g',':','t','e','s','t','3',0},
419             {'W','a','r','n','i','n','g',':','t','e','s','t','4',0},
420             {'W','a','r','n','i','n','g',':','t','e','s','t','5',0},
421             {'W','a','r','n','i','n','g',':','t','e','s','t','6',0},
422             {'W','a','r','n','i','n','g',':','t','e','s','t','7',0},
423             {0},
424             {':',0},
425             {'a',':',0},
426             {':','b',0},
427             {'c','d',0},
428             {' ','e',' ',':','f',0},
429             {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0}
430         };
431     static const WCHAR test_indices[][6] =
432         {
433             {'t','e','s','t','1',0},
434             {'t','e','s','t','2',0},
435             {'t','e','s','t','3',0},
436             {'t','e','s','t','4',0}
437         };
438
439     session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
440         WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
441     ok(session != NULL, "WinHttpOpen failed to open session.\n");
442
443     connection = WinHttpConnect (session, test_site, INTERNET_DEFAULT_HTTP_PORT, 0);
444     ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError());
445
446     request = WinHttpOpenRequest(connection, test_verb, test_file, NULL, WINHTTP_NO_REFERER,
447         WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
448     if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED)
449     {
450         skip("Network unreachable, skipping.\n");
451         goto done;
452     }
453     ok(request != NULL, "WinHttpOpenRequest failed to open a request, error: %u.\n", GetLastError());
454
455     index = 0;
456     len = sizeof(buffer);
457     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
458         test_header_name, buffer, &len, &index);
459     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, found 'Warning' header.\n");
460     ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD);
461     ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError());
462
463     index = 0;
464     len = sizeof(buffer);
465     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
466         test_header_name, buffer, &len, &index);
467     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
468     ok(index == 1, "WinHttpQueryHeaders failed: header index not incremented\n");
469     ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders failed: incorrect string returned\n");
470     ok(len == 5*sizeof(WCHAR), "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %d\n", len);
471
472     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
473         test_header_name, buffer, &len, &index);
474     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, second index should not exist.\n");
475
476     /* Try to fetch the header info with a buffer that's big enough to fit the
477      * string but not the NULL terminator.
478      */
479     index = 0;
480     len = 5*sizeof(WCHAR);
481     memset(check_buffer, 0xab, sizeof(check_buffer));
482     memcpy(buffer, check_buffer, sizeof(buffer));
483     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
484         test_header_name, buffer, &len, &index);
485     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded with a buffer that's too small.\n");
486     ok(memcmp(buffer, check_buffer, sizeof(buffer)) == 0,
487             "WinHttpQueryHeaders failed, modified the buffer when it should not have.\n");
488     ok(len == 6*sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %d\n", len);
489
490     /* Try with a NULL buffer */
491     index = 0;
492     len = sizeof(buffer);
493     SetLastError(0xdeadbeef);
494     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
495         test_header_name, NULL, &len, &index);
496     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n");
497     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
498     ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len);
499     ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n");
500
501     /* Try with a NULL buffer and a length that's too small */
502     index = 0;
503     len = 10;
504     SetLastError(0xdeadbeef);
505     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
506         test_header_name, NULL, &len, &index);
507     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n");
508     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
509         "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICENT_BUFFER, go %u\n", GetLastError());
510     ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len);
511     ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n");
512
513     index = 0;
514     len = 0;
515     SetLastError(0xdeadbeef);
516     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
517         test_header_name, NULL, &len, &index);
518     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n");
519     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
520         "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
521     ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len);
522     ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n");
523
524     /* valid query */
525     oldlen = len;
526     index = 0;
527     len = sizeof(buffer);
528     memset(buffer, 0xff, sizeof(buffer));
529     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
530         test_header_name, buffer, &len, &index);
531     ok(ret == TRUE, "WinHttpQueryHeaders failed: got %d\n", ret);
532     ok(len + sizeof(WCHAR) <= oldlen, "WinHttpQueryHeaders resulting length longer than advertized.\n");
533     ok((len < sizeof(buffer) - sizeof(WCHAR)) && buffer[len / sizeof(WCHAR)] == 0, "WinHttpQueryHeaders did not append NULL terminator\n");
534     ok(len == lstrlenW(buffer) * sizeof(WCHAR), "WinHttpQueryHeaders returned incorrect length.\n");
535     ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0 ||
536         memcmp(buffer, full_path_test_header_begin, sizeof(full_path_test_header_begin)) == 0,
537         "WinHttpQueryHeaders returned invalid beginning of header string.\n");
538     ok(memcmp(buffer + lstrlenW(buffer) - 4, test_header_end, sizeof(test_header_end)) == 0,
539         "WinHttpQueryHeaders returned invalid end of header string.\n");
540     ok(index == 0, "WinHttpQueryHeaders incremented header index.\n");
541
542     index = 0;
543     len = 0;
544     SetLastError(0xdeadbeef);
545     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
546         test_header_name, NULL, &len, &index);
547     ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n");
548     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
549         "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
550     ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len);
551     ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n");
552
553     oldlen = len;
554     index = 0;
555     len = sizeof(buffer);
556     memset(buffer, 0xff, sizeof(buffer));
557     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
558         test_header_name, buffer, &len, &index);
559     ok(ret == TRUE, "WinHttpQueryHeaders failed %u\n", GetLastError());
560     ok(len + sizeof(WCHAR) <= oldlen, "resulting length longer than advertized\n");
561     ok((len < sizeof(buffer) - sizeof(WCHAR)) && !buffer[len / sizeof(WCHAR)] && !buffer[len / sizeof(WCHAR) - 1],
562         "no double NULL terminator\n");
563     ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0 ||
564         memcmp(buffer, full_path_test_header_begin, sizeof(full_path_test_header_begin)) == 0,
565         "invalid beginning of header string.\n");
566     ok(index == 0, "header index was incremented\n");
567
568     /* tests for more indices */
569     ret = WinHttpAddRequestHeaders(request, test_headers[1], -1L, WINHTTP_ADDREQ_FLAG_ADD);
570     ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret);
571
572     index = 0;
573     len = sizeof(buffer);
574     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
575         test_header_name, buffer, &len, &index);
576     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
577     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
578     ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
579
580     len = sizeof(buffer);
581     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
582         test_header_name, buffer, &len, &index);
583     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
584     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
585     ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
586
587     ret = WinHttpAddRequestHeaders(request, test_headers[2], -1L, WINHTTP_ADDREQ_FLAG_REPLACE);
588     ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n");
589
590     index = 0;
591     len = sizeof(buffer);
592     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
593         test_header_name, buffer, &len, &index);
594     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
595     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
596     reverse = (memcmp(buffer, test_indices[1], sizeof(test_indices[1])) != 0); /* Win7 returns values in reverse order of adding */
597     ok(memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
598
599     len = sizeof(buffer);
600     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
601         test_header_name, buffer, &len, &index);
602     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
603     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
604     ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
605
606     /* add if new flag */
607     ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW);
608     ok(ret == FALSE, "WinHttpAddRequestHeaders incorrectly replaced existing header.\n");
609
610     index = 0;
611     len = sizeof(buffer);
612     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
613         test_header_name, buffer, &len, &index);
614     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
615     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
616     ok(memcmp(buffer, test_indices[reverse ? 2 : 1], sizeof(test_indices[reverse ? 2 : 1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
617
618     len = sizeof(buffer);
619     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
620         test_header_name, buffer, &len, &index);
621     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
622     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
623     ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
624
625     len = sizeof(buffer);
626     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
627         test_header_name, buffer, &len, &index);
628     ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n");
629
630     /* coalesce flag */
631     ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_COALESCE);
632     ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n");
633
634     index = 0;
635     len = sizeof(buffer);
636     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
637         test_header_name, buffer, &len, &index);
638     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
639     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
640     ok(memcmp(buffer, reverse ? test_flag_coalesce_reverse : test_flag_coalesce, sizeof(reverse ? test_flag_coalesce_reverse : test_flag_coalesce)) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
641
642     len = sizeof(buffer);
643     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
644         test_header_name, buffer, &len, &index);
645     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
646     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
647     ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
648
649     len = sizeof(buffer);
650     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
651         test_header_name, buffer, &len, &index);
652     ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n");
653
654     /* coalesce with comma flag */
655     ret = WinHttpAddRequestHeaders(request, test_headers[4], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA);
656     ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n");
657
658     index = 0;
659     len = sizeof(buffer);
660     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
661         test_header_name, buffer, &len, &index);
662     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
663     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
664     ok(memcmp(buffer, reverse ? test_flag_coalesce_comma_reverse : test_flag_coalesce_comma, sizeof(reverse ? test_flag_coalesce_comma_reverse : test_flag_coalesce_comma)) == 0,
665         "WinHttpQueryHeaders returned incorrect string.\n");
666
667     len = sizeof(buffer);
668     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
669         test_header_name, buffer, &len, &index);
670     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
671     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
672     ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
673
674     len = sizeof(buffer);
675     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
676         test_header_name, buffer, &len, &index);
677     ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n");
678
679
680     /* coalesce with semicolon flag */
681     ret = WinHttpAddRequestHeaders(request, test_headers[5], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON);
682     ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n");
683
684     index = 0;
685     len = sizeof(buffer);
686     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
687         test_header_name, buffer, &len, &index);
688     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
689     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
690     ok(memcmp(buffer, reverse ? test_flag_coalesce_semicolon_reverse : test_flag_coalesce_semicolon, sizeof(reverse ? test_flag_coalesce_semicolon_reverse : test_flag_coalesce_semicolon)) == 0,
691             "WinHttpQueryHeaders returned incorrect string.\n");
692
693     len = sizeof(buffer);
694     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
695         test_header_name, buffer, &len, &index);
696     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
697     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
698     ok(memcmp(buffer, test_indices[reverse ? 1 : 2], sizeof(test_indices[reverse ? 1 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
699
700     len = sizeof(buffer);
701     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
702         test_header_name, buffer, &len, &index);
703     ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n");
704
705     /* add and replace flags */
706     ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
707     ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n");
708
709     index = 0;
710     len = sizeof(buffer);
711     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
712         test_header_name, buffer, &len, &index);
713     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
714     ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n");
715     ok(memcmp(buffer, test_indices[reverse ? 3 : 2], sizeof(test_indices[reverse ? 3 : 2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
716
717     len = sizeof(buffer);
718     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
719         test_header_name, buffer, &len, &index);
720     ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError());
721     ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n");
722     ok(memcmp(buffer, test_indices[reverse ? 1 : 3], sizeof(test_indices[reverse ? 1 : 3])) == 0, "WinHttpQueryHeaders returned incorrect string.\n");
723
724     len = sizeof(buffer);
725     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
726         test_header_name, buffer, &len, &index);
727     ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n");
728
729     ret = WinHttpAddRequestHeaders(request, test_headers[8], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
730     ok(!ret, "WinHttpAddRequestHeaders failed\n");
731
732     ret = WinHttpAddRequestHeaders(request, test_headers[9], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
733     ok(ret, "WinHttpAddRequestHeaders failed\n");
734
735     ret = WinHttpAddRequestHeaders(request, test_headers[10], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
736     ok(!ret, "WinHttpAddRequestHeaders failed\n");
737
738     ret = WinHttpAddRequestHeaders(request, test_headers[11], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
739     ok(!ret, "WinHttpAddRequestHeaders failed\n");
740
741     ret = WinHttpAddRequestHeaders(request, test_headers[12], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
742     ok(!ret, "WinHttpAddRequestHeaders failed\n");
743
744     ret = WinHttpAddRequestHeaders(request, test_headers[13], ~0u, WINHTTP_ADDREQ_FLAG_ADD);
745     ok(ret, "WinHttpAddRequestHeaders failed\n");
746
747     index = 0;
748     buffer[0] = 0;
749     len = sizeof(buffer);
750     ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
751         field, buffer, &len, &index);
752     ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError());
753     ok(!memcmp(buffer, value, sizeof(value)) || ! memcmp(buffer, value_nospace, sizeof(value_nospace)), "unexpected result\n");
754
755     ret = WinHttpCloseHandle(request);
756     ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret);
757  done:
758     ret = WinHttpCloseHandle(connection);
759     ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret);
760     ret = WinHttpCloseHandle(session);
761     ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret);
762
763 }
764
765 static void test_secure_connection(void)
766 {
767     static const WCHAR google[] = {'w','w','w','.','g','o','o','g','l','e','.','c','o','m',0};
768
769     HINTERNET ses, con, req;
770     DWORD size, status, policy, bitness;
771     BOOL ret;
772     CERT_CONTEXT *cert;
773     WINHTTP_CERTIFICATE_INFO info;
774
775     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
776     ok(ses != NULL, "failed to open session %u\n", GetLastError());
777
778     policy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
779     ret = WinHttpSetOption(ses, WINHTTP_OPTION_REDIRECT_POLICY, &policy, sizeof(policy));
780     ok(ret, "failed to set redirect policy %u\n", GetLastError());
781
782     con = WinHttpConnect(ses, google, 443, 0);
783     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
784
785     /* try without setting WINHTTP_FLAG_SECURE */
786     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
787     ok(req != NULL, "failed to open a request %u\n", GetLastError());
788
789     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
790     if (!ret && GetLastError() == ERROR_WINHTTP_CANNOT_CONNECT)
791     {
792         skip("Connection failed, skipping.\n");
793         goto cleanup;
794     }
795     ok(ret, "failed to send request %u\n", GetLastError());
796
797     ret = WinHttpReceiveResponse(req, NULL);
798     ok(!ret, "succeeded unexpectedly\n");
799
800     size = 0;
801     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL);
802     ok(!ret, "succeeded unexpectedly\n");
803
804     WinHttpCloseHandle(req);
805
806     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, WINHTTP_FLAG_SECURE);
807     ok(req != NULL, "failed to open a request %u\n", GetLastError());
808
809     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
810     ok(ret, "failed to send request %u\n", GetLastError());
811     if (!ret)
812     {
813         skip("secure connection failed, skipping remaining secure tests\n");
814         goto cleanup;
815     }
816
817     size = sizeof(cert);
818     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &size );
819     ok(ret, "failed to retrieve certificate context %u\n", GetLastError());
820     if (ret)
821         CertFreeCertificateContext(cert);
822
823     size = sizeof(bitness);
824     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_KEY_BITNESS, &bitness, &size );
825     ok(ret, "failed to retrieve key bitness %u\n", GetLastError());
826
827     size = sizeof(info);
828     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT, &info, &size );
829     ok(ret, "failed to retrieve certificate info %u\n", GetLastError());
830
831     trace("lpszSubjectInfo %s\n", wine_dbgstr_w(info.lpszSubjectInfo));
832     trace("lpszIssuerInfo %s\n", wine_dbgstr_w(info.lpszIssuerInfo));
833     trace("lpszProtocolName %s\n", wine_dbgstr_w(info.lpszProtocolName));
834     trace("lpszSignatureAlgName %s\n", wine_dbgstr_w(info.lpszSignatureAlgName));
835     trace("lpszEncryptionAlgName %s\n", wine_dbgstr_w(info.lpszEncryptionAlgName));
836     trace("dwKeySize %u\n", info.dwKeySize);
837
838     ret = WinHttpReceiveResponse(req, NULL);
839     ok(ret, "failed to receive response %u\n", GetLastError());
840
841     size = sizeof(status);
842     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
843     ok(ret, "failed unexpectedly %u\n", GetLastError());
844     ok(status == 200, "request failed unexpectedly %u\n", status);
845
846     size = 0;
847     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL);
848     ok(!ret, "succeeded unexpectedly\n");
849
850 cleanup:
851     WinHttpCloseHandle(req);
852     WinHttpCloseHandle(con);
853     WinHttpCloseHandle(ses);
854 }
855
856 static void test_request_parameter_defaults(void)
857 {
858     static const WCHAR empty[] = {0};
859     static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
860
861     HINTERNET ses, con, req;
862     DWORD size, status, error;
863     WCHAR *version;
864     BOOL ret;
865
866     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
867     ok(ses != NULL, "failed to open session %u\n", GetLastError());
868
869     con = WinHttpConnect(ses, codeweavers, 0, 0);
870     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
871
872     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
873     ok(req != NULL, "failed to open a request %u\n", GetLastError());
874
875     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
876     ok(ret, "failed to send request %u\n", GetLastError());
877
878     ret = WinHttpReceiveResponse(req, NULL);
879     ok(ret, "failed to receive response %u\n", GetLastError());
880
881     size = sizeof(status);
882     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
883     ok(ret, "failed unexpectedly %u\n", GetLastError());
884     ok(status == 200, "request failed unexpectedly %u\n", status);
885
886     WinHttpCloseHandle(req);
887
888     req = WinHttpOpenRequest(con, empty, empty, empty, NULL, NULL, 0);
889     ok(req != NULL, "failed to open a request %u\n", GetLastError());
890
891     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
892     ok(ret, "failed to send request %u\n", GetLastError());
893
894     ret = WinHttpReceiveResponse(req, NULL);
895     ok(ret, "failed to receive response %u\n", GetLastError());
896
897     size = 0;
898     SetLastError(0xdeadbeef);
899     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_VERSION, NULL, NULL, &size, NULL);
900     error = GetLastError();
901     ok(!ret, "succeeded unexpectedly\n");
902     ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", error);
903
904     version = HeapAlloc(GetProcessHeap(), 0, size);
905     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_VERSION, NULL, version, &size, NULL);
906     ok(ret, "failed unexpectedly %u\n", GetLastError());
907     ok(lstrlenW(version) == size / sizeof(WCHAR), "unexpected size %u\n", size);
908     HeapFree(GetProcessHeap(), 0, version);
909
910     size = sizeof(status);
911     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
912     ok(ret, "failed unexpectedly %u\n", GetLastError());
913     ok(status == 200, "request failed unexpectedly %u\n", status);
914
915     WinHttpCloseHandle(req);
916     WinHttpCloseHandle(con);
917     WinHttpCloseHandle(ses);
918 }
919
920 static const WCHAR Connections[] = {
921     'S','o','f','t','w','a','r','e','\\',
922     'M','i','c','r','o','s','o','f','t','\\',
923     'W','i','n','d','o','w','s','\\',
924     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
925     'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
926     'C','o','n','n','e','c','t','i','o','n','s',0 };
927 static const WCHAR WinHttpSettings[] = {
928     'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
929
930 static DWORD get_default_proxy_reg_value( BYTE *buf, DWORD len, DWORD *type )
931 {
932     LONG l;
933     HKEY key;
934     DWORD ret = 0;
935
936     l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
937     if (!l)
938     {
939         DWORD size = 0;
940
941         l = RegQueryValueExW( key, WinHttpSettings, NULL, type, NULL, &size );
942         if (!l)
943         {
944             if (size <= len)
945                 l = RegQueryValueExW( key, WinHttpSettings, NULL, type, buf,
946                     &size );
947             if (!l)
948                 ret = size;
949         }
950         RegCloseKey( key );
951     }
952     return ret;
953 }
954
955 static void set_default_proxy_reg_value( BYTE *buf, DWORD len, DWORD type )
956 {
957     LONG l;
958     HKEY key;
959
960     l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
961         KEY_WRITE, NULL, &key, NULL );
962     if (!l)
963     {
964         if (len)
965             RegSetValueExW( key, WinHttpSettings, 0, type, buf, len );
966         else
967             RegDeleteValueW( key, WinHttpSettings );
968         RegCloseKey( key );
969     }
970 }
971
972 static void test_set_default_proxy_config(void)
973 {
974     static const WCHAR wideString[] = { 0x226f, 0x575b, 0 };
975     static const WCHAR normalString[] = { 'f','o','o',0 };
976     DWORD type, len;
977     BYTE *saved_proxy_settings = NULL;
978     WINHTTP_PROXY_INFO info;
979     BOOL ret;
980
981     /* FIXME: it would be simpler to read the current settings using
982      * WinHttpGetDefaultProxyConfiguration and save them using
983      * WinHttpSetDefaultProxyConfiguration, but they appear to have a bug.
984      *
985      * If a proxy is configured in the registry, e.g. via 'proxcfg -p "foo"',
986      * the access type reported by WinHttpGetDefaultProxyConfiguration is 1,
987      * WINHTTP_ACCESS_TYPE_NO_PROXY, whereas it should be
988      * WINHTTP_ACCESS_TYPE_NAMED_PROXY.
989      * If WinHttpSetDefaultProxyConfiguration is called with dwAccessType = 1,
990      * the lpszProxy and lpszProxyBypass values are ignored.
991      * Thus, if a proxy is set with proxycfg, then calling
992      * WinHttpGetDefaultProxyConfiguration followed by
993      * WinHttpSetDefaultProxyConfiguration results in the proxy settings
994      * getting deleted from the registry.
995      *
996      * Instead I read the current registry value and restore it directly.
997      */
998     len = get_default_proxy_reg_value( NULL, 0, &type );
999     if (len)
1000     {
1001         saved_proxy_settings = HeapAlloc( GetProcessHeap(), 0, len );
1002         len = get_default_proxy_reg_value( saved_proxy_settings, len, &type );
1003     }
1004
1005     if (0)
1006     {
1007         /* Crashes on Vista and higher */
1008         SetLastError(0xdeadbeef);
1009         ret = WinHttpSetDefaultProxyConfiguration(NULL);
1010         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1011             "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1012     }
1013
1014     /* test with invalid access type */
1015     info.dwAccessType = 0xdeadbeef;
1016     info.lpszProxy = info.lpszProxyBypass = NULL;
1017     SetLastError(0xdeadbeef);
1018     ret = WinHttpSetDefaultProxyConfiguration(&info);
1019     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1020         "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1021
1022     /* at a minimum, the proxy server must be set */
1023     info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1024     info.lpszProxy = info.lpszProxyBypass = NULL;
1025     SetLastError(0xdeadbeef);
1026     ret = WinHttpSetDefaultProxyConfiguration(&info);
1027     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1028         "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1029     info.lpszProxyBypass = normalString;
1030     SetLastError(0xdeadbeef);
1031     ret = WinHttpSetDefaultProxyConfiguration(&info);
1032     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1033         "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1034
1035     /* the proxy server can't have wide characters */
1036     info.lpszProxy = wideString;
1037     SetLastError(0xdeadbeef);
1038     ret = WinHttpSetDefaultProxyConfiguration(&info);
1039     ok((!ret && GetLastError() == ERROR_INVALID_PARAMETER) ||
1040         broken(ret), /* Earlier winhttp versions on W2K/XP */
1041         "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1042
1043     info.lpszProxy = normalString;
1044     SetLastError(0xdeadbeef);
1045     ret = WinHttpSetDefaultProxyConfiguration(&info);
1046     if (ret)
1047     {
1048         ok(ret, "always true\n");
1049         set_default_proxy_reg_value( saved_proxy_settings, len, type );
1050     }
1051     else if (GetLastError() == ERROR_ACCESS_DENIED)
1052         skip("couldn't set default proxy configuration: access denied\n");
1053     else
1054         ok(ret, "WinHttpSetDefaultProxyConfiguration failed: %d\n",
1055            GetLastError());
1056 }
1057
1058 static void test_Timeouts (void)
1059 {
1060     BOOL ret;
1061     DWORD value, size;
1062     HINTERNET ses, req, con;
1063     static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
1064
1065
1066     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1067     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1068
1069     SetLastError(0xdeadbeef);
1070     ret = WinHttpSetTimeouts(ses, -2, 0, 0, 0);
1071     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1072        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1073
1074     SetLastError(0xdeadbeef);
1075     ret = WinHttpSetTimeouts(ses, 0, -2, 0, 0);
1076     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1077        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1078
1079     SetLastError(0xdeadbeef);
1080     ret = WinHttpSetTimeouts(ses, 0, 0, -2, 0);
1081     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1082        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1083
1084     SetLastError(0xdeadbeef);
1085     ret = WinHttpSetTimeouts(ses, 0, 0, 0, -2);
1086     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1087        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1088
1089     SetLastError(0xdeadbeef);
1090     ret = WinHttpSetTimeouts(ses, -1, -1, -1, -1);
1091     ok(ret, "%u\n", GetLastError());
1092
1093     SetLastError(0xdeadbeef);
1094     ret = WinHttpSetTimeouts(ses, 0, 0, 0, 0);
1095     ok(ret, "%u\n", GetLastError());
1096
1097     SetLastError(0xdeadbeef);
1098     ret = WinHttpSetTimeouts(ses, 0x0123, 0x4567, 0x89ab, 0xcdef);
1099     ok(ret, "%u\n", GetLastError());
1100
1101     SetLastError(0xdeadbeef);
1102     value = 0xdeadbeef;
1103     size  = sizeof(DWORD);
1104     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1105     ok(ret, "%u\n", GetLastError());
1106     ok(value == 0x0123, "Expected 0x0123, got %u\n", value);
1107
1108     SetLastError(0xdeadbeef);
1109     value = 0xdeadbeef;
1110     size  = sizeof(DWORD);
1111     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1112     ok(ret, "%u\n", GetLastError());
1113     ok(value == 0x4567, "Expected 0x4567, got %u\n", value);
1114
1115     SetLastError(0xdeadbeef);
1116     value = 0xdeadbeef;
1117     size  = sizeof(DWORD);
1118     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1119     ok(ret, "%u\n", GetLastError());
1120     ok(value == 0x89ab, "Expected 0x89ab, got %u\n", value);
1121
1122     SetLastError(0xdeadbeef);
1123     value = 0xdeadbeef;
1124     size  = sizeof(DWORD);
1125     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1126     ok(ret, "%u\n", GetLastError());
1127     ok(value == 0xcdef, "Expected 0xcdef, got %u\n", value);
1128
1129     SetLastError(0xdeadbeef);
1130     value = 0;
1131     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1132     ok(ret, "%u\n", GetLastError());
1133
1134     SetLastError(0xdeadbeef);
1135     value = 0xdeadbeef;
1136     size  = sizeof(DWORD);
1137     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1138     ok(ret, "%u\n", GetLastError());
1139     ok(value == 0, "Expected 0, got %u\n", value);
1140
1141     SetLastError(0xdeadbeef);
1142     value = 0;
1143     ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1144     ok(ret, "%u\n", GetLastError());
1145
1146     SetLastError(0xdeadbeef);
1147     value = 0xdeadbeef;
1148     size  = sizeof(DWORD);
1149     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1150     ok(ret, "%u\n", GetLastError());
1151     ok(value == 0, "Expected 0, got %u\n", value);
1152
1153     SetLastError(0xdeadbeef);
1154     value = 0;
1155     ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1156     ok(ret, "%u\n", GetLastError());
1157
1158     SetLastError(0xdeadbeef);
1159     value = 0xdeadbeef;
1160     size  = sizeof(DWORD);
1161     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1162     ok(ret, "%u\n", GetLastError());
1163     ok(value == 0, "Expected 0, got %u\n", value);
1164
1165     SetLastError(0xdeadbeef);
1166     value = 0;
1167     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1168     ok(ret, "%u\n", GetLastError());
1169
1170     SetLastError(0xdeadbeef);
1171     value = 0xdeadbeef;
1172     size  = sizeof(DWORD);
1173     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1174     ok(ret, "%u\n", GetLastError());
1175     ok(value == 0, "Expected 0, got %u\n", value);
1176
1177     SetLastError(0xdeadbeef);
1178     value = 0xbeefdead;
1179     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1180     ok(ret, "%u\n", GetLastError());
1181
1182     SetLastError(0xdeadbeef);
1183     value = 0xdeadbeef;
1184     size  = sizeof(DWORD);
1185     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1186     ok(ret, "%u\n", GetLastError());
1187     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1188
1189     SetLastError(0xdeadbeef);
1190     value = 0xbeefdead;
1191     ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1192     ok(ret, "%u\n", GetLastError());
1193
1194     SetLastError(0xdeadbeef);
1195     value = 0xdeadbeef;
1196     size  = sizeof(DWORD);
1197     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1198     ok(ret, "%u\n", GetLastError());
1199     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1200
1201     SetLastError(0xdeadbeef);
1202     value = 0xbeefdead;
1203     ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1204     ok(ret, "%u\n", GetLastError());
1205
1206     SetLastError(0xdeadbeef);
1207     value = 0xdeadbeef;
1208     size  = sizeof(DWORD);
1209     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1210     ok(ret, "%u\n", GetLastError());
1211     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1212
1213     SetLastError(0xdeadbeef);
1214     value = 0xbeefdead;
1215     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1216     ok(ret, "%u\n", GetLastError());
1217
1218     SetLastError(0xdeadbeef);
1219     value = 0xdeadbeef;
1220     size  = sizeof(DWORD);
1221     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1222     ok(ret, "%u\n", GetLastError());
1223     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1224
1225     con = WinHttpConnect(ses, codeweavers, 0, 0);
1226     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1227
1228     /* Timeout values should match the last one set for session */
1229     SetLastError(0xdeadbeef);
1230     value = 0xdeadbeef;
1231     size  = sizeof(DWORD);
1232     ret = WinHttpQueryOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1233     ok(ret, "%u\n", GetLastError());
1234     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1235
1236     SetLastError(0xdeadbeef);
1237     value = 0xdeadbeef;
1238     size  = sizeof(DWORD);
1239     ret = WinHttpQueryOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1240     ok(ret, "%u\n", GetLastError());
1241     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1242
1243     SetLastError(0xdeadbeef);
1244     value = 0xdeadbeef;
1245     size  = sizeof(DWORD);
1246     ret = WinHttpQueryOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1247     ok(ret, "%u\n", GetLastError());
1248     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1249
1250     SetLastError(0xdeadbeef);
1251     value = 0xdeadbeef;
1252     size  = sizeof(DWORD);
1253     ret = WinHttpQueryOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1254     ok(ret, "%u\n", GetLastError());
1255     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1256
1257     SetLastError(0xdeadbeef);
1258     ret = WinHttpSetTimeouts(con, -2, 0, 0, 0);
1259     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1260        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1261
1262     SetLastError(0xdeadbeef);
1263     ret = WinHttpSetTimeouts(con, 0, -2, 0, 0);
1264     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1265        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1266
1267     SetLastError(0xdeadbeef);
1268     ret = WinHttpSetTimeouts(con, 0, 0, -2, 0);
1269     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1270        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1271
1272     SetLastError(0xdeadbeef);
1273     ret = WinHttpSetTimeouts(con, 0, 0, 0, -2);
1274     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1275        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1276
1277     SetLastError(0xdeadbeef);
1278     ret = WinHttpSetTimeouts(con, -1, -1, -1, -1);
1279     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1280        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1281
1282     SetLastError(0xdeadbeef);
1283     ret = WinHttpSetTimeouts(con, 0, 0, 0, 0);
1284     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1285        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1286
1287     SetLastError(0xdeadbeef);
1288     value = 0;
1289     ret = WinHttpSetOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1290     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1291        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1292
1293     SetLastError(0xdeadbeef);
1294     value = 0;
1295     ret = WinHttpSetOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1296     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1297        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1298
1299     SetLastError(0xdeadbeef);
1300     value = 0;
1301     ret = WinHttpSetOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1302     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1303        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1304
1305     SetLastError(0xdeadbeef);
1306     value = 0;
1307     ret = WinHttpSetOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1308     ok(!ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE,
1309        "expected ERROR_WINHTTP_INVALID_TYPE, got %u\n", GetLastError());
1310
1311     /* Changing timeout values for session should affect the values for connection */
1312     SetLastError(0xdeadbeef);
1313     value = 0xdead;
1314     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1315     ok(ret, "%u\n", GetLastError());
1316
1317     SetLastError(0xdeadbeef);
1318     value = 0xdeadbeef;
1319     size  = sizeof(DWORD);
1320     ret = WinHttpQueryOption(con, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1321     ok(ret, "%u\n", GetLastError());
1322     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1323
1324     SetLastError(0xdeadbeef);
1325     value = 0xdead;
1326     ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1327     ok(ret, "%u\n", GetLastError());
1328
1329     SetLastError(0xdeadbeef);
1330     value = 0xdeadbeef;
1331     size  = sizeof(DWORD);
1332     ret = WinHttpQueryOption(con, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1333     ok(ret, "%u\n", GetLastError());
1334     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1335
1336     SetLastError(0xdeadbeef);
1337     value = 0xdead;
1338     ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1339     ok(ret, "%u\n", GetLastError());
1340
1341     SetLastError(0xdeadbeef);
1342     value = 0xdeadbeef;
1343     size  = sizeof(DWORD);
1344     ret = WinHttpQueryOption(con, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1345     ok(ret, "%u\n", GetLastError());
1346     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1347
1348     SetLastError(0xdeadbeef);
1349     value = 0xdead;
1350     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1351     ok(ret, "%u\n", GetLastError());
1352
1353     SetLastError(0xdeadbeef);
1354     value = 0xdeadbeef;
1355     size  = sizeof(DWORD);
1356     ret = WinHttpQueryOption(con, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1357     ok(ret, "%u\n", GetLastError());
1358     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1359
1360     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
1361     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1362
1363     /* Timeout values should match the last one set for session */
1364     SetLastError(0xdeadbeef);
1365     value = 0xdeadbeef;
1366     size  = sizeof(DWORD);
1367     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1368     ok(ret, "%u\n", GetLastError());
1369     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1370
1371     SetLastError(0xdeadbeef);
1372     value = 0xdeadbeef;
1373     size  = sizeof(DWORD);
1374     ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1375     ok(ret, "%u\n", GetLastError());
1376     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1377
1378     SetLastError(0xdeadbeef);
1379     value = 0xdeadbeef;
1380     size  = sizeof(DWORD);
1381     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1382     ok(ret, "%u\n", GetLastError());
1383     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1384
1385     SetLastError(0xdeadbeef);
1386     value = 0xdeadbeef;
1387     size  = sizeof(DWORD);
1388     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1389     ok(ret, "%u\n", GetLastError());
1390     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1391
1392     SetLastError(0xdeadbeef);
1393     ret = WinHttpSetTimeouts(req, -2, 0, 0, 0);
1394     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1395        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1396
1397     SetLastError(0xdeadbeef);
1398     ret = WinHttpSetTimeouts(req, 0, -2, 0, 0);
1399     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1400        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1401
1402     SetLastError(0xdeadbeef);
1403     ret = WinHttpSetTimeouts(req, 0, 0, -2, 0);
1404     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1405        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1406
1407     SetLastError(0xdeadbeef);
1408     ret = WinHttpSetTimeouts(req, 0, 0, 0, -2);
1409     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1410        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
1411
1412     SetLastError(0xdeadbeef);
1413     ret = WinHttpSetTimeouts(req, -1, -1, -1, -1);
1414     ok(ret, "%u\n", GetLastError());
1415
1416     SetLastError(0xdeadbeef);
1417     ret = WinHttpSetTimeouts(req, 0, 0, 0, 0);
1418     ok(ret, "%u\n", GetLastError());
1419
1420     SetLastError(0xdeadbeef);
1421     ret = WinHttpSetTimeouts(req, 0xcdef, 0x89ab, 0x4567, 0x0123);
1422     ok(ret, "%u\n", GetLastError());
1423
1424     SetLastError(0xdeadbeef);
1425     value = 0xdeadbeef;
1426     size  = sizeof(DWORD);
1427     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1428     ok(ret, "%u\n", GetLastError());
1429     ok(value == 0xcdef, "Expected 0xcdef, got %u\n", value);
1430
1431     SetLastError(0xdeadbeef);
1432     value = 0xdeadbeef;
1433     size  = sizeof(DWORD);
1434     ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1435     ok(ret, "%u\n", GetLastError());
1436     ok(value == 0x89ab, "Expected 0x89ab, got %u\n", value);
1437
1438     SetLastError(0xdeadbeef);
1439     value = 0xdeadbeef;
1440     size  = sizeof(DWORD);
1441     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1442     ok(ret, "%u\n", GetLastError());
1443     ok(value == 0x4567, "Expected 0x4567, got %u\n", value);
1444
1445     SetLastError(0xdeadbeef);
1446     value = 0xdeadbeef;
1447     size  = sizeof(DWORD);
1448     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1449     ok(ret, "%u\n", GetLastError());
1450     ok(value == 0x0123, "Expected 0x0123, got %u\n", value);
1451
1452     SetLastError(0xdeadbeef);
1453     value = 0;
1454     ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1455     ok(ret, "%u\n", GetLastError());
1456
1457     SetLastError(0xdeadbeef);
1458     value = 0xdeadbeef;
1459     size  = sizeof(DWORD);
1460     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1461     ok(ret, "%u\n", GetLastError());
1462     ok(value == 0, "Expected 0, got %u\n", value);
1463
1464     SetLastError(0xdeadbeef);
1465     value = 0;
1466     ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1467     ok(ret, "%u\n", GetLastError());
1468
1469     SetLastError(0xdeadbeef);
1470     value = 0xdeadbeef;
1471     size  = sizeof(DWORD);
1472     ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1473     ok(ret, "%u\n", GetLastError());
1474     ok(value == 0, "Expected 0, got %u\n", value);
1475
1476     SetLastError(0xdeadbeef);
1477     value = 0;
1478     ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1479     ok(ret, "%u\n", GetLastError());
1480
1481     SetLastError(0xdeadbeef);
1482     value = 0xdeadbeef;
1483     size  = sizeof(DWORD);
1484     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1485     ok(ret, "%u\n", GetLastError());
1486     ok(value == 0, "Expected 0, got %u\n", value);
1487
1488     SetLastError(0xdeadbeef);
1489     value = 0;
1490     ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1491     ok(ret, "%u\n", GetLastError());
1492
1493     SetLastError(0xdeadbeef);
1494     value = 0xdeadbeef;
1495     size  = sizeof(DWORD);
1496     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1497     ok(ret, "%u\n", GetLastError());
1498     ok(value == 0, "Expected 0, got %u\n", value);
1499
1500     SetLastError(0xdeadbeef);
1501     value = 0xbeefdead;
1502     ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1503     ok(ret, "%u\n", GetLastError());
1504
1505     SetLastError(0xdeadbeef);
1506     value = 0xdeadbeef;
1507     size  = sizeof(DWORD);
1508     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1509     ok(ret, "%u\n", GetLastError());
1510     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1511
1512     SetLastError(0xdeadbeef);
1513     value = 0xbeefdead;
1514     ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1515     ok(ret, "%u\n", GetLastError());
1516
1517     SetLastError(0xdeadbeef);
1518     value = 0xdeadbeef;
1519     size  = sizeof(DWORD);
1520     ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1521     ok(ret, "%u\n", GetLastError());
1522     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1523
1524     SetLastError(0xdeadbeef);
1525     value = 0xbeefdead;
1526     ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1527     ok(ret, "%u\n", GetLastError());
1528
1529     SetLastError(0xdeadbeef);
1530     value = 0xdeadbeef;
1531     size  = sizeof(DWORD);
1532     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1533     ok(ret, "%u\n", GetLastError());
1534     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1535
1536     SetLastError(0xdeadbeef);
1537     value = 0xbeefdead;
1538     ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1539     ok(ret, "%u\n", GetLastError());
1540
1541     SetLastError(0xdeadbeef);
1542     value = 0xdeadbeef;
1543     size  = sizeof(DWORD);
1544     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1545     ok(ret, "%u\n", GetLastError());
1546     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1547
1548     /* Changing timeout values for session should not affect the values for a request,
1549      * neither should the other way around.
1550      */
1551     SetLastError(0xdeadbeef);
1552     value = 0xbeefdead;
1553     ret = WinHttpSetOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1554     ok(ret, "%u\n", GetLastError());
1555
1556     SetLastError(0xdeadbeef);
1557     value = 0xdeadbeef;
1558     size  = sizeof(DWORD);
1559     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1560     ok(ret, "%u\n", GetLastError());
1561     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1562
1563     SetLastError(0xdeadbeef);
1564     value = 0xbeefdead;
1565     ret = WinHttpSetOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1566     ok(ret, "%u\n", GetLastError());
1567
1568     SetLastError(0xdeadbeef);
1569     value = 0xdeadbeef;
1570     size  = sizeof(DWORD);
1571     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1572     ok(ret, "%u\n", GetLastError());
1573     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1574
1575     SetLastError(0xdeadbeef);
1576     value = 0xbeefdead;
1577     ret = WinHttpSetOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1578     ok(ret, "%u\n", GetLastError());
1579
1580     SetLastError(0xdeadbeef);
1581     value = 0xdeadbeef;
1582     size  = sizeof(DWORD);
1583     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1584     ok(ret, "%u\n", GetLastError());
1585     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1586
1587     SetLastError(0xdeadbeef);
1588     value = 0xbeefdead;
1589     ret = WinHttpSetOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1590     ok(ret, "%u\n", GetLastError());
1591
1592     SetLastError(0xdeadbeef);
1593     value = 0xdeadbeef;
1594     size  = sizeof(DWORD);
1595     ret = WinHttpQueryOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1596     ok(ret, "%u\n", GetLastError());
1597     ok(value == 0xdead, "Expected 0xdead, got %u\n", value);
1598
1599     SetLastError(0xdeadbeef);
1600     value = 0xbeef;
1601     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, sizeof(value));
1602     ok(ret, "%u\n", GetLastError());
1603
1604     SetLastError(0xdeadbeef);
1605     value = 0xdeadbeef;
1606     size  = sizeof(DWORD);
1607     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RESOLVE_TIMEOUT, &value, &size);
1608     ok(ret, "%u\n", GetLastError());
1609     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1610
1611     SetLastError(0xdeadbeef);
1612     value = 0xbeef;
1613     ret = WinHttpSetOption(ses, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, sizeof(value));
1614     ok(ret, "%u\n", GetLastError());
1615
1616     SetLastError(0xdeadbeef);
1617     value = 0xdeadbeef;
1618     size  = sizeof(DWORD);
1619     ret = WinHttpQueryOption(req, WINHTTP_OPTION_CONNECT_TIMEOUT, &value, &size);
1620     ok(ret, "%u\n", GetLastError());
1621     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1622
1623     SetLastError(0xdeadbeef);
1624     value = 0xbeef;
1625     ret = WinHttpSetOption(ses, WINHTTP_OPTION_SEND_TIMEOUT, &value, sizeof(value));
1626     ok(ret, "%u\n", GetLastError());
1627
1628     SetLastError(0xdeadbeef);
1629     value = 0xdeadbeef;
1630     size  = sizeof(DWORD);
1631     ret = WinHttpQueryOption(req, WINHTTP_OPTION_SEND_TIMEOUT, &value, &size);
1632     ok(ret, "%u\n", GetLastError());
1633     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1634
1635     SetLastError(0xdeadbeef);
1636     value = 0xbeef;
1637     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, sizeof(value));
1638     ok(ret, "%u\n", GetLastError());
1639
1640     SetLastError(0xdeadbeef);
1641     value = 0xdeadbeef;
1642     size  = sizeof(DWORD);
1643     ret = WinHttpQueryOption(req, WINHTTP_OPTION_RECEIVE_TIMEOUT, &value, &size);
1644     ok(ret, "%u\n", GetLastError());
1645     ok(value == 0xbeefdead, "Expected 0xbeefdead, got %u\n", value);
1646
1647     WinHttpCloseHandle(req);
1648     WinHttpCloseHandle(con);
1649     WinHttpCloseHandle(ses);
1650 }
1651
1652 static void test_resolve_timeout(void)
1653 {
1654     static const WCHAR codeweavers[] =
1655         {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
1656     static const WCHAR nxdomain[] =
1657         {'n','x','d','o','m','a','i','n','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0};
1658
1659     HINTERNET ses, con, req;
1660     DWORD timeout;
1661     BOOL ret;
1662
1663     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1664     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1665
1666     timeout = 10000;
1667     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &timeout, sizeof(timeout));
1668     ok(ret, "failed to set resolve timeout %u\n", GetLastError());
1669
1670     con = WinHttpConnect(ses, nxdomain, 0, 0);
1671     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1672
1673     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
1674     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1675
1676     SetLastError(0xdeadbeef);
1677     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1678     ok(!ret, "sent request\n");
1679     ok(GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED,
1680        "expected ERROR_WINHTTP_NAME_NOT_RESOLVED got %u\n", GetLastError());
1681
1682     WinHttpCloseHandle(req);
1683     WinHttpCloseHandle(con);
1684     WinHttpCloseHandle(ses);
1685
1686     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1687     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1688
1689     timeout = 10000;
1690     ret = WinHttpSetOption(ses, WINHTTP_OPTION_RESOLVE_TIMEOUT, &timeout, sizeof(timeout));
1691     ok(ret, "failed to set resolve timeout %u\n", GetLastError());
1692
1693     con = WinHttpConnect(ses, codeweavers, 0, 0);
1694     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1695
1696     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
1697     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1698
1699     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1700     ok(ret, "failed to send request\n");
1701
1702     WinHttpCloseHandle(req);
1703     WinHttpCloseHandle(con);
1704     WinHttpCloseHandle(ses);
1705 }
1706
1707 static const char page1[] =
1708 "<HTML>\r\n"
1709 "<HEAD><TITLE>winhttp test page</TITLE></HEAD>\r\n"
1710 "<BODY>The quick brown fox jumped over the lazy dog<P></BODY>\r\n"
1711 "</HTML>\r\n\r\n";
1712
1713 static const char okmsg[] =
1714 "HTTP/1.1 200 OK\r\n"
1715 "Server: winetest\r\n"
1716 "\r\n";
1717
1718 static const char notokmsg[] =
1719 "HTTP/1.1 400 Bad Request\r\n"
1720 "Server: winetest\r\n"
1721 "\r\n";
1722
1723 static const char noauthmsg[] =
1724 "HTTP/1.1 401 Unauthorized\r\n"
1725 "Server: winetest\r\n"
1726 "Connection: close\r\n"
1727 "WWW-Authenticate: Basic realm=\"placebo\"\r\n"
1728 "\r\n";
1729
1730 static const char proxymsg[] =
1731 "HTTP/1.1 407 Proxy Authentication Required\r\n"
1732 "Server: winetest\r\n"
1733 "Proxy-Connection: close\r\n"
1734 "Proxy-Authenticate: Basic realm=\"placebo\"\r\n"
1735 "\r\n";
1736
1737 struct server_info
1738 {
1739     HANDLE event;
1740     int port;
1741 };
1742
1743 static DWORD CALLBACK server_thread(LPVOID param)
1744 {
1745     struct server_info *si = param;
1746     int r, c, i, on;
1747     SOCKET s;
1748     struct sockaddr_in sa;
1749     char buffer[0x100];
1750     WSADATA wsaData;
1751     int last_request = 0;
1752
1753     WSAStartup(MAKEWORD(1,1), &wsaData);
1754
1755     s = socket(AF_INET, SOCK_STREAM, 0);
1756     if (s == INVALID_SOCKET)
1757         return 1;
1758
1759     on = 1;
1760     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof on);
1761
1762     memset(&sa, 0, sizeof sa);
1763     sa.sin_family = AF_INET;
1764     sa.sin_port = htons(si->port);
1765     sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
1766
1767     r = bind(s, (struct sockaddr *)&sa, sizeof(sa));
1768     if (r < 0)
1769         return 1;
1770
1771     listen(s, 0);
1772     SetEvent(si->event);
1773     do
1774     {
1775         c = accept(s, NULL, NULL);
1776
1777         memset(buffer, 0, sizeof buffer);
1778         for(i = 0; i < sizeof buffer - 1; i++)
1779         {
1780             r = recv(c, &buffer[i], 1, 0);
1781             if (r != 1)
1782                 break;
1783             if (i < 4) continue;
1784             if (buffer[i - 2] == '\n' && buffer[i] == '\n' &&
1785                 buffer[i - 3] == '\r' && buffer[i - 1] == '\r')
1786                 break;
1787         }
1788         if (strstr(buffer, "GET /basic"))
1789         {
1790             send(c, okmsg, sizeof okmsg - 1, 0);
1791             send(c, page1, sizeof page1 - 1, 0);
1792         }
1793         if (strstr(buffer, "/auth"))
1794         {
1795             if (strstr(buffer, "Authorization: Basic dXNlcjpwd2Q="))
1796                 send(c, okmsg, sizeof okmsg - 1, 0);
1797             else
1798                 send(c, noauthmsg, sizeof noauthmsg - 1, 0);
1799         }
1800         if (strstr(buffer, "/no_headers"))
1801         {
1802             send(c, page1, sizeof page1 - 1, 0);
1803         }
1804         if (strstr(buffer, "GET /quit"))
1805         {
1806             send(c, okmsg, sizeof okmsg - 1, 0);
1807             send(c, page1, sizeof page1 - 1, 0);
1808             last_request = 1;
1809         }
1810         shutdown(c, 2);
1811         closesocket(c);
1812
1813     } while (!last_request);
1814
1815     closesocket(s);
1816     return 0;
1817 }
1818
1819 static void test_basic_request(int port, const WCHAR *verb, const WCHAR *path)
1820 {
1821     HINTERNET ses, con, req;
1822     char buffer[0x100];
1823     DWORD count, status, size;
1824     BOOL ret;
1825
1826     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1827     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1828
1829     con = WinHttpConnect(ses, localhostW, port, 0);
1830     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1831
1832     req = WinHttpOpenRequest(con, verb, path, NULL, NULL, NULL, 0);
1833     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1834
1835     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1836     ok(ret, "failed to send request %u\n", GetLastError());
1837
1838     ret = WinHttpReceiveResponse(req, NULL);
1839     ok(ret, "failed to receive response %u\n", GetLastError());
1840
1841     size = sizeof(status);
1842     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
1843     ok(ret, "failed to query status code %u\n", GetLastError());
1844     ok(status == 200, "request failed unexpectedly %u\n", status);
1845
1846     count = 0;
1847     memset(buffer, 0, sizeof(buffer));
1848     ret = WinHttpReadData(req, buffer, sizeof buffer, &count);
1849     ok(ret, "failed to read data %u\n", GetLastError());
1850     ok(count == sizeof page1 - 1, "count was wrong\n");
1851     ok(!memcmp(buffer, page1, sizeof page1), "http data wrong\n");
1852
1853     WinHttpCloseHandle(req);
1854     WinHttpCloseHandle(con);
1855     WinHttpCloseHandle(ses);
1856 }
1857
1858 static void test_basic_authentication(int port)
1859 {
1860     static const WCHAR authW[] = {'/','a','u','t','h',0};
1861     static const WCHAR userW[] = {'u','s','e','r',0};
1862     static const WCHAR passW[] = {'p','w','d',0};
1863     HINTERNET ses, con, req;
1864     DWORD status, size, error;
1865     BOOL ret;
1866
1867     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1868     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1869
1870     con = WinHttpConnect(ses, localhostW, port, 0);
1871     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1872
1873     req = WinHttpOpenRequest(con, NULL, authW, NULL, NULL, NULL, 0);
1874     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1875
1876     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1877     ok(ret, "failed to send request %u\n", GetLastError());
1878
1879     ret = WinHttpReceiveResponse(req, NULL);
1880     ok(ret, "failed to receive response %u\n", GetLastError());
1881
1882     size = sizeof(status);
1883     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
1884     ok(ret, "failed to query status code %u\n", GetLastError());
1885     ok(status == 401, "request failed unexpectedly %u\n", status);
1886
1887     SetLastError(0xdeadbeef);
1888     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, NULL, NULL);
1889     error = GetLastError();
1890     ok(!ret, "expected failure\n");
1891     ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error);
1892
1893     SetLastError(0xdeadbeef);
1894     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, passW, NULL);
1895     error = GetLastError();
1896     ok(!ret, "expected failure\n");
1897     ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error);
1898
1899     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL);
1900     ok(ret, "failed to set credentials %u\n", GetLastError());
1901
1902     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1903     ok(ret, "failed to send request %u\n", GetLastError());
1904
1905     ret = WinHttpReceiveResponse(req, NULL);
1906     ok(ret, "failed to receive response %u\n", GetLastError());
1907
1908     size = sizeof(status);
1909     ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL);
1910     ok(ret, "failed to query status code %u\n", GetLastError());
1911     ok(status == 200, "request failed unexpectedly %u\n", status);
1912
1913     WinHttpCloseHandle(req);
1914     WinHttpCloseHandle(con);
1915     WinHttpCloseHandle(ses);
1916 }
1917
1918 static void test_no_headers(int port)
1919 {
1920     static const WCHAR no_headersW[] = {'/','n','o','_','h','e','a','d','e','r','s',0};
1921     HINTERNET ses, con, req;
1922     BOOL ret;
1923
1924     ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0);
1925     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1926
1927     con = WinHttpConnect(ses, localhostW, port, 0);
1928     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1929
1930     req = WinHttpOpenRequest(con, NULL, no_headersW, NULL, NULL, NULL, 0);
1931     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1932
1933     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
1934     ok(ret, "failed to send request %u\n", GetLastError());
1935
1936     ret = WinHttpReceiveResponse(req, NULL);
1937     ok(!ret, "expected failure\n");
1938
1939     WinHttpCloseHandle(req);
1940     WinHttpCloseHandle(con);
1941     WinHttpCloseHandle(ses);
1942 }
1943
1944 static void test_credentials(void)
1945 {
1946     static WCHAR userW[] = {'u','s','e','r',0};
1947     static WCHAR passW[] = {'p','a','s','s',0};
1948     static WCHAR proxy_userW[] = {'p','r','o','x','y','u','s','e','r',0};
1949     static WCHAR proxy_passW[] = {'p','r','o','x','y','p','a','s','s',0};
1950     HINTERNET ses, con, req;
1951     DWORD size, error;
1952     WCHAR buffer[32];
1953     BOOL ret;
1954
1955     ses = WinHttpOpen(test_useragent, 0, proxy_userW, proxy_passW, 0);
1956     ok(ses != NULL, "failed to open session %u\n", GetLastError());
1957
1958     con = WinHttpConnect(ses, localhostW, 0, 0);
1959     ok(con != NULL, "failed to open a connection %u\n", GetLastError());
1960
1961     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
1962     ok(req != NULL, "failed to open a request %u\n", GetLastError());
1963
1964     size = sizeof(buffer)/sizeof(WCHAR);
1965     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size);
1966     ok(ret, "failed to query proxy username %u\n", GetLastError());
1967     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
1968     ok(!size, "expected 0, got %u\n", size);
1969
1970     size = sizeof(buffer)/sizeof(WCHAR);
1971     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size);
1972     ok(ret, "failed to query proxy password %u\n", GetLastError());
1973     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
1974     ok(!size, "expected 0, got %u\n", size);
1975
1976     ret = WinHttpSetOption(req, WINHTTP_OPTION_PROXY_USERNAME, proxy_userW, lstrlenW(proxy_userW));
1977     ok(ret, "failed to set username %u\n", GetLastError());
1978
1979     size = sizeof(buffer)/sizeof(WCHAR);
1980     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_USERNAME, &buffer, &size);
1981     ok(ret, "failed to query proxy username %u\n", GetLastError());
1982     ok(!winetest_strcmpW(buffer, proxy_userW), "unexpected result %s\n", wine_dbgstr_w(buffer));
1983     ok(size == lstrlenW(proxy_userW) * sizeof(WCHAR), "unexpected result %u\n", size);
1984
1985     size = sizeof(buffer)/sizeof(WCHAR);
1986     ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size);
1987     ok(ret, "failed to query username %u\n", GetLastError());
1988     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
1989     ok(!size, "expected 0, got %u\n", size);
1990
1991     size = sizeof(buffer)/sizeof(WCHAR);
1992     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size);
1993     ok(ret, "failed to query password %u\n", GetLastError());
1994     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
1995     ok(!size, "expected 0, got %u\n", size);
1996
1997     ret = WinHttpSetOption(req, WINHTTP_OPTION_PROXY_PASSWORD, proxy_passW, lstrlenW(proxy_passW));
1998     ok(ret, "failed to set proxy password %u\n", GetLastError());
1999
2000     size = sizeof(buffer)/sizeof(WCHAR);
2001     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PROXY_PASSWORD, &buffer, &size);
2002     ok(ret, "failed to query proxy password %u\n", GetLastError());
2003     ok(!winetest_strcmpW(buffer, proxy_passW), "unexpected result %s\n", wine_dbgstr_w(buffer));
2004     ok(size == lstrlenW(proxy_passW) * sizeof(WCHAR), "unexpected result %u\n", size);
2005
2006     ret = WinHttpSetOption(req, WINHTTP_OPTION_USERNAME, userW, lstrlenW(userW));
2007     ok(ret, "failed to set username %u\n", GetLastError());
2008
2009     size = sizeof(buffer)/sizeof(WCHAR);
2010     ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size);
2011     ok(ret, "failed to query username %u\n", GetLastError());
2012     ok(!winetest_strcmpW(buffer, userW), "unexpected result %s\n", wine_dbgstr_w(buffer));
2013     ok(size == lstrlenW(userW) * sizeof(WCHAR), "unexpected result %u\n", size);
2014
2015     ret = WinHttpSetOption(req, WINHTTP_OPTION_PASSWORD, passW, lstrlenW(passW));
2016     ok(ret, "failed to set password %u\n", GetLastError());
2017
2018     size = sizeof(buffer)/sizeof(WCHAR);
2019     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size);
2020     ok(ret, "failed to query password %u\n", GetLastError());
2021     ok(!winetest_strcmpW(buffer, passW), "unexpected result %s\n", wine_dbgstr_w(buffer));
2022     ok(size == lstrlenW(passW) * sizeof(WCHAR), "unexpected result %u\n", size);
2023
2024     WinHttpCloseHandle(req);
2025
2026     req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0);
2027     ok(req != NULL, "failed to open a request %u\n", GetLastError());
2028
2029     SetLastError(0xdeadbeef);
2030     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, NULL, NULL);
2031     error = GetLastError();
2032     ok(!ret, "expected failure\n");
2033     ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error);
2034
2035     SetLastError(0xdeadbeef);
2036     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, NULL, passW, NULL);
2037     error = GetLastError();
2038     ok(!ret, "expected failure\n");
2039     ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error);
2040
2041     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, userW, passW, NULL);
2042     ok(ret, "failed to set credentials %u\n", GetLastError());
2043
2044     size = sizeof(buffer)/sizeof(WCHAR);
2045     ret = WinHttpQueryOption(req, WINHTTP_OPTION_USERNAME, &buffer, &size);
2046     ok(ret, "failed to query username %u\n", GetLastError());
2047     todo_wine {
2048     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
2049     ok(!size, "expected 0, got %u\n", size);
2050     }
2051
2052     size = sizeof(buffer)/sizeof(WCHAR);
2053     ret = WinHttpQueryOption(req, WINHTTP_OPTION_PASSWORD, &buffer, &size);
2054     ok(ret, "failed to query password %u\n", GetLastError());
2055     todo_wine {
2056     ok(!buffer[0], "unexpected result %s\n", wine_dbgstr_w(buffer));
2057     ok(!size, "expected 0, got %u\n", size);
2058     }
2059
2060     WinHttpCloseHandle(req);
2061     WinHttpCloseHandle(con);
2062     WinHttpCloseHandle(ses);
2063 }
2064
2065 START_TEST (winhttp)
2066 {
2067     static const WCHAR basicW[] = {'/','b','a','s','i','c',0};
2068     static const WCHAR quitW[] = {'/','q','u','i','t',0};
2069     struct server_info si;
2070     HANDLE thread;
2071     DWORD ret;
2072
2073     test_OpenRequest();
2074     test_SendRequest();
2075     test_WinHttpTimeFromSystemTime();
2076     test_WinHttpTimeToSystemTime();
2077     test_WinHttpAddHeaders();
2078     test_secure_connection();
2079     test_request_parameter_defaults();
2080     test_QueryOption();
2081     test_set_default_proxy_config();
2082     test_empty_headers_param();
2083     test_Timeouts();
2084     test_resolve_timeout();
2085     test_credentials();
2086
2087     si.event = CreateEvent(NULL, 0, 0, NULL);
2088     si.port = 7532;
2089
2090     thread = CreateThread(NULL, 0, server_thread, (LPVOID)&si, 0, NULL);
2091     ok(thread != NULL, "failed to create thread %u\n", GetLastError());
2092
2093     ret = WaitForSingleObject(si.event, 10000);
2094     ok(ret == WAIT_OBJECT_0, "failed to start winhttp test server %u\n", GetLastError());
2095     if (ret != WAIT_OBJECT_0)
2096         return;
2097
2098     test_basic_request(si.port, NULL, basicW);
2099     test_no_headers(si.port);
2100     test_basic_authentication(si.port);
2101
2102     /* send the basic request again to shutdown the server thread */
2103     test_basic_request(si.port, NULL, quitW);
2104
2105     WaitForSingleObject(thread, 3000);
2106 }