* Sync up to trunk head (r64894).
[reactos.git] / dll / win32 / winhttp / session.c
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "winhttp_private.h"
20
21 #include <wincrypt.h>
22 #include <winreg.h>
23 #include <dispex.h>
24 #include <activscp.h>
25
26 #define DEFAULT_RESOLVE_TIMEOUT 0
27 #define DEFAULT_CONNECT_TIMEOUT 20000
28 #define DEFAULT_SEND_TIMEOUT 30000
29 #define DEFAULT_RECEIVE_TIMEOUT 30000
30
31 void set_last_error( DWORD error )
32 {
33 /* FIXME */
34 SetLastError( error );
35 }
36
37 DWORD get_last_error( void )
38 {
39 /* FIXME */
40 return GetLastError();
41 }
42
43 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
44 {
45 TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
46
47 if (hdr->callback && (hdr->notify_mask & status)) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
48 }
49
50 /***********************************************************************
51 * WinHttpCheckPlatform (winhttp.@)
52 */
53 BOOL WINAPI WinHttpCheckPlatform( void )
54 {
55 TRACE("\n");
56 return TRUE;
57 }
58
59 /***********************************************************************
60 * session_destroy (internal)
61 */
62 static void session_destroy( object_header_t *hdr )
63 {
64 session_t *session = (session_t *)hdr;
65 struct list *item, *next;
66 domain_t *domain;
67
68 TRACE("%p\n", session);
69
70 LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
71 {
72 domain = LIST_ENTRY( item, domain_t, entry );
73 delete_domain( domain );
74 }
75 heap_free( session->agent );
76 heap_free( session->proxy_server );
77 heap_free( session->proxy_bypass );
78 heap_free( session->proxy_username );
79 heap_free( session->proxy_password );
80 heap_free( session );
81 #ifdef __REACTOS__
82 WSACleanup();
83 #endif
84 }
85
86 static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
87 {
88 session_t *session = (session_t *)hdr;
89
90 switch (option)
91 {
92 case WINHTTP_OPTION_REDIRECT_POLICY:
93 {
94 if (!buffer || *buflen < sizeof(DWORD))
95 {
96 *buflen = sizeof(DWORD);
97 set_last_error( ERROR_INSUFFICIENT_BUFFER );
98 return FALSE;
99 }
100
101 *(DWORD *)buffer = hdr->redirect_policy;
102 *buflen = sizeof(DWORD);
103 return TRUE;
104 }
105 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
106 *(DWORD *)buffer = session->resolve_timeout;
107 *buflen = sizeof(DWORD);
108 return TRUE;
109 case WINHTTP_OPTION_CONNECT_TIMEOUT:
110 *(DWORD *)buffer = session->connect_timeout;
111 *buflen = sizeof(DWORD);
112 return TRUE;
113 case WINHTTP_OPTION_SEND_TIMEOUT:
114 *(DWORD *)buffer = session->send_timeout;
115 *buflen = sizeof(DWORD);
116 return TRUE;
117 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
118 *(DWORD *)buffer = session->recv_timeout;
119 *buflen = sizeof(DWORD);
120 return TRUE;
121 default:
122 FIXME("unimplemented option %u\n", option);
123 set_last_error( ERROR_INVALID_PARAMETER );
124 return FALSE;
125 }
126 }
127
128 static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
129 {
130 session_t *session = (session_t *)hdr;
131
132 switch (option)
133 {
134 case WINHTTP_OPTION_PROXY:
135 {
136 WINHTTP_PROXY_INFO *pi = buffer;
137
138 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
139 return TRUE;
140 }
141 case WINHTTP_OPTION_REDIRECT_POLICY:
142 {
143 DWORD policy;
144
145 if (buflen != sizeof(policy))
146 {
147 set_last_error( ERROR_INSUFFICIENT_BUFFER );
148 return FALSE;
149 }
150
151 policy = *(DWORD *)buffer;
152 TRACE("0x%x\n", policy);
153 hdr->redirect_policy = policy;
154 return TRUE;
155 }
156 case WINHTTP_OPTION_DISABLE_FEATURE:
157 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
158 return FALSE;
159 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
160 session->resolve_timeout = *(DWORD *)buffer;
161 return TRUE;
162 case WINHTTP_OPTION_CONNECT_TIMEOUT:
163 session->connect_timeout = *(DWORD *)buffer;
164 return TRUE;
165 case WINHTTP_OPTION_SEND_TIMEOUT:
166 session->send_timeout = *(DWORD *)buffer;
167 return TRUE;
168 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
169 session->recv_timeout = *(DWORD *)buffer;
170 return TRUE;
171 case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
172 FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
173 return TRUE;
174 default:
175 FIXME("unimplemented option %u\n", option);
176 set_last_error( ERROR_INVALID_PARAMETER );
177 return FALSE;
178 }
179 }
180
181 static const object_vtbl_t session_vtbl =
182 {
183 session_destroy,
184 session_query_option,
185 session_set_option
186 };
187
188 /***********************************************************************
189 * WinHttpOpen (winhttp.@)
190 */
191 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
192 {
193 session_t *session;
194 HINTERNET handle = NULL;
195 #ifdef __REACTOS__
196 WSADATA wsaData;
197 int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
198 if (error) ERR("WSAStartup failed: %d\n", error);
199 #endif
200
201 TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
202
203 if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
204
205 session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
206 session->hdr.vtbl = &session_vtbl;
207 session->hdr.flags = flags;
208 session->hdr.refs = 1;
209 session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
210 list_init( &session->hdr.children );
211 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
212 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
213 session->send_timeout = DEFAULT_SEND_TIMEOUT;
214 session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
215 list_init( &session->cookie_cache );
216
217 if (agent && !(session->agent = strdupW( agent ))) goto end;
218 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
219 {
220 WINHTTP_PROXY_INFO info;
221
222 WinHttpGetDefaultProxyConfiguration( &info );
223 session->access = info.dwAccessType;
224 if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
225 {
226 GlobalFree( (LPWSTR)info.lpszProxy );
227 GlobalFree( (LPWSTR)info.lpszProxyBypass );
228 goto end;
229 }
230 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
231 {
232 GlobalFree( (LPWSTR)info.lpszProxy );
233 GlobalFree( (LPWSTR)info.lpszProxyBypass );
234 goto end;
235 }
236 }
237 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
238 {
239 session->access = access;
240 if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
241 if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
242 }
243
244 if (!(handle = alloc_handle( &session->hdr ))) goto end;
245 session->hdr.handle = handle;
246
247 end:
248 release_object( &session->hdr );
249 TRACE("returning %p\n", handle);
250 return handle;
251 }
252
253 /***********************************************************************
254 * connect_destroy (internal)
255 */
256 static void connect_destroy( object_header_t *hdr )
257 {
258 connect_t *connect = (connect_t *)hdr;
259
260 TRACE("%p\n", connect);
261
262 release_object( &connect->session->hdr );
263
264 heap_free( connect->hostname );
265 heap_free( connect->servername );
266 heap_free( connect->username );
267 heap_free( connect->password );
268 heap_free( connect );
269 }
270
271 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
272 {
273 connect_t *connect = (connect_t *)hdr;
274
275 switch (option)
276 {
277 case WINHTTP_OPTION_PARENT_HANDLE:
278 {
279 if (!buffer || *buflen < sizeof(HINTERNET))
280 {
281 *buflen = sizeof(HINTERNET);
282 set_last_error( ERROR_INSUFFICIENT_BUFFER );
283 return FALSE;
284 }
285
286 *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
287 *buflen = sizeof(HINTERNET);
288 return TRUE;
289 }
290 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
291 *(DWORD *)buffer = connect->session->resolve_timeout;
292 *buflen = sizeof(DWORD);
293 return TRUE;
294 case WINHTTP_OPTION_CONNECT_TIMEOUT:
295 *(DWORD *)buffer = connect->session->connect_timeout;
296 *buflen = sizeof(DWORD);
297 return TRUE;
298 case WINHTTP_OPTION_SEND_TIMEOUT:
299 *(DWORD *)buffer = connect->session->send_timeout;
300 *buflen = sizeof(DWORD);
301 return TRUE;
302 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
303 *(DWORD *)buffer = connect->session->recv_timeout;
304 *buflen = sizeof(DWORD);
305 return TRUE;
306 default:
307 FIXME("unimplemented option %u\n", option);
308 set_last_error( ERROR_INVALID_PARAMETER );
309 return FALSE;
310 }
311 }
312
313 static const object_vtbl_t connect_vtbl =
314 {
315 connect_destroy,
316 connect_query_option,
317 NULL
318 };
319
320 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
321 {
322 static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
323 BOOL ret = FALSE;
324
325 if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
326 ret = TRUE;
327 else if (*domain == '*')
328 {
329 if (domain[1] == '.')
330 {
331 LPCWSTR dot;
332
333 /* For a hostname to match a wildcard, the last domain must match
334 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
335 * hostname is www.foo.a.b, it matches, but a.b does not.
336 */
337 dot = strchrW( server, '.' );
338 if (dot)
339 {
340 int len = strlenW( dot + 1 );
341
342 if (len > strlenW( domain + 2 ))
343 {
344 LPCWSTR ptr;
345
346 /* The server's domain is longer than the wildcard, so it
347 * could be a subdomain. Compare the last portion of the
348 * server's domain.
349 */
350 ptr = dot + len + 1 - strlenW( domain + 2 );
351 if (!strcmpiW( ptr, domain + 2 ))
352 {
353 /* This is only a match if the preceding character is
354 * a '.', i.e. that it is a matching domain. E.g.
355 * if domain is '*.b.c' and server is 'www.ab.c' they
356 * do not match.
357 */
358 ret = *(ptr - 1) == '.';
359 }
360 }
361 else
362 ret = !strcmpiW( dot + 1, domain + 2 );
363 }
364 }
365 }
366 else
367 ret = !strcmpiW( server, domain );
368 return ret;
369 }
370
371 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
372 #define MAX_HOST_NAME_LENGTH 256
373
374 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
375 {
376 LPCWSTR ptr;
377 BOOL ret = FALSE;
378
379 if (!session->proxy_bypass) return FALSE;
380 ptr = session->proxy_bypass;
381 do {
382 LPCWSTR tmp = ptr;
383
384 ptr = strchrW( ptr, ';' );
385 if (!ptr)
386 ptr = strchrW( tmp, ' ' );
387 if (ptr)
388 {
389 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
390 {
391 WCHAR domain[MAX_HOST_NAME_LENGTH];
392
393 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
394 domain[ptr - tmp] = 0;
395 ret = domain_matches( server, domain );
396 }
397 ptr += 1;
398 }
399 else if (*tmp)
400 ret = domain_matches( server, tmp );
401 } while (ptr && !ret);
402 return ret;
403 }
404
405 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
406 {
407 session_t *session = connect->session;
408 BOOL ret = TRUE;
409
410 if (session->proxy_server && !should_bypass_proxy(session, server))
411 {
412 LPCWSTR colon;
413
414 if ((colon = strchrW( session->proxy_server, ':' )))
415 {
416 if (!connect->servername || strncmpiW( connect->servername,
417 session->proxy_server, colon - session->proxy_server - 1 ))
418 {
419 heap_free( connect->servername );
420 connect->resolved = FALSE;
421 if (!(connect->servername = heap_alloc(
422 (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
423 {
424 ret = FALSE;
425 goto end;
426 }
427 memcpy( connect->servername, session->proxy_server,
428 (colon - session->proxy_server) * sizeof(WCHAR) );
429 connect->servername[colon - session->proxy_server] = 0;
430 if (*(colon + 1))
431 connect->serverport = atoiW( colon + 1 );
432 else
433 connect->serverport = INTERNET_DEFAULT_PORT;
434 }
435 }
436 else
437 {
438 if (!connect->servername || strcmpiW( connect->servername,
439 session->proxy_server ))
440 {
441 heap_free( connect->servername );
442 connect->resolved = FALSE;
443 if (!(connect->servername = strdupW( session->proxy_server )))
444 {
445 ret = FALSE;
446 goto end;
447 }
448 connect->serverport = INTERNET_DEFAULT_PORT;
449 }
450 }
451 }
452 else if (server)
453 {
454 heap_free( connect->servername );
455 connect->resolved = FALSE;
456 if (!(connect->servername = strdupW( server )))
457 {
458 ret = FALSE;
459 goto end;
460 }
461 connect->serverport = port;
462 }
463 end:
464 return ret;
465 }
466
467 /***********************************************************************
468 * WinHttpConnect (winhttp.@)
469 */
470 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
471 {
472 connect_t *connect;
473 session_t *session;
474 HINTERNET hconnect = NULL;
475
476 TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
477
478 if (!server)
479 {
480 set_last_error( ERROR_INVALID_PARAMETER );
481 return NULL;
482 }
483 if (!(session = (session_t *)grab_object( hsession )))
484 {
485 set_last_error( ERROR_INVALID_HANDLE );
486 return NULL;
487 }
488 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
489 {
490 release_object( &session->hdr );
491 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
492 return NULL;
493 }
494 if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
495 {
496 release_object( &session->hdr );
497 return NULL;
498 }
499 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
500 connect->hdr.vtbl = &connect_vtbl;
501 connect->hdr.refs = 1;
502 connect->hdr.flags = session->hdr.flags;
503 connect->hdr.callback = session->hdr.callback;
504 connect->hdr.notify_mask = session->hdr.notify_mask;
505 connect->hdr.context = session->hdr.context;
506 connect->hdr.redirect_policy = session->hdr.redirect_policy;
507 list_init( &connect->hdr.children );
508
509 addref_object( &session->hdr );
510 connect->session = session;
511 list_add_head( &session->hdr.children, &connect->hdr.entry );
512
513 if (!(connect->hostname = strdupW( server ))) goto end;
514 connect->hostport = port;
515 if (!set_server_for_hostname( connect, server, port )) goto end;
516
517 if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
518 connect->hdr.handle = hconnect;
519
520 send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
521
522 end:
523 release_object( &connect->hdr );
524 release_object( &session->hdr );
525 TRACE("returning %p\n", hconnect);
526 return hconnect;
527 }
528
529 /***********************************************************************
530 * request_destroy (internal)
531 */
532 static void request_destroy( object_header_t *hdr )
533 {
534 request_t *request = (request_t *)hdr;
535 unsigned int i;
536
537 TRACE("%p\n", request);
538
539 release_object( &request->connect->hdr );
540
541 destroy_authinfo( request->authinfo );
542 destroy_authinfo( request->proxy_authinfo );
543
544 heap_free( request->verb );
545 heap_free( request->path );
546 heap_free( request->version );
547 heap_free( request->raw_headers );
548 heap_free( request->status_text );
549 for (i = 0; i < request->num_headers; i++)
550 {
551 heap_free( request->headers[i].field );
552 heap_free( request->headers[i].value );
553 }
554 heap_free( request->headers );
555 for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
556 heap_free( request->accept_types );
557 heap_free( request );
558 }
559
560 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
561 {
562 int len = 0;
563 if (str) len = strlenW( str );
564 if (buffer && *buflen > len)
565 {
566 if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
567 buffer[len] = 0;
568 }
569 *buflen = len * sizeof(WCHAR);
570 }
571
572 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
573 {
574 WCHAR *ret;
575 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
576
577 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
578 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
579 CertNameToStrW( encoding, blob, format, ret, size );
580
581 return ret;
582 }
583
584 static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
585 {
586 #if !defined(__MINGW32__) && !defined(_MSC_VER)
587 switch (addr->sa_family)
588 {
589 case AF_INET:
590 {
591 const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
592 struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
593 char *p;
594
595 addr_win->sin_family = WS_AF_INET;
596 addr_win->sin_port = addr_unix->sin_port;
597 memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
598 p = (char *)&addr_win->sin_addr + 4;
599 memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
600 return TRUE;
601 }
602 case AF_INET6:
603 {
604 const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
605 struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
606
607 addr_win->sin6_family = WS_AF_INET6;
608 addr_win->sin6_port = addr_unix->sin6_port;
609 addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
610 memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
611 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
612 addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
613 #else
614 addr_win->sin6_scope_id = 0;
615 #endif
616 memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
617 return TRUE;
618 }
619 default:
620 ERR("unhandled family %u\n", addr->sa_family);
621 return FALSE;
622 }
623 #else
624 switch (addr->sa_family)
625 {
626 case AF_INET:
627 {
628 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
629
630 memcpy( addr_in, addr, sizeof(*addr_in) );
631 memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
632 return TRUE;
633 }
634 case AF_INET6:
635 {
636 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
637
638 memcpy( addr_in6, addr, sizeof(*addr_in6) );
639 memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
640 return TRUE;
641 }
642 default:
643 ERR("unhandled family %u\n", addr->sa_family);
644 return FALSE;
645 }
646 #endif
647 }
648
649 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
650 {
651 request_t *request = (request_t *)hdr;
652
653 switch (option)
654 {
655 case WINHTTP_OPTION_SECURITY_FLAGS:
656 {
657 DWORD flags;
658 int bits;
659
660 if (!buffer || *buflen < sizeof(flags))
661 {
662 *buflen = sizeof(flags);
663 set_last_error( ERROR_INSUFFICIENT_BUFFER );
664 return FALSE;
665 }
666
667 flags = 0;
668 if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
669 flags |= request->netconn.security_flags;
670 bits = netconn_get_cipher_strength( &request->netconn );
671 if (bits >= 128)
672 flags |= SECURITY_FLAG_STRENGTH_STRONG;
673 else if (bits >= 56)
674 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
675 else
676 flags |= SECURITY_FLAG_STRENGTH_WEAK;
677 *(DWORD *)buffer = flags;
678 *buflen = sizeof(flags);
679 return TRUE;
680 }
681 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
682 {
683 const CERT_CONTEXT *cert;
684
685 if (!buffer || *buflen < sizeof(cert))
686 {
687 *buflen = sizeof(cert);
688 set_last_error( ERROR_INSUFFICIENT_BUFFER );
689 return FALSE;
690 }
691
692 if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
693 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
694 *buflen = sizeof(cert);
695 return TRUE;
696 }
697 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
698 {
699 const CERT_CONTEXT *cert;
700 const CRYPT_OID_INFO *oidInfo;
701 WINHTTP_CERTIFICATE_INFO *ci = buffer;
702
703 FIXME("partial stub\n");
704
705 if (!buffer || *buflen < sizeof(*ci))
706 {
707 *buflen = sizeof(*ci);
708 set_last_error( ERROR_INSUFFICIENT_BUFFER );
709 return FALSE;
710 }
711 if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
712
713 ci->ftExpiry = cert->pCertInfo->NotAfter;
714 ci->ftStart = cert->pCertInfo->NotBefore;
715 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
716 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
717 ci->lpszProtocolName = NULL;
718 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
719 cert->pCertInfo->SignatureAlgorithm.pszObjId,
720 0 );
721 if (oidInfo)
722 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
723 else
724 ci->lpszSignatureAlgName = NULL;
725 ci->lpszEncryptionAlgName = NULL;
726 ci->dwKeySize = netconn_get_cipher_strength( &request->netconn );
727
728 CertFreeCertificateContext( cert );
729 *buflen = sizeof(*ci);
730 return TRUE;
731 }
732 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
733 {
734 if (!buffer || *buflen < sizeof(DWORD))
735 {
736 *buflen = sizeof(DWORD);
737 set_last_error( ERROR_INSUFFICIENT_BUFFER );
738 return FALSE;
739 }
740
741 *(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn );
742 *buflen = sizeof(DWORD);
743 return TRUE;
744 }
745 case WINHTTP_OPTION_CONNECTION_INFO:
746 {
747 WINHTTP_CONNECTION_INFO *info = buffer;
748 struct sockaddr local;
749 socklen_t len = sizeof(local);
750 const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
751
752 if (!buffer || *buflen < sizeof(*info))
753 {
754 *buflen = sizeof(*info);
755 set_last_error( ERROR_INSUFFICIENT_BUFFER );
756 return FALSE;
757 }
758 if (!netconn_connected( &request->netconn ))
759 {
760 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
761 return FALSE;
762 }
763 if (getsockname( request->netconn.socket, &local, &len )) return FALSE;
764 if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
765 if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
766 info->cbSize = sizeof(*info);
767 return TRUE;
768 }
769 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
770 *(DWORD *)buffer = request->resolve_timeout;
771 *buflen = sizeof(DWORD);
772 return TRUE;
773 case WINHTTP_OPTION_CONNECT_TIMEOUT:
774 *(DWORD *)buffer = request->connect_timeout;
775 *buflen = sizeof(DWORD);
776 return TRUE;
777 case WINHTTP_OPTION_SEND_TIMEOUT:
778 *(DWORD *)buffer = request->send_timeout;
779 *buflen = sizeof(DWORD);
780 return TRUE;
781 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
782 *(DWORD *)buffer = request->recv_timeout;
783 *buflen = sizeof(DWORD);
784 return TRUE;
785
786 case WINHTTP_OPTION_USERNAME:
787 str_to_buffer( buffer, request->connect->username, buflen );
788 return TRUE;
789
790 case WINHTTP_OPTION_PASSWORD:
791 str_to_buffer( buffer, request->connect->password, buflen );
792 return TRUE;
793
794 case WINHTTP_OPTION_PROXY_USERNAME:
795 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
796 return TRUE;
797
798 case WINHTTP_OPTION_PROXY_PASSWORD:
799 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
800 return TRUE;
801
802 default:
803 FIXME("unimplemented option %u\n", option);
804 set_last_error( ERROR_INVALID_PARAMETER );
805 return FALSE;
806 }
807 }
808
809 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
810 {
811 WCHAR *ret;
812 if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
813 {
814 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
815 ret[buflen] = 0;
816 return ret;
817 }
818 set_last_error( ERROR_OUTOFMEMORY );
819 return NULL;
820 }
821
822 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
823 {
824 request_t *request = (request_t *)hdr;
825
826 switch (option)
827 {
828 case WINHTTP_OPTION_PROXY:
829 {
830 WINHTTP_PROXY_INFO *pi = buffer;
831
832 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
833 return TRUE;
834 }
835 case WINHTTP_OPTION_DISABLE_FEATURE:
836 {
837 DWORD disable;
838
839 if (buflen != sizeof(DWORD))
840 {
841 set_last_error( ERROR_INSUFFICIENT_BUFFER );
842 return FALSE;
843 }
844
845 disable = *(DWORD *)buffer;
846 TRACE("0x%x\n", disable);
847 hdr->disable_flags |= disable;
848 return TRUE;
849 }
850 case WINHTTP_OPTION_AUTOLOGON_POLICY:
851 {
852 DWORD policy;
853
854 if (buflen != sizeof(DWORD))
855 {
856 set_last_error( ERROR_INSUFFICIENT_BUFFER );
857 return FALSE;
858 }
859
860 policy = *(DWORD *)buffer;
861 TRACE("0x%x\n", policy);
862 hdr->logon_policy = policy;
863 return TRUE;
864 }
865 case WINHTTP_OPTION_REDIRECT_POLICY:
866 {
867 DWORD policy;
868
869 if (buflen != sizeof(DWORD))
870 {
871 set_last_error( ERROR_INSUFFICIENT_BUFFER );
872 return FALSE;
873 }
874
875 policy = *(DWORD *)buffer;
876 TRACE("0x%x\n", policy);
877 hdr->redirect_policy = policy;
878 return TRUE;
879 }
880 case WINHTTP_OPTION_SECURITY_FLAGS:
881 {
882 DWORD flags;
883
884 if (buflen < sizeof(DWORD))
885 {
886 set_last_error( ERROR_INSUFFICIENT_BUFFER );
887 return FALSE;
888 }
889 flags = *(DWORD *)buffer;
890 TRACE("0x%x\n", flags);
891 if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
892 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
893 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
894 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
895 {
896 set_last_error( ERROR_INVALID_PARAMETER );
897 return FALSE;
898 }
899 request->netconn.security_flags = flags;
900 return TRUE;
901 }
902 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
903 request->resolve_timeout = *(DWORD *)buffer;
904 return TRUE;
905 case WINHTTP_OPTION_CONNECT_TIMEOUT:
906 request->connect_timeout = *(DWORD *)buffer;
907 return TRUE;
908 case WINHTTP_OPTION_SEND_TIMEOUT:
909 request->send_timeout = *(DWORD *)buffer;
910 return TRUE;
911 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
912 request->recv_timeout = *(DWORD *)buffer;
913 return TRUE;
914
915 case WINHTTP_OPTION_USERNAME:
916 {
917 connect_t *connect = request->connect;
918
919 heap_free( connect->username );
920 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
921 return TRUE;
922 }
923 case WINHTTP_OPTION_PASSWORD:
924 {
925 connect_t *connect = request->connect;
926
927 heap_free( connect->password );
928 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
929 return TRUE;
930 }
931 case WINHTTP_OPTION_PROXY_USERNAME:
932 {
933 session_t *session = request->connect->session;
934
935 heap_free( session->proxy_username );
936 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
937 return TRUE;
938 }
939 case WINHTTP_OPTION_PROXY_PASSWORD:
940 {
941 session_t *session = request->connect->session;
942
943 heap_free( session->proxy_password );
944 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
945 return TRUE;
946 }
947 default:
948 FIXME("unimplemented option %u\n", option);
949 set_last_error( ERROR_INVALID_PARAMETER );
950 return TRUE;
951 }
952 }
953
954 static const object_vtbl_t request_vtbl =
955 {
956 request_destroy,
957 request_query_option,
958 request_set_option
959 };
960
961 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
962 {
963 const WCHAR **types = accept_types;
964 DWORD i;
965
966 if (!types) return TRUE;
967 while (*types)
968 {
969 request->num_accept_types++;
970 types++;
971 }
972 if (!request->num_accept_types) return TRUE;
973 if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
974 {
975 request->num_accept_types = 0;
976 return FALSE;
977 }
978 types = accept_types;
979 for (i = 0; i < request->num_accept_types; i++)
980 {
981 if (!(request->accept_types[i] = strdupW( *types )))
982 {
983 for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
984 heap_free( request->accept_types );
985 request->accept_types = NULL;
986 request->num_accept_types = 0;
987 return FALSE;
988 }
989 types++;
990 }
991 return TRUE;
992 }
993
994 /***********************************************************************
995 * WinHttpOpenRequest (winhttp.@)
996 */
997 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
998 LPCWSTR referrer, LPCWSTR *types, DWORD flags )
999 {
1000 request_t *request;
1001 connect_t *connect;
1002 HINTERNET hrequest = NULL;
1003
1004 TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
1005 debugstr_w(version), debugstr_w(referrer), types, flags);
1006
1007 if(types && TRACE_ON(winhttp)) {
1008 const WCHAR **iter;
1009
1010 TRACE("accept types:\n");
1011 for(iter = types; *iter; iter++)
1012 TRACE(" %s\n", debugstr_w(*iter));
1013 }
1014
1015 if (!(connect = (connect_t *)grab_object( hconnect )))
1016 {
1017 set_last_error( ERROR_INVALID_HANDLE );
1018 return NULL;
1019 }
1020 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1021 {
1022 release_object( &connect->hdr );
1023 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1024 return NULL;
1025 }
1026 if (!(request = heap_alloc_zero( sizeof(request_t) )))
1027 {
1028 release_object( &connect->hdr );
1029 return NULL;
1030 }
1031 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1032 request->hdr.vtbl = &request_vtbl;
1033 request->hdr.refs = 1;
1034 request->hdr.flags = flags;
1035 request->hdr.callback = connect->hdr.callback;
1036 request->hdr.notify_mask = connect->hdr.notify_mask;
1037 request->hdr.context = connect->hdr.context;
1038 request->hdr.redirect_policy = connect->hdr.redirect_policy;
1039 list_init( &request->hdr.children );
1040
1041 addref_object( &connect->hdr );
1042 request->connect = connect;
1043 list_add_head( &connect->hdr.children, &request->hdr.entry );
1044
1045 if (!netconn_init( &request->netconn )) goto end;
1046 request->resolve_timeout = connect->session->resolve_timeout;
1047 request->connect_timeout = connect->session->connect_timeout;
1048 request->send_timeout = connect->session->send_timeout;
1049 request->recv_timeout = connect->session->recv_timeout;
1050
1051 if (!verb || !verb[0]) verb = getW;
1052 if (!(request->verb = strdupW( verb ))) goto end;
1053
1054 if (object)
1055 {
1056 WCHAR *path, *p;
1057 unsigned int len;
1058
1059 len = strlenW( object ) + 1;
1060 if (object[0] != '/') len++;
1061 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
1062
1063 if (object[0] != '/') *p++ = '/';
1064 strcpyW( p, object );
1065 request->path = path;
1066 }
1067 else if (!(request->path = strdupW( slashW ))) goto end;
1068
1069 if (!version || !version[0]) version = http1_1;
1070 if (!(request->version = strdupW( version ))) goto end;
1071 if (!(store_accept_types( request, types ))) goto end;
1072
1073 if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
1074 request->hdr.handle = hrequest;
1075
1076 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1077
1078 end:
1079 release_object( &request->hdr );
1080 release_object( &connect->hdr );
1081 TRACE("returning %p\n", hrequest);
1082 return hrequest;
1083 }
1084
1085 /***********************************************************************
1086 * WinHttpCloseHandle (winhttp.@)
1087 */
1088 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1089 {
1090 object_header_t *hdr;
1091
1092 TRACE("%p\n", handle);
1093
1094 if (!(hdr = grab_object( handle )))
1095 {
1096 set_last_error( ERROR_INVALID_HANDLE );
1097 return FALSE;
1098 }
1099 release_object( hdr );
1100 free_handle( handle );
1101 return TRUE;
1102 }
1103
1104 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1105 {
1106 BOOL ret = FALSE;
1107
1108 if (!buflen)
1109 {
1110 set_last_error( ERROR_INVALID_PARAMETER );
1111 return FALSE;
1112 }
1113
1114 switch (option)
1115 {
1116 case WINHTTP_OPTION_CONTEXT_VALUE:
1117 {
1118 if (!buffer || *buflen < sizeof(DWORD_PTR))
1119 {
1120 *buflen = sizeof(DWORD_PTR);
1121 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1122 return FALSE;
1123 }
1124
1125 *(DWORD_PTR *)buffer = hdr->context;
1126 *buflen = sizeof(DWORD_PTR);
1127 return TRUE;
1128 }
1129 default:
1130 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1131 else
1132 {
1133 FIXME("unimplemented option %u\n", option);
1134 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1135 return FALSE;
1136 }
1137 break;
1138 }
1139 return ret;
1140 }
1141
1142 /***********************************************************************
1143 * WinHttpQueryOption (winhttp.@)
1144 */
1145 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1146 {
1147 BOOL ret = FALSE;
1148 object_header_t *hdr;
1149
1150 TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1151
1152 if (!(hdr = grab_object( handle )))
1153 {
1154 set_last_error( ERROR_INVALID_HANDLE );
1155 return FALSE;
1156 }
1157
1158 ret = query_option( hdr, option, buffer, buflen );
1159
1160 release_object( hdr );
1161 return ret;
1162 }
1163
1164 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1165 {
1166 BOOL ret = TRUE;
1167
1168 if (!buffer)
1169 {
1170 set_last_error( ERROR_INVALID_PARAMETER );
1171 return FALSE;
1172 }
1173
1174 switch (option)
1175 {
1176 case WINHTTP_OPTION_CONTEXT_VALUE:
1177 {
1178 if (buflen != sizeof(DWORD_PTR))
1179 {
1180 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1181 return FALSE;
1182 }
1183
1184 hdr->context = *(DWORD_PTR *)buffer;
1185 return TRUE;
1186 }
1187 default:
1188 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1189 else
1190 {
1191 FIXME("unimplemented option %u\n", option);
1192 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1193 return FALSE;
1194 }
1195 break;
1196 }
1197 return ret;
1198 }
1199
1200 /***********************************************************************
1201 * WinHttpSetOption (winhttp.@)
1202 */
1203 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1204 {
1205 BOOL ret = FALSE;
1206 object_header_t *hdr;
1207
1208 TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1209
1210 if (!(hdr = grab_object( handle )))
1211 {
1212 set_last_error( ERROR_INVALID_HANDLE );
1213 return FALSE;
1214 }
1215
1216 ret = set_option( hdr, option, buffer, buflen );
1217
1218 release_object( hdr );
1219 return ret;
1220 }
1221
1222 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1223 {
1224 char *ret;
1225 DWORD size = 0;
1226
1227 GetComputerNameExA( format, NULL, &size );
1228 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1229 if (!(ret = heap_alloc( size ))) return NULL;
1230 if (!GetComputerNameExA( format, ret, &size ))
1231 {
1232 heap_free( ret );
1233 return NULL;
1234 }
1235 return ret;
1236 }
1237
1238 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1239 {
1240 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1241
1242 if (len_suffix > len_domain) return FALSE;
1243 if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1244 return FALSE;
1245 }
1246
1247 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1248 {
1249 int ret = -1;
1250 #ifdef HAVE_GETNAMEINFO
1251 ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1252 #endif
1253 return ret;
1254 }
1255
1256 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1257 {
1258 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1259 static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
1260 char name[NI_MAXHOST];
1261 WCHAR *ret, *p;
1262 int len;
1263
1264 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1265 if (!ai) return NULL;
1266
1267 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1268
1269 len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
1270 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1271 strcpyW( p, httpW );
1272 p += strlenW( httpW );
1273 while (*hostname) { *p++ = *hostname++; }
1274 strcpyW( p, wpadW );
1275 return ret;
1276 }
1277
1278 static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen )
1279 {
1280 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1281 CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
1282 const void *ref;
1283 BOOL ret = FALSE;
1284
1285 if (!settings) return FALSE;
1286
1287 if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
1288 {
1289 CFRelease( settings );
1290 return FALSE;
1291 }
1292 if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII ))
1293 {
1294 TRACE( "returning %s\n", debugstr_a(buf) );
1295 ret = TRUE;
1296 }
1297 CFRelease( settings );
1298 return ret;
1299 #else
1300 FIXME( "no support on this platform\n" );
1301 return FALSE;
1302 #endif
1303 }
1304
1305 #define INTERNET_MAX_URL_LENGTH 2084
1306
1307 /***********************************************************************
1308 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1309 */
1310 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1311 {
1312 BOOL ret = FALSE;
1313 char system_url[INTERNET_MAX_URL_LENGTH + 1];
1314
1315 TRACE("0x%08x, %p\n", flags, url);
1316
1317 if (!flags || !url)
1318 {
1319 set_last_error( ERROR_INVALID_PARAMETER );
1320 return FALSE;
1321 }
1322 if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) ))
1323 {
1324 WCHAR *urlW;
1325
1326 if (!(urlW = strdupAW( system_url ))) return FALSE;
1327 *url = urlW;
1328 return TRUE;
1329 }
1330 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1331 {
1332 static int fixme_shown;
1333 if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
1334 }
1335 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1336 {
1337 #ifdef HAVE_GETADDRINFO
1338 char *fqdn, *domain, *p;
1339
1340 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1341 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1342 {
1343 heap_free( fqdn );
1344 return FALSE;
1345 }
1346 p = fqdn;
1347 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1348 {
1349 struct addrinfo *ai;
1350 char *name;
1351 int res;
1352
1353 if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1354 {
1355 heap_free( fqdn );
1356 heap_free( domain );
1357 return FALSE;
1358 }
1359 strcpy( name, "wpad" );
1360 strcat( name, p );
1361 res = getaddrinfo( name, NULL, NULL, &ai );
1362 if (!res)
1363 {
1364 *url = build_wpad_url( name, ai );
1365 freeaddrinfo( ai );
1366 if (*url)
1367 {
1368 TRACE("returning %s\n", debugstr_w(*url));
1369 heap_free( name );
1370 ret = TRUE;
1371 break;
1372 }
1373 }
1374 heap_free( name );
1375 p++;
1376 }
1377 heap_free( domain );
1378 heap_free( fqdn );
1379 #else
1380 FIXME("getaddrinfo not found at build time\n");
1381 #endif
1382 }
1383 if (!ret)
1384 {
1385 set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1386 *url = NULL;
1387 }
1388 return ret;
1389 }
1390
1391 static const WCHAR Connections[] = {
1392 'S','o','f','t','w','a','r','e','\\',
1393 'M','i','c','r','o','s','o','f','t','\\',
1394 'W','i','n','d','o','w','s','\\',
1395 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1396 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1397 'C','o','n','n','e','c','t','i','o','n','s',0 };
1398 static const WCHAR WinHttpSettings[] = {
1399 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1400 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1401 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1402 static const DWORD PROXY_TYPE_DIRECT = 1;
1403 static const DWORD PROXY_TYPE_PROXY = 2;
1404 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1405 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1406
1407 struct connection_settings_header
1408 {
1409 DWORD magic;
1410 DWORD unknown; /* always zero? */
1411 DWORD flags; /* one or more of PROXY_* */
1412 };
1413
1414 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1415 {
1416 const BYTE *begin;
1417
1418 for (begin = src; src - begin < len; src++, dst++)
1419 *dst = *src;
1420 *dst = 0;
1421 }
1422
1423 /***********************************************************************
1424 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1425 */
1426 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1427 {
1428 LONG l;
1429 HKEY key;
1430 BOOL got_from_reg = FALSE, direct = TRUE;
1431 char *envproxy;
1432
1433 TRACE("%p\n", info);
1434
1435 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1436 if (!l)
1437 {
1438 DWORD type, size = 0;
1439
1440 l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1441 if (!l && type == REG_BINARY &&
1442 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1443 {
1444 BYTE *buf = heap_alloc( size );
1445
1446 if (buf)
1447 {
1448 struct connection_settings_header *hdr =
1449 (struct connection_settings_header *)buf;
1450 DWORD *len = (DWORD *)(hdr + 1);
1451
1452 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1453 &size );
1454 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1455 hdr->unknown == 0)
1456 {
1457 if (hdr->flags & PROXY_TYPE_PROXY)
1458 {
1459 BOOL sane = FALSE;
1460 LPWSTR proxy = NULL;
1461 LPWSTR proxy_bypass = NULL;
1462
1463 /* Sanity-check length of proxy string */
1464 if ((BYTE *)len - buf + *len <= size)
1465 {
1466 sane = TRUE;
1467 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1468 if (proxy)
1469 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1470 len = (DWORD *)((BYTE *)(len + 1) + *len);
1471 }
1472 if (sane)
1473 {
1474 /* Sanity-check length of proxy bypass string */
1475 if ((BYTE *)len - buf + *len <= size)
1476 {
1477 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1478 if (proxy_bypass)
1479 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1480 }
1481 else
1482 {
1483 sane = FALSE;
1484 GlobalFree( proxy );
1485 proxy = NULL;
1486 }
1487 }
1488 info->lpszProxy = proxy;
1489 info->lpszProxyBypass = proxy_bypass;
1490 if (sane)
1491 {
1492 got_from_reg = TRUE;
1493 direct = FALSE;
1494 info->dwAccessType =
1495 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1496 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1497 debugstr_w(info->lpszProxy),
1498 debugstr_w(info->lpszProxyBypass));
1499 }
1500 }
1501 }
1502 heap_free( buf );
1503 }
1504 }
1505 RegCloseKey( key );
1506 }
1507 if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1508 {
1509 char *colon, *http_proxy;
1510
1511 if ((colon = strchr( envproxy, ':' )))
1512 {
1513 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1514 {
1515 static const char http[] = "http://";
1516
1517 /* It's a scheme, check that it's http */
1518 if (!strncmp( envproxy, http, strlen( http ) ))
1519 http_proxy = envproxy + strlen( http );
1520 else
1521 {
1522 WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1523 http_proxy = NULL;
1524 }
1525 }
1526 else
1527 http_proxy = envproxy;
1528 }
1529 else
1530 http_proxy = envproxy;
1531 if (http_proxy)
1532 {
1533 WCHAR *http_proxyW;
1534 int len;
1535
1536 len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1537 if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1538 {
1539 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1540 direct = FALSE;
1541 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1542 info->lpszProxy = http_proxyW;
1543 info->lpszProxyBypass = NULL;
1544 TRACE("http proxy (from environment) = %s\n",
1545 debugstr_w(info->lpszProxy));
1546 }
1547 }
1548 }
1549 if (direct)
1550 {
1551 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1552 info->lpszProxy = NULL;
1553 info->lpszProxyBypass = NULL;
1554 }
1555 return TRUE;
1556 }
1557
1558 /***********************************************************************
1559 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1560 */
1561 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1562 {
1563 static const WCHAR settingsW[] =
1564 {'D','e','f','a','u','l','t','C','o','n','n','e','c','t','i','o','n','S','e','t','t','i','n','g','s',0};
1565 HKEY hkey = NULL;
1566 struct connection_settings_header *hdr = NULL;
1567 DWORD type, offset, len, size = 0;
1568 BOOL ret = FALSE;
1569
1570 TRACE("%p\n", config);
1571
1572 if (!config)
1573 {
1574 set_last_error( ERROR_INVALID_PARAMETER );
1575 return FALSE;
1576 }
1577 memset( config, 0, sizeof(*config) );
1578 config->fAutoDetect = TRUE;
1579
1580 if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1581 RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1582 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1583 {
1584 ret = TRUE;
1585 goto done;
1586 }
1587 if (!(hdr = heap_alloc( size ))) goto done;
1588 if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1589 hdr->magic != WININET_SETTINGS_MAGIC)
1590 {
1591 ret = TRUE;
1592 goto done;
1593 }
1594
1595 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1596 offset = sizeof(*hdr);
1597 if (offset + sizeof(DWORD) > size) goto done;
1598 len = *(DWORD *)((char *)hdr + offset);
1599 offset += sizeof(DWORD);
1600 if (len && hdr->flags & PROXY_TYPE_PROXY)
1601 {
1602 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1603 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1604 }
1605 offset += len;
1606 if (offset + sizeof(DWORD) > size) goto done;
1607 len = *(DWORD *)((char *)hdr + offset);
1608 offset += sizeof(DWORD);
1609 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1610 {
1611 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1612 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1613 }
1614 offset += len;
1615 if (offset + sizeof(DWORD) > size) goto done;
1616 len = *(DWORD *)((char *)hdr + offset);
1617 offset += sizeof(DWORD);
1618 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1619 {
1620 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1621 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1622 }
1623 ret = TRUE;
1624
1625 done:
1626 RegCloseKey( hkey );
1627 heap_free( hdr );
1628 if (!ret)
1629 {
1630 GlobalFree( config->lpszAutoConfigUrl );
1631 config->lpszAutoConfigUrl = NULL;
1632 GlobalFree( config->lpszProxy );
1633 config->lpszProxy = NULL;
1634 GlobalFree( config->lpszProxyBypass );
1635 config->lpszProxyBypass = NULL;
1636 }
1637 return ret;
1638 }
1639
1640 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1641 {
1642 const char *p;
1643 WCHAR *q;
1644 int len;
1645
1646 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1647 info->lpszProxy = NULL;
1648 info->lpszProxyBypass = NULL;
1649
1650 TRACE("%s\n", debugstr_a( result ));
1651
1652 p = result;
1653 while (*p == ' ') p++;
1654 len = strlen( p );
1655 if (len >= 5 && !strncasecmp( p, "PROXY", sizeof("PROXY") - 1 ))
1656 {
1657 p += 5;
1658 while (*p == ' ') p++;
1659 if (!*p || *p == ';') return TRUE;
1660 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1661 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1662 for (; *q; q++)
1663 {
1664 if (*q == ' ' || *q == ';')
1665 {
1666 *q = 0;
1667 break;
1668 }
1669 }
1670 }
1671 return TRUE;
1672 }
1673
1674 static char *download_script( const WCHAR *url, DWORD *out_size )
1675 {
1676 static const WCHAR typeW[] = {'*','/','*',0};
1677 static const WCHAR *acceptW[] = {typeW, NULL};
1678 HINTERNET ses, con = NULL, req = NULL;
1679 WCHAR *hostname;
1680 URL_COMPONENTSW uc;
1681 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1682 char *tmp, *buffer = NULL;
1683
1684 *out_size = 0;
1685
1686 memset( &uc, 0, sizeof(uc) );
1687 uc.dwStructSize = sizeof(uc);
1688 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1689 if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1690 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1691 hostname[uc.dwHostNameLength] = 0;
1692
1693 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1694 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1695 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1696 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1697 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1698
1699 if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1700 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1701 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1702
1703 size = 4096;
1704 if (!(buffer = heap_alloc( size ))) goto done;
1705 to_read = size;
1706 offset = 0;
1707 for (;;)
1708 {
1709 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1710 if (!bytes_read) break;
1711 to_read -= bytes_read;
1712 offset += bytes_read;
1713 *out_size += bytes_read;
1714 if (!to_read)
1715 {
1716 to_read = size;
1717 size *= 2;
1718 if (!(tmp = heap_realloc( buffer, size ))) goto done;
1719 buffer = tmp;
1720 }
1721 }
1722
1723 done:
1724 WinHttpCloseHandle( req );
1725 WinHttpCloseHandle( con );
1726 WinHttpCloseHandle( ses );
1727 heap_free( hostname );
1728 if (!buffer) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1729 return buffer;
1730 }
1731
1732 struct AUTO_PROXY_SCRIPT_BUFFER
1733 {
1734 DWORD dwStructSize;
1735 LPSTR lpszScriptBuffer;
1736 DWORD dwScriptBufferSize;
1737 };
1738
1739 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1740 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1741 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1742
1743 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1744 {
1745 BOOL ret;
1746 char *result, *urlA;
1747 DWORD len_result;
1748 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1749
1750 buffer.dwStructSize = sizeof(buffer);
1751 buffer.lpszScriptBuffer = script;
1752 buffer.dwScriptBufferSize = size;
1753
1754 if (!(urlA = strdupWA( url ))) return FALSE;
1755 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1756 {
1757 heap_free( urlA );
1758 return FALSE;
1759 }
1760 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA), NULL, 0, &result, &len_result )))
1761 {
1762 ret = parse_script_result( result, info );
1763 heap_free( result );
1764 }
1765 heap_free( urlA );
1766 return InternetDeInitializeAutoProxyDll( NULL, 0 );
1767 }
1768
1769 /***********************************************************************
1770 * WinHttpGetProxyForUrl (winhttp.@)
1771 */
1772 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1773 WINHTTP_PROXY_INFO *info )
1774 {
1775 WCHAR *detected_pac_url = NULL;
1776 const WCHAR *pac_url;
1777 session_t *session;
1778 char *script;
1779 DWORD size;
1780 BOOL ret = FALSE;
1781
1782 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1783
1784 if (!(session = (session_t *)grab_object( hsession )))
1785 {
1786 set_last_error( ERROR_INVALID_HANDLE );
1787 return FALSE;
1788 }
1789 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1790 {
1791 release_object( &session->hdr );
1792 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1793 return FALSE;
1794 }
1795 if (!url || !options || !info ||
1796 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1797 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1798 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1799 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1800 {
1801 release_object( &session->hdr );
1802 set_last_error( ERROR_INVALID_PARAMETER );
1803 return FALSE;
1804 }
1805 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1806 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1807 goto done;
1808
1809 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1810 else pac_url = detected_pac_url;
1811
1812 if ((script = download_script( pac_url, &size )))
1813 {
1814 ret = run_script( script, size, url, info );
1815 heap_free( script );
1816 }
1817
1818 done:
1819 GlobalFree( detected_pac_url );
1820 release_object( &session->hdr );
1821 return ret;
1822 }
1823
1824 /***********************************************************************
1825 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
1826 */
1827 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1828 {
1829 LONG l;
1830 HKEY key;
1831 BOOL ret = FALSE;
1832 const WCHAR *src;
1833
1834 TRACE("%p\n", info);
1835
1836 if (!info)
1837 {
1838 set_last_error( ERROR_INVALID_PARAMETER );
1839 return FALSE;
1840 }
1841 switch (info->dwAccessType)
1842 {
1843 case WINHTTP_ACCESS_TYPE_NO_PROXY:
1844 break;
1845 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1846 if (!info->lpszProxy)
1847 {
1848 set_last_error( ERROR_INVALID_PARAMETER );
1849 return FALSE;
1850 }
1851 /* Only ASCII characters are allowed */
1852 for (src = info->lpszProxy; *src; src++)
1853 if (*src > 0x7f)
1854 {
1855 set_last_error( ERROR_INVALID_PARAMETER );
1856 return FALSE;
1857 }
1858 if (info->lpszProxyBypass)
1859 {
1860 for (src = info->lpszProxyBypass; *src; src++)
1861 if (*src > 0x7f)
1862 {
1863 set_last_error( ERROR_INVALID_PARAMETER );
1864 return FALSE;
1865 }
1866 }
1867 break;
1868 default:
1869 set_last_error( ERROR_INVALID_PARAMETER );
1870 return FALSE;
1871 }
1872
1873 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1874 KEY_WRITE, NULL, &key, NULL );
1875 if (!l)
1876 {
1877 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1878 BYTE *buf;
1879
1880 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1881 {
1882 size += strlenW( info->lpszProxy );
1883 if (info->lpszProxyBypass)
1884 size += strlenW( info->lpszProxyBypass );
1885 }
1886 buf = heap_alloc( size );
1887 if (buf)
1888 {
1889 struct connection_settings_header *hdr =
1890 (struct connection_settings_header *)buf;
1891 DWORD *len = (DWORD *)(hdr + 1);
1892
1893 hdr->magic = WINHTTP_SETTINGS_MAGIC;
1894 hdr->unknown = 0;
1895 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1896 {
1897 BYTE *dst;
1898
1899 hdr->flags = PROXY_TYPE_PROXY;
1900 *len++ = strlenW( info->lpszProxy );
1901 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
1902 src++, dst++)
1903 *dst = *src;
1904 len = (DWORD *)dst;
1905 if (info->lpszProxyBypass)
1906 {
1907 *len++ = strlenW( info->lpszProxyBypass );
1908 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
1909 src++, dst++)
1910 *dst = *src;
1911 }
1912 else
1913 *len++ = 0;
1914 }
1915 else
1916 {
1917 hdr->flags = PROXY_TYPE_DIRECT;
1918 *len++ = 0;
1919 *len++ = 0;
1920 }
1921 l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
1922 if (!l)
1923 ret = TRUE;
1924 heap_free( buf );
1925 }
1926 RegCloseKey( key );
1927 }
1928 return ret;
1929 }
1930
1931 /***********************************************************************
1932 * WinHttpSetStatusCallback (winhttp.@)
1933 */
1934 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
1935 DWORD flags, DWORD_PTR reserved )
1936 {
1937 object_header_t *hdr;
1938 WINHTTP_STATUS_CALLBACK ret;
1939
1940 TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
1941
1942 if (!(hdr = grab_object( handle )))
1943 {
1944 set_last_error( ERROR_INVALID_HANDLE );
1945 return WINHTTP_INVALID_STATUS_CALLBACK;
1946 }
1947 ret = hdr->callback;
1948 hdr->callback = callback;
1949 hdr->notify_mask = flags;
1950
1951 release_object( hdr );
1952 return ret;
1953 }
1954
1955 /***********************************************************************
1956 * WinHttpSetTimeouts (winhttp.@)
1957 */
1958 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
1959 {
1960 BOOL ret = TRUE;
1961 object_header_t *hdr;
1962 request_t *request;
1963 session_t *session;
1964
1965 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
1966
1967 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
1968 {
1969 set_last_error( ERROR_INVALID_PARAMETER );
1970 return FALSE;
1971 }
1972
1973 if (!(hdr = grab_object( handle )))
1974 {
1975 set_last_error( ERROR_INVALID_HANDLE );
1976 return FALSE;
1977 }
1978
1979 switch(hdr->type)
1980 {
1981 case WINHTTP_HANDLE_TYPE_REQUEST:
1982 request = (request_t *)hdr;
1983 request->connect_timeout = connect;
1984
1985 if (resolve < 0) resolve = 0;
1986 request->resolve_timeout = resolve;
1987
1988 if (send < 0) send = 0;
1989 request->send_timeout = send;
1990
1991 if (receive < 0) receive = 0;
1992 request->recv_timeout = receive;
1993
1994 if (netconn_connected( &request->netconn ))
1995 {
1996 if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE;
1997 if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE;
1998 }
1999
2000 release_object( &request->hdr );
2001 break;
2002
2003 case WINHTTP_HANDLE_TYPE_SESSION:
2004 session = (session_t *)hdr;
2005 session->connect_timeout = connect;
2006
2007 if (resolve < 0) resolve = 0;
2008 session->resolve_timeout = resolve;
2009
2010 if (send < 0) send = 0;
2011 session->send_timeout = send;
2012
2013 if (receive < 0) receive = 0;
2014 session->recv_timeout = receive;
2015 break;
2016
2017 default:
2018 release_object( hdr );
2019 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2020 return FALSE;
2021 }
2022 return ret;
2023 }
2024
2025 static const WCHAR wkday[7][4] =
2026 {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2027 {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2028 static const WCHAR month[12][4] =
2029 {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2030 {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2031 {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2032
2033 /***********************************************************************
2034 * WinHttpTimeFromSystemTime (WININET.@)
2035 */
2036 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2037 {
2038 static const WCHAR format[] =
2039 {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2040 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2041
2042 TRACE("%p, %p\n", time, string);
2043
2044 if (!time || !string) return FALSE;
2045
2046 sprintfW( string, format,
2047 wkday[time->wDayOfWeek],
2048 time->wDay,
2049 month[time->wMonth - 1],
2050 time->wYear,
2051 time->wHour,
2052 time->wMinute,
2053 time->wSecond );
2054
2055 return TRUE;
2056 }
2057
2058 /***********************************************************************
2059 * WinHttpTimeToSystemTime (WININET.@)
2060 */
2061 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2062 {
2063 unsigned int i;
2064 const WCHAR *s = string;
2065 WCHAR *end;
2066
2067 TRACE("%s, %p\n", debugstr_w(string), time);
2068
2069 if (!string || !time) return FALSE;
2070
2071 /* Windows does this too */
2072 GetSystemTime( time );
2073
2074 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2075 * a SYSTEMTIME structure.
2076 */
2077
2078 while (*s && !isalphaW( *s )) s++;
2079 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2080 time->wDayOfWeek = 7;
2081
2082 for (i = 0; i < 7; i++)
2083 {
2084 if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2085 toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2086 toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2087 {
2088 time->wDayOfWeek = i;
2089 break;
2090 }
2091 }
2092
2093 if (time->wDayOfWeek > 6) return TRUE;
2094 while (*s && !isdigitW( *s )) s++;
2095 time->wDay = strtolW( s, &end, 10 );
2096 s = end;
2097
2098 while (*s && !isalphaW( *s )) s++;
2099 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2100 time->wMonth = 0;
2101
2102 for (i = 0; i < 12; i++)
2103 {
2104 if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2105 toupperW( month[i][1]) == toupperW( s[1] ) &&
2106 toupperW( month[i][2]) == toupperW( s[2] ) )
2107 {
2108 time->wMonth = i + 1;
2109 break;
2110 }
2111 }
2112 if (time->wMonth == 0) return TRUE;
2113
2114 while (*s && !isdigitW( *s )) s++;
2115 if (*s == '\0') return TRUE;
2116 time->wYear = strtolW( s, &end, 10 );
2117 s = end;
2118
2119 while (*s && !isdigitW( *s )) s++;
2120 if (*s == '\0') return TRUE;
2121 time->wHour = strtolW( s, &end, 10 );
2122 s = end;
2123
2124 while (*s && !isdigitW( *s )) s++;
2125 if (*s == '\0') return TRUE;
2126 time->wMinute = strtolW( s, &end, 10 );
2127 s = end;
2128
2129 while (*s && !isdigitW( *s )) s++;
2130 if (*s == '\0') return TRUE;
2131 time->wSecond = strtolW( s, &end, 10 );
2132
2133 time->wMilliseconds = 0;
2134 return TRUE;
2135 }