winhttp: Allocate a credential handle for each session.
[wine.git] / dlls / winhttp / session.c
bloba448869e3bb0df953235362f8202fd3f65876c40
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
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.
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.
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
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #ifdef HAVE_CORESERVICES_CORESERVICES_H
27 #define GetCurrentThread MacGetCurrentThread
28 #define LoadResource MacLoadResource
29 #include <CoreServices/CoreServices.h>
30 #undef GetCurrentThread
31 #undef LoadResource
32 #undef DPRINTF
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #ifndef __MINGW32__
38 #define USE_WS_PREFIX
39 #endif
40 #include "winsock2.h"
41 #include "ws2ipdef.h"
42 #include "winhttp.h"
43 #include "wincrypt.h"
44 #include "winreg.h"
45 #define COBJMACROS
46 #include "ole2.h"
47 #include "dispex.h"
48 #include "activscp.h"
50 #include "winhttp_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
54 #define DEFAULT_RESOLVE_TIMEOUT 0
55 #define DEFAULT_CONNECT_TIMEOUT 20000
56 #define DEFAULT_SEND_TIMEOUT 30000
57 #define DEFAULT_RECEIVE_TIMEOUT 30000
59 void set_last_error( DWORD error )
61 /* FIXME */
62 SetLastError( error );
65 DWORD get_last_error( void )
67 /* FIXME */
68 return GetLastError();
71 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
73 if (hdr->callback && (hdr->notify_mask & status))
75 TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
76 hdr->callback( hdr->handle, hdr->context, status, info, buflen );
77 TRACE("returning from 0x%08x callback\n", status);
81 /***********************************************************************
82 * WinHttpCheckPlatform (winhttp.@)
84 BOOL WINAPI WinHttpCheckPlatform( void )
86 TRACE("\n");
87 return TRUE;
90 /***********************************************************************
91 * session_destroy (internal)
93 static void session_destroy( object_header_t *hdr )
95 session_t *session = (session_t *)hdr;
96 struct list *item, *next;
97 domain_t *domain;
99 TRACE("%p\n", session);
101 if (session->unload_event) SetEvent( session->unload_event );
102 if (session->cred_handle_initialized) FreeCredentialsHandle( &session->cred_handle );
104 LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
106 domain = LIST_ENTRY( item, domain_t, entry );
107 delete_domain( domain );
109 heap_free( session->agent );
110 heap_free( session->proxy_server );
111 heap_free( session->proxy_bypass );
112 heap_free( session->proxy_username );
113 heap_free( session->proxy_password );
114 heap_free( session );
117 static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
119 session_t *session = (session_t *)hdr;
121 switch (option)
123 case WINHTTP_OPTION_REDIRECT_POLICY:
125 if (!buffer || *buflen < sizeof(DWORD))
127 *buflen = sizeof(DWORD);
128 set_last_error( ERROR_INSUFFICIENT_BUFFER );
129 return FALSE;
132 *(DWORD *)buffer = hdr->redirect_policy;
133 *buflen = sizeof(DWORD);
134 return TRUE;
136 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
137 *(DWORD *)buffer = session->resolve_timeout;
138 *buflen = sizeof(DWORD);
139 return TRUE;
140 case WINHTTP_OPTION_CONNECT_TIMEOUT:
141 *(DWORD *)buffer = session->connect_timeout;
142 *buflen = sizeof(DWORD);
143 return TRUE;
144 case WINHTTP_OPTION_SEND_TIMEOUT:
145 *(DWORD *)buffer = session->send_timeout;
146 *buflen = sizeof(DWORD);
147 return TRUE;
148 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
149 *(DWORD *)buffer = session->recv_timeout;
150 *buflen = sizeof(DWORD);
151 return TRUE;
152 default:
153 FIXME("unimplemented option %u\n", option);
154 set_last_error( ERROR_INVALID_PARAMETER );
155 return FALSE;
159 static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
161 session_t *session = (session_t *)hdr;
163 switch (option)
165 case WINHTTP_OPTION_PROXY:
167 WINHTTP_PROXY_INFO *pi = buffer;
169 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
170 return TRUE;
172 case WINHTTP_OPTION_REDIRECT_POLICY:
174 DWORD policy;
176 if (buflen != sizeof(policy))
178 set_last_error( ERROR_INSUFFICIENT_BUFFER );
179 return FALSE;
182 policy = *(DWORD *)buffer;
183 TRACE("0x%x\n", policy);
184 hdr->redirect_policy = policy;
185 return TRUE;
187 case WINHTTP_OPTION_DISABLE_FEATURE:
188 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
189 return FALSE;
190 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
191 session->resolve_timeout = *(DWORD *)buffer;
192 return TRUE;
193 case WINHTTP_OPTION_CONNECT_TIMEOUT:
194 session->connect_timeout = *(DWORD *)buffer;
195 return TRUE;
196 case WINHTTP_OPTION_SEND_TIMEOUT:
197 session->send_timeout = *(DWORD *)buffer;
198 return TRUE;
199 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
200 session->recv_timeout = *(DWORD *)buffer;
201 return TRUE;
202 case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
203 FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
204 return TRUE;
205 case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
206 TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
207 session->unload_event = *(HANDLE *)buffer;
208 return TRUE;
209 case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
210 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %d\n", *(DWORD *)buffer);
211 return TRUE;
212 case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
213 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %d\n", *(DWORD *)buffer);
214 return TRUE;
215 default:
216 FIXME("unimplemented option %u\n", option);
217 set_last_error( ERROR_INVALID_PARAMETER );
218 return FALSE;
222 static const object_vtbl_t session_vtbl =
224 session_destroy,
225 session_query_option,
226 session_set_option
229 /***********************************************************************
230 * WinHttpOpen (winhttp.@)
232 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
234 session_t *session;
235 HINTERNET handle = NULL;
237 TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
239 if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
241 session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
242 session->hdr.vtbl = &session_vtbl;
243 session->hdr.flags = flags;
244 session->hdr.refs = 1;
245 session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
246 list_init( &session->hdr.children );
247 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
248 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
249 session->send_timeout = DEFAULT_SEND_TIMEOUT;
250 session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
251 list_init( &session->cookie_cache );
253 if (agent && !(session->agent = strdupW( agent ))) goto end;
254 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
256 WINHTTP_PROXY_INFO info;
258 WinHttpGetDefaultProxyConfiguration( &info );
259 session->access = info.dwAccessType;
260 if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
262 GlobalFree( info.lpszProxy );
263 GlobalFree( info.lpszProxyBypass );
264 goto end;
266 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
268 GlobalFree( info.lpszProxy );
269 GlobalFree( info.lpszProxyBypass );
270 goto end;
273 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
275 session->access = access;
276 if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
277 if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
280 if (!(handle = alloc_handle( &session->hdr ))) goto end;
281 session->hdr.handle = handle;
283 end:
284 release_object( &session->hdr );
285 TRACE("returning %p\n", handle);
286 if (handle) set_last_error( ERROR_SUCCESS );
287 return handle;
290 /***********************************************************************
291 * connect_destroy (internal)
293 static void connect_destroy( object_header_t *hdr )
295 connect_t *connect = (connect_t *)hdr;
297 TRACE("%p\n", connect);
299 release_object( &connect->session->hdr );
301 heap_free( connect->hostname );
302 heap_free( connect->servername );
303 heap_free( connect->username );
304 heap_free( connect->password );
305 heap_free( connect );
308 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
310 connect_t *connect = (connect_t *)hdr;
312 switch (option)
314 case WINHTTP_OPTION_PARENT_HANDLE:
316 if (!buffer || *buflen < sizeof(HINTERNET))
318 *buflen = sizeof(HINTERNET);
319 set_last_error( ERROR_INSUFFICIENT_BUFFER );
320 return FALSE;
323 *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
324 *buflen = sizeof(HINTERNET);
325 return TRUE;
327 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
328 *(DWORD *)buffer = connect->session->resolve_timeout;
329 *buflen = sizeof(DWORD);
330 return TRUE;
331 case WINHTTP_OPTION_CONNECT_TIMEOUT:
332 *(DWORD *)buffer = connect->session->connect_timeout;
333 *buflen = sizeof(DWORD);
334 return TRUE;
335 case WINHTTP_OPTION_SEND_TIMEOUT:
336 *(DWORD *)buffer = connect->session->send_timeout;
337 *buflen = sizeof(DWORD);
338 return TRUE;
339 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
340 *(DWORD *)buffer = connect->session->recv_timeout;
341 *buflen = sizeof(DWORD);
342 return TRUE;
343 default:
344 FIXME("unimplemented option %u\n", option);
345 set_last_error( ERROR_INVALID_PARAMETER );
346 return FALSE;
350 static const object_vtbl_t connect_vtbl =
352 connect_destroy,
353 connect_query_option,
354 NULL
357 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
359 static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
360 BOOL ret = FALSE;
362 if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
363 ret = TRUE;
364 else if (*domain == '*')
366 if (domain[1] == '.')
368 LPCWSTR dot;
370 /* For a hostname to match a wildcard, the last domain must match
371 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
372 * hostname is www.foo.a.b, it matches, but a.b does not.
374 dot = strchrW( server, '.' );
375 if (dot)
377 int len = strlenW( dot + 1 );
379 if (len > strlenW( domain + 2 ))
381 LPCWSTR ptr;
383 /* The server's domain is longer than the wildcard, so it
384 * could be a subdomain. Compare the last portion of the
385 * server's domain.
387 ptr = dot + len + 1 - strlenW( domain + 2 );
388 if (!strcmpiW( ptr, domain + 2 ))
390 /* This is only a match if the preceding character is
391 * a '.', i.e. that it is a matching domain. E.g.
392 * if domain is '*.b.c' and server is 'www.ab.c' they
393 * do not match.
395 ret = *(ptr - 1) == '.';
398 else
399 ret = !strcmpiW( dot + 1, domain + 2 );
403 else
404 ret = !strcmpiW( server, domain );
405 return ret;
408 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
409 #define MAX_HOST_NAME_LENGTH 256
411 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
413 LPCWSTR ptr;
414 BOOL ret = FALSE;
416 if (!session->proxy_bypass) return FALSE;
417 ptr = session->proxy_bypass;
418 do {
419 LPCWSTR tmp = ptr;
421 ptr = strchrW( ptr, ';' );
422 if (!ptr)
423 ptr = strchrW( tmp, ' ' );
424 if (ptr)
426 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
428 WCHAR domain[MAX_HOST_NAME_LENGTH];
430 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
431 domain[ptr - tmp] = 0;
432 ret = domain_matches( server, domain );
434 ptr += 1;
436 else if (*tmp)
437 ret = domain_matches( server, tmp );
438 } while (ptr && !ret);
439 return ret;
442 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
444 session_t *session = connect->session;
445 BOOL ret = TRUE;
447 if (session->proxy_server && !should_bypass_proxy(session, server))
449 LPCWSTR colon;
451 if ((colon = strchrW( session->proxy_server, ':' )))
453 if (!connect->servername || strncmpiW( connect->servername,
454 session->proxy_server, colon - session->proxy_server - 1 ))
456 heap_free( connect->servername );
457 connect->resolved = FALSE;
458 if (!(connect->servername = heap_alloc(
459 (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
461 ret = FALSE;
462 goto end;
464 memcpy( connect->servername, session->proxy_server,
465 (colon - session->proxy_server) * sizeof(WCHAR) );
466 connect->servername[colon - session->proxy_server] = 0;
467 if (*(colon + 1))
468 connect->serverport = atoiW( colon + 1 );
469 else
470 connect->serverport = INTERNET_DEFAULT_PORT;
473 else
475 if (!connect->servername || strcmpiW( connect->servername,
476 session->proxy_server ))
478 heap_free( connect->servername );
479 connect->resolved = FALSE;
480 if (!(connect->servername = strdupW( session->proxy_server )))
482 ret = FALSE;
483 goto end;
485 connect->serverport = INTERNET_DEFAULT_PORT;
489 else if (server)
491 heap_free( connect->servername );
492 connect->resolved = FALSE;
493 if (!(connect->servername = strdupW( server )))
495 ret = FALSE;
496 goto end;
498 connect->serverport = port;
500 end:
501 return ret;
504 /***********************************************************************
505 * WinHttpConnect (winhttp.@)
507 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
509 connect_t *connect;
510 session_t *session;
511 HINTERNET hconnect = NULL;
513 TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
515 if (!server)
517 set_last_error( ERROR_INVALID_PARAMETER );
518 return NULL;
520 if (!(session = (session_t *)grab_object( hsession )))
522 set_last_error( ERROR_INVALID_HANDLE );
523 return NULL;
525 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
527 release_object( &session->hdr );
528 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
529 return NULL;
531 if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
533 release_object( &session->hdr );
534 return NULL;
536 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
537 connect->hdr.vtbl = &connect_vtbl;
538 connect->hdr.refs = 1;
539 connect->hdr.flags = session->hdr.flags;
540 connect->hdr.callback = session->hdr.callback;
541 connect->hdr.notify_mask = session->hdr.notify_mask;
542 connect->hdr.context = session->hdr.context;
543 connect->hdr.redirect_policy = session->hdr.redirect_policy;
544 list_init( &connect->hdr.children );
546 addref_object( &session->hdr );
547 connect->session = session;
548 list_add_head( &session->hdr.children, &connect->hdr.entry );
550 if (!(connect->hostname = strdupW( server ))) goto end;
551 connect->hostport = port;
552 if (!set_server_for_hostname( connect, server, port )) goto end;
554 if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
555 connect->hdr.handle = hconnect;
557 send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
559 end:
560 release_object( &connect->hdr );
561 release_object( &session->hdr );
562 TRACE("returning %p\n", hconnect);
563 if (hconnect) set_last_error( ERROR_SUCCESS );
564 return hconnect;
567 /***********************************************************************
568 * request_destroy (internal)
570 static void request_destroy( object_header_t *hdr )
572 request_t *request = (request_t *)hdr;
573 unsigned int i, j;
575 TRACE("%p\n", request);
577 if (request->task_thread)
579 /* Signal to the task proc to quit. It will call
580 this again when it does. */
581 HANDLE thread = request->task_thread;
582 request->task_thread = 0;
583 SetEvent( request->task_cancel );
584 CloseHandle( thread );
585 return;
587 release_object( &request->connect->hdr );
589 destroy_authinfo( request->authinfo );
590 destroy_authinfo( request->proxy_authinfo );
592 heap_free( request->verb );
593 heap_free( request->path );
594 heap_free( request->version );
595 heap_free( request->raw_headers );
596 heap_free( request->status_text );
597 for (i = 0; i < request->num_headers; i++)
599 heap_free( request->headers[i].field );
600 heap_free( request->headers[i].value );
602 heap_free( request->headers );
603 for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
604 heap_free( request->accept_types );
605 for (i = 0; i < TARGET_MAX; i++)
607 for (j = 0; j < SCHEME_MAX; j++)
609 heap_free( request->creds[i][j].username );
610 heap_free( request->creds[i][j].password );
613 heap_free( request );
616 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
618 int len = 0;
619 if (str) len = strlenW( str );
620 if (buffer && *buflen > len)
622 if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
623 buffer[len] = 0;
625 *buflen = len * sizeof(WCHAR);
628 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
630 WCHAR *ret;
631 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
633 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
634 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
635 CertNameToStrW( encoding, blob, format, ret, size );
637 return ret;
640 static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
642 #ifndef __MINGW32__
643 switch (addr->sa_family)
645 case AF_INET:
647 const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
648 struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
649 char *p;
651 addr_win->sin_family = WS_AF_INET;
652 addr_win->sin_port = addr_unix->sin_port;
653 memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
654 p = (char *)&addr_win->sin_addr + 4;
655 memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
656 return TRUE;
658 case AF_INET6:
660 const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
661 struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
663 addr_win->sin6_family = WS_AF_INET6;
664 addr_win->sin6_port = addr_unix->sin6_port;
665 addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
666 memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
667 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
668 addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
669 #else
670 addr_win->sin6_scope_id = 0;
671 #endif
672 memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
673 return TRUE;
675 default:
676 ERR("unhandled family %u\n", addr->sa_family);
677 return FALSE;
679 #else
680 switch (addr->sa_family)
682 case AF_INET:
684 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
686 memcpy( addr_in, addr, sizeof(*addr_in) );
687 memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
688 return TRUE;
690 case AF_INET6:
692 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
694 memcpy( addr_in6, addr, sizeof(*addr_in6) );
695 memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
696 return TRUE;
698 default:
699 ERR("unhandled family %u\n", addr->sa_family);
700 return FALSE;
702 #endif
705 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
707 request_t *request = (request_t *)hdr;
709 switch (option)
711 case WINHTTP_OPTION_SECURITY_FLAGS:
713 DWORD flags = 0;
714 int bits;
716 if (!buffer || *buflen < sizeof(flags))
718 *buflen = sizeof(flags);
719 set_last_error( ERROR_INSUFFICIENT_BUFFER );
720 return FALSE;
723 flags = 0;
724 if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
725 flags |= request->security_flags;
726 if (request->netconn)
728 bits = netconn_get_cipher_strength( request->netconn );
729 if (bits >= 128)
730 flags |= SECURITY_FLAG_STRENGTH_STRONG;
731 else if (bits >= 56)
732 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
733 else
734 flags |= SECURITY_FLAG_STRENGTH_WEAK;
736 *(DWORD *)buffer = flags;
737 *buflen = sizeof(flags);
738 return TRUE;
740 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
742 const CERT_CONTEXT *cert;
744 if (!buffer || *buflen < sizeof(cert))
746 *buflen = sizeof(cert);
747 set_last_error( ERROR_INSUFFICIENT_BUFFER );
748 return FALSE;
751 if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
752 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
753 *buflen = sizeof(cert);
754 return TRUE;
756 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
758 const CERT_CONTEXT *cert;
759 const CRYPT_OID_INFO *oidInfo;
760 WINHTTP_CERTIFICATE_INFO *ci = buffer;
762 FIXME("partial stub\n");
764 if (!buffer || *buflen < sizeof(*ci))
766 *buflen = sizeof(*ci);
767 set_last_error( ERROR_INSUFFICIENT_BUFFER );
768 return FALSE;
770 if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
772 ci->ftExpiry = cert->pCertInfo->NotAfter;
773 ci->ftStart = cert->pCertInfo->NotBefore;
774 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
775 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
776 ci->lpszProtocolName = NULL;
777 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
778 cert->pCertInfo->SignatureAlgorithm.pszObjId,
779 0 );
780 if (oidInfo)
781 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
782 else
783 ci->lpszSignatureAlgName = NULL;
784 ci->lpszEncryptionAlgName = NULL;
785 ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
787 CertFreeCertificateContext( cert );
788 *buflen = sizeof(*ci);
789 return TRUE;
791 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
793 if (!buffer || *buflen < sizeof(DWORD))
795 *buflen = sizeof(DWORD);
796 set_last_error( ERROR_INSUFFICIENT_BUFFER );
797 return FALSE;
800 *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
801 *buflen = sizeof(DWORD);
802 return TRUE;
804 case WINHTTP_OPTION_CONNECTION_INFO:
806 WINHTTP_CONNECTION_INFO *info = buffer;
807 struct sockaddr local;
808 socklen_t len = sizeof(local);
809 const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
811 if (!buffer || *buflen < sizeof(*info))
813 *buflen = sizeof(*info);
814 set_last_error( ERROR_INSUFFICIENT_BUFFER );
815 return FALSE;
817 if (!request->netconn)
819 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
820 return FALSE;
822 if (getsockname( request->netconn->socket, &local, &len )) return FALSE;
823 if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
824 if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
825 info->cbSize = sizeof(*info);
826 return TRUE;
828 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
829 *(DWORD *)buffer = request->resolve_timeout;
830 *buflen = sizeof(DWORD);
831 return TRUE;
832 case WINHTTP_OPTION_CONNECT_TIMEOUT:
833 *(DWORD *)buffer = request->connect_timeout;
834 *buflen = sizeof(DWORD);
835 return TRUE;
836 case WINHTTP_OPTION_SEND_TIMEOUT:
837 *(DWORD *)buffer = request->send_timeout;
838 *buflen = sizeof(DWORD);
839 return TRUE;
840 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
841 *(DWORD *)buffer = request->recv_timeout;
842 *buflen = sizeof(DWORD);
843 return TRUE;
845 case WINHTTP_OPTION_USERNAME:
846 str_to_buffer( buffer, request->connect->username, buflen );
847 return TRUE;
849 case WINHTTP_OPTION_PASSWORD:
850 str_to_buffer( buffer, request->connect->password, buflen );
851 return TRUE;
853 case WINHTTP_OPTION_PROXY_USERNAME:
854 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
855 return TRUE;
857 case WINHTTP_OPTION_PROXY_PASSWORD:
858 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
859 return TRUE;
861 default:
862 FIXME("unimplemented option %u\n", option);
863 set_last_error( ERROR_INVALID_PARAMETER );
864 return FALSE;
868 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
870 WCHAR *ret;
871 if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
873 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
874 ret[buflen] = 0;
875 return ret;
877 set_last_error( ERROR_OUTOFMEMORY );
878 return NULL;
881 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
883 request_t *request = (request_t *)hdr;
885 switch (option)
887 case WINHTTP_OPTION_PROXY:
889 WINHTTP_PROXY_INFO *pi = buffer;
891 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
892 return TRUE;
894 case WINHTTP_OPTION_DISABLE_FEATURE:
896 DWORD disable;
898 if (buflen != sizeof(DWORD))
900 set_last_error( ERROR_INSUFFICIENT_BUFFER );
901 return FALSE;
904 disable = *(DWORD *)buffer;
905 TRACE("0x%x\n", disable);
906 hdr->disable_flags |= disable;
907 return TRUE;
909 case WINHTTP_OPTION_AUTOLOGON_POLICY:
911 DWORD policy;
913 if (buflen != sizeof(DWORD))
915 set_last_error( ERROR_INSUFFICIENT_BUFFER );
916 return FALSE;
919 policy = *(DWORD *)buffer;
920 TRACE("0x%x\n", policy);
921 hdr->logon_policy = policy;
922 return TRUE;
924 case WINHTTP_OPTION_REDIRECT_POLICY:
926 DWORD policy;
928 if (buflen != sizeof(DWORD))
930 set_last_error( ERROR_INSUFFICIENT_BUFFER );
931 return FALSE;
934 policy = *(DWORD *)buffer;
935 TRACE("0x%x\n", policy);
936 hdr->redirect_policy = policy;
937 return TRUE;
939 case WINHTTP_OPTION_SECURITY_FLAGS:
941 DWORD flags;
943 if (buflen < sizeof(DWORD))
945 set_last_error( ERROR_INSUFFICIENT_BUFFER );
946 return FALSE;
948 flags = *(DWORD *)buffer;
949 TRACE("0x%x\n", flags);
950 if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
951 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
952 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
953 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
955 set_last_error( ERROR_INVALID_PARAMETER );
956 return FALSE;
958 request->security_flags = flags;
959 return TRUE;
961 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
962 request->resolve_timeout = *(DWORD *)buffer;
963 return TRUE;
964 case WINHTTP_OPTION_CONNECT_TIMEOUT:
965 request->connect_timeout = *(DWORD *)buffer;
966 return TRUE;
967 case WINHTTP_OPTION_SEND_TIMEOUT:
968 request->send_timeout = *(DWORD *)buffer;
969 return TRUE;
970 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
971 request->recv_timeout = *(DWORD *)buffer;
972 return TRUE;
974 case WINHTTP_OPTION_USERNAME:
976 connect_t *connect = request->connect;
978 heap_free( connect->username );
979 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
980 return TRUE;
982 case WINHTTP_OPTION_PASSWORD:
984 connect_t *connect = request->connect;
986 heap_free( connect->password );
987 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
988 return TRUE;
990 case WINHTTP_OPTION_PROXY_USERNAME:
992 session_t *session = request->connect->session;
994 heap_free( session->proxy_username );
995 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
996 return TRUE;
998 case WINHTTP_OPTION_PROXY_PASSWORD:
1000 session_t *session = request->connect->session;
1002 heap_free( session->proxy_password );
1003 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
1004 return TRUE;
1006 case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
1007 if (!(hdr->flags & WINHTTP_FLAG_SECURE))
1009 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
1010 return FALSE;
1012 FIXME("WINHTTP_OPTION_CLIENT_CERT_CONTEXT\n");
1013 return TRUE;
1014 default:
1015 FIXME("unimplemented option %u\n", option);
1016 set_last_error( ERROR_INVALID_PARAMETER );
1017 return TRUE;
1021 static const object_vtbl_t request_vtbl =
1023 request_destroy,
1024 request_query_option,
1025 request_set_option
1028 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
1030 const WCHAR **types = accept_types;
1031 DWORD i;
1033 if (!types) return TRUE;
1034 while (*types)
1036 request->num_accept_types++;
1037 types++;
1039 if (!request->num_accept_types) return TRUE;
1040 if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
1042 request->num_accept_types = 0;
1043 return FALSE;
1045 types = accept_types;
1046 for (i = 0; i < request->num_accept_types; i++)
1048 if (!(request->accept_types[i] = strdupW( *types )))
1050 for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
1051 heap_free( request->accept_types );
1052 request->accept_types = NULL;
1053 request->num_accept_types = 0;
1054 return FALSE;
1056 types++;
1058 return TRUE;
1061 /***********************************************************************
1062 * WinHttpOpenRequest (winhttp.@)
1064 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
1065 LPCWSTR referrer, LPCWSTR *types, DWORD flags )
1067 request_t *request;
1068 connect_t *connect;
1069 HINTERNET hrequest = NULL;
1071 TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
1072 debugstr_w(version), debugstr_w(referrer), types, flags);
1074 if(types && TRACE_ON(winhttp)) {
1075 const WCHAR **iter;
1077 TRACE("accept types:\n");
1078 for(iter = types; *iter; iter++)
1079 TRACE(" %s\n", debugstr_w(*iter));
1082 if (!(connect = (connect_t *)grab_object( hconnect )))
1084 set_last_error( ERROR_INVALID_HANDLE );
1085 return NULL;
1087 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1089 release_object( &connect->hdr );
1090 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1091 return NULL;
1093 if (!(request = heap_alloc_zero( sizeof(request_t) )))
1095 release_object( &connect->hdr );
1096 return NULL;
1098 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1099 request->hdr.vtbl = &request_vtbl;
1100 request->hdr.refs = 1;
1101 request->hdr.flags = flags;
1102 request->hdr.callback = connect->hdr.callback;
1103 request->hdr.notify_mask = connect->hdr.notify_mask;
1104 request->hdr.context = connect->hdr.context;
1105 request->hdr.redirect_policy = connect->hdr.redirect_policy;
1106 list_init( &request->hdr.children );
1107 list_init( &request->task_queue );
1109 addref_object( &connect->hdr );
1110 request->connect = connect;
1111 list_add_head( &connect->hdr.children, &request->hdr.entry );
1113 request->resolve_timeout = connect->session->resolve_timeout;
1114 request->connect_timeout = connect->session->connect_timeout;
1115 request->send_timeout = connect->session->send_timeout;
1116 request->recv_timeout = connect->session->recv_timeout;
1118 if (!verb || !verb[0]) verb = getW;
1119 if (!(request->verb = strdupW( verb ))) goto end;
1121 if (object)
1123 WCHAR *path, *p;
1124 unsigned int len;
1126 len = strlenW( object ) + 1;
1127 if (object[0] != '/') len++;
1128 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
1130 if (object[0] != '/') *p++ = '/';
1131 strcpyW( p, object );
1132 request->path = path;
1134 else if (!(request->path = strdupW( slashW ))) goto end;
1136 if (!version || !version[0]) version = http1_1;
1137 if (!(request->version = strdupW( version ))) goto end;
1138 if (!(store_accept_types( request, types ))) goto end;
1140 if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
1141 request->hdr.handle = hrequest;
1143 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1145 end:
1146 release_object( &request->hdr );
1147 release_object( &connect->hdr );
1148 TRACE("returning %p\n", hrequest);
1149 if (hrequest) set_last_error( ERROR_SUCCESS );
1150 return hrequest;
1153 /***********************************************************************
1154 * WinHttpCloseHandle (winhttp.@)
1156 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1158 object_header_t *hdr;
1160 TRACE("%p\n", handle);
1162 if (!(hdr = grab_object( handle )))
1164 set_last_error( ERROR_INVALID_HANDLE );
1165 return FALSE;
1167 release_object( hdr );
1168 free_handle( handle );
1169 set_last_error( ERROR_SUCCESS );
1170 return TRUE;
1173 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1175 BOOL ret = FALSE;
1177 if (!buflen)
1179 set_last_error( ERROR_INVALID_PARAMETER );
1180 return FALSE;
1183 switch (option)
1185 case WINHTTP_OPTION_CONTEXT_VALUE:
1187 if (!buffer || *buflen < sizeof(DWORD_PTR))
1189 *buflen = sizeof(DWORD_PTR);
1190 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1191 return FALSE;
1194 *(DWORD_PTR *)buffer = hdr->context;
1195 *buflen = sizeof(DWORD_PTR);
1196 return TRUE;
1198 default:
1199 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1200 else
1202 FIXME("unimplemented option %u\n", option);
1203 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1204 return FALSE;
1206 break;
1208 return ret;
1211 /***********************************************************************
1212 * WinHttpQueryOption (winhttp.@)
1214 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1216 BOOL ret = FALSE;
1217 object_header_t *hdr;
1219 TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1221 if (!(hdr = grab_object( handle )))
1223 set_last_error( ERROR_INVALID_HANDLE );
1224 return FALSE;
1227 ret = query_option( hdr, option, buffer, buflen );
1229 release_object( hdr );
1230 if (ret) set_last_error( ERROR_SUCCESS );
1231 return ret;
1234 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1236 BOOL ret = TRUE;
1238 if (!buffer && buflen)
1240 set_last_error( ERROR_INVALID_PARAMETER );
1241 return FALSE;
1244 switch (option)
1246 case WINHTTP_OPTION_CONTEXT_VALUE:
1248 if (buflen != sizeof(DWORD_PTR))
1250 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1251 return FALSE;
1254 hdr->context = *(DWORD_PTR *)buffer;
1255 return TRUE;
1257 default:
1258 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1259 else
1261 FIXME("unimplemented option %u\n", option);
1262 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1263 return FALSE;
1265 break;
1267 return ret;
1270 /***********************************************************************
1271 * WinHttpSetOption (winhttp.@)
1273 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1275 BOOL ret = FALSE;
1276 object_header_t *hdr;
1278 TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1280 if (!(hdr = grab_object( handle )))
1282 set_last_error( ERROR_INVALID_HANDLE );
1283 return FALSE;
1286 ret = set_option( hdr, option, buffer, buflen );
1288 release_object( hdr );
1289 if (ret) set_last_error( ERROR_SUCCESS );
1290 return ret;
1293 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1295 char *ret;
1296 DWORD size = 0;
1298 GetComputerNameExA( format, NULL, &size );
1299 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1300 if (!(ret = heap_alloc( size ))) return NULL;
1301 if (!GetComputerNameExA( format, ret, &size ))
1303 heap_free( ret );
1304 return NULL;
1306 return ret;
1309 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1311 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1313 if (len_suffix > len_domain) return FALSE;
1314 if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1315 return FALSE;
1318 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1320 int ret = -1;
1321 #ifdef HAVE_GETNAMEINFO
1322 ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1323 #endif
1324 return ret;
1327 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1329 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1330 static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
1331 char name[NI_MAXHOST];
1332 WCHAR *ret, *p;
1333 int len;
1335 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1336 if (!ai) return NULL;
1338 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1340 len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
1341 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1342 strcpyW( p, httpW );
1343 p += strlenW( httpW );
1344 while (*hostname) { *p++ = *hostname++; }
1345 strcpyW( p, wpadW );
1346 return ret;
1349 static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen )
1351 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1352 CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
1353 const void *ref;
1354 BOOL ret = FALSE;
1356 if (!settings) return FALSE;
1358 if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
1360 CFRelease( settings );
1361 return FALSE;
1363 if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII ))
1365 TRACE( "returning %s\n", debugstr_a(buf) );
1366 ret = TRUE;
1368 CFRelease( settings );
1369 return ret;
1370 #else
1371 static BOOL first = TRUE;
1372 if (first)
1374 FIXME( "no support on this platform\n" );
1375 first = FALSE;
1377 else
1378 TRACE( "no support on this platform\n" );
1379 return FALSE;
1380 #endif
1383 #define INTERNET_MAX_URL_LENGTH 2084
1385 /***********************************************************************
1386 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1388 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1390 BOOL ret = FALSE;
1391 char system_url[INTERNET_MAX_URL_LENGTH + 1];
1393 TRACE("0x%08x, %p\n", flags, url);
1395 if (!flags || !url)
1397 set_last_error( ERROR_INVALID_PARAMETER );
1398 return FALSE;
1400 if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) ))
1402 WCHAR *urlW;
1404 if (!(urlW = strdupAW( system_url ))) return FALSE;
1405 *url = urlW;
1406 set_last_error( ERROR_SUCCESS );
1407 return TRUE;
1409 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1411 static int fixme_shown;
1412 if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
1414 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1416 #ifdef HAVE_GETADDRINFO
1417 char *fqdn, *domain, *p;
1419 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1420 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1422 heap_free( fqdn );
1423 return FALSE;
1425 p = fqdn;
1426 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1428 struct addrinfo *ai;
1429 char *name;
1430 int res;
1432 if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1434 heap_free( fqdn );
1435 heap_free( domain );
1436 return FALSE;
1438 strcpy( name, "wpad" );
1439 strcat( name, p );
1440 res = getaddrinfo( name, NULL, NULL, &ai );
1441 if (!res)
1443 *url = build_wpad_url( name, ai );
1444 freeaddrinfo( ai );
1445 if (*url)
1447 TRACE("returning %s\n", debugstr_w(*url));
1448 heap_free( name );
1449 ret = TRUE;
1450 break;
1453 heap_free( name );
1454 p++;
1456 heap_free( domain );
1457 heap_free( fqdn );
1458 #else
1459 FIXME("getaddrinfo not found at build time\n");
1460 #endif
1462 if (!ret)
1464 set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1465 *url = NULL;
1467 else set_last_error( ERROR_SUCCESS );
1468 return ret;
1471 static const WCHAR Connections[] = {
1472 'S','o','f','t','w','a','r','e','\\',
1473 'M','i','c','r','o','s','o','f','t','\\',
1474 'W','i','n','d','o','w','s','\\',
1475 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1476 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1477 'C','o','n','n','e','c','t','i','o','n','s',0 };
1478 static const WCHAR WinHttpSettings[] = {
1479 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1480 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1481 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1482 static const DWORD PROXY_TYPE_DIRECT = 1;
1483 static const DWORD PROXY_TYPE_PROXY = 2;
1484 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1485 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1487 struct connection_settings_header
1489 DWORD magic;
1490 DWORD unknown; /* always zero? */
1491 DWORD flags; /* one or more of PROXY_* */
1494 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1496 const BYTE *begin;
1498 for (begin = src; src - begin < len; src++, dst++)
1499 *dst = *src;
1500 *dst = 0;
1503 /***********************************************************************
1504 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1506 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1508 LONG l;
1509 HKEY key;
1510 BOOL got_from_reg = FALSE, direct = TRUE;
1511 char *envproxy;
1513 TRACE("%p\n", info);
1515 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1516 if (!l)
1518 DWORD type, size = 0;
1520 l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1521 if (!l && type == REG_BINARY &&
1522 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1524 BYTE *buf = heap_alloc( size );
1526 if (buf)
1528 struct connection_settings_header *hdr =
1529 (struct connection_settings_header *)buf;
1530 DWORD *len = (DWORD *)(hdr + 1);
1532 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1533 &size );
1534 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1535 hdr->unknown == 0)
1537 if (hdr->flags & PROXY_TYPE_PROXY)
1539 BOOL sane = FALSE;
1540 LPWSTR proxy = NULL;
1541 LPWSTR proxy_bypass = NULL;
1543 /* Sanity-check length of proxy string */
1544 if ((BYTE *)len - buf + *len <= size)
1546 sane = TRUE;
1547 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1548 if (proxy)
1549 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1550 len = (DWORD *)((BYTE *)(len + 1) + *len);
1552 if (sane)
1554 /* Sanity-check length of proxy bypass string */
1555 if ((BYTE *)len - buf + *len <= size)
1557 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1558 if (proxy_bypass)
1559 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1561 else
1563 sane = FALSE;
1564 GlobalFree( proxy );
1565 proxy = NULL;
1568 info->lpszProxy = proxy;
1569 info->lpszProxyBypass = proxy_bypass;
1570 if (sane)
1572 got_from_reg = TRUE;
1573 direct = FALSE;
1574 info->dwAccessType =
1575 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1576 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1577 debugstr_w(info->lpszProxy),
1578 debugstr_w(info->lpszProxyBypass));
1582 heap_free( buf );
1585 RegCloseKey( key );
1587 if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1589 char *colon, *http_proxy;
1591 if ((colon = strchr( envproxy, ':' )))
1593 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1595 static const char http[] = "http://";
1597 /* It's a scheme, check that it's http */
1598 if (!strncmp( envproxy, http, strlen( http ) ))
1599 http_proxy = envproxy + strlen( http );
1600 else
1602 WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1603 http_proxy = NULL;
1606 else
1607 http_proxy = envproxy;
1609 else
1610 http_proxy = envproxy;
1611 if (http_proxy)
1613 WCHAR *http_proxyW;
1614 int len;
1616 len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1617 if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1619 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1620 direct = FALSE;
1621 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1622 info->lpszProxy = http_proxyW;
1623 info->lpszProxyBypass = NULL;
1624 TRACE("http proxy (from environment) = %s\n",
1625 debugstr_w(info->lpszProxy));
1629 if (direct)
1631 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1632 info->lpszProxy = NULL;
1633 info->lpszProxyBypass = NULL;
1635 set_last_error( ERROR_SUCCESS );
1636 return TRUE;
1639 /***********************************************************************
1640 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1642 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1644 static const WCHAR settingsW[] =
1645 {'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};
1646 HKEY hkey = NULL;
1647 struct connection_settings_header *hdr = NULL;
1648 DWORD type, offset, len, size = 0;
1649 BOOL ret = FALSE;
1651 TRACE("%p\n", config);
1653 if (!config)
1655 set_last_error( ERROR_INVALID_PARAMETER );
1656 return FALSE;
1658 memset( config, 0, sizeof(*config) );
1659 config->fAutoDetect = TRUE;
1661 if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1662 RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1663 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1665 ret = TRUE;
1666 goto done;
1668 if (!(hdr = heap_alloc( size ))) goto done;
1669 if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1670 hdr->magic != WININET_SETTINGS_MAGIC)
1672 ret = TRUE;
1673 goto done;
1676 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1677 offset = sizeof(*hdr);
1678 if (offset + sizeof(DWORD) > size) goto done;
1679 len = *(DWORD *)((char *)hdr + offset);
1680 offset += sizeof(DWORD);
1681 if (len && hdr->flags & PROXY_TYPE_PROXY)
1683 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1684 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1686 offset += len;
1687 if (offset + sizeof(DWORD) > size) goto done;
1688 len = *(DWORD *)((char *)hdr + offset);
1689 offset += sizeof(DWORD);
1690 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1692 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1693 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1695 offset += len;
1696 if (offset + sizeof(DWORD) > size) goto done;
1697 len = *(DWORD *)((char *)hdr + offset);
1698 offset += sizeof(DWORD);
1699 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1701 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1702 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1704 ret = TRUE;
1706 done:
1707 RegCloseKey( hkey );
1708 heap_free( hdr );
1709 if (!ret)
1711 GlobalFree( config->lpszAutoConfigUrl );
1712 config->lpszAutoConfigUrl = NULL;
1713 GlobalFree( config->lpszProxy );
1714 config->lpszProxy = NULL;
1715 GlobalFree( config->lpszProxyBypass );
1716 config->lpszProxyBypass = NULL;
1718 else set_last_error( ERROR_SUCCESS );
1719 return ret;
1722 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1724 const char *p;
1725 WCHAR *q;
1726 int len;
1728 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1729 info->lpszProxy = NULL;
1730 info->lpszProxyBypass = NULL;
1732 TRACE("%s\n", debugstr_a( result ));
1734 p = result;
1735 while (*p == ' ') p++;
1736 len = strlen( p );
1737 if (len >= 5 && !strncasecmp( p, "PROXY", sizeof("PROXY") - 1 ))
1739 p += 5;
1740 while (*p == ' ') p++;
1741 if (!*p || *p == ';') return TRUE;
1742 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1743 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1744 for (; *q; q++)
1746 if (*q == ' ' || *q == ';')
1748 *q = 0;
1749 break;
1753 return TRUE;
1756 static char *download_script( const WCHAR *url, DWORD *out_size )
1758 static const WCHAR typeW[] = {'*','/','*',0};
1759 static const WCHAR *acceptW[] = {typeW, NULL};
1760 HINTERNET ses, con = NULL, req = NULL;
1761 WCHAR *hostname;
1762 URL_COMPONENTSW uc;
1763 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1764 char *tmp, *buffer = NULL;
1766 *out_size = 0;
1768 memset( &uc, 0, sizeof(uc) );
1769 uc.dwStructSize = sizeof(uc);
1770 uc.dwHostNameLength = -1;
1771 uc.dwUrlPathLength = -1;
1772 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1773 if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1774 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1775 hostname[uc.dwHostNameLength] = 0;
1777 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1778 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1779 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1780 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1781 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1783 if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1784 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1785 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1787 size = 4096;
1788 if (!(buffer = heap_alloc( size ))) goto done;
1789 to_read = size;
1790 offset = 0;
1791 for (;;)
1793 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1794 if (!bytes_read) break;
1795 to_read -= bytes_read;
1796 offset += bytes_read;
1797 *out_size += bytes_read;
1798 if (!to_read)
1800 to_read = size;
1801 size *= 2;
1802 if (!(tmp = heap_realloc( buffer, size ))) goto done;
1803 buffer = tmp;
1807 done:
1808 WinHttpCloseHandle( req );
1809 WinHttpCloseHandle( con );
1810 WinHttpCloseHandle( ses );
1811 heap_free( hostname );
1812 if (!buffer) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1813 return buffer;
1816 struct AUTO_PROXY_SCRIPT_BUFFER
1818 DWORD dwStructSize;
1819 LPSTR lpszScriptBuffer;
1820 DWORD dwScriptBufferSize;
1823 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1824 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1825 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1827 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1829 BOOL ret;
1830 char *result, *urlA;
1831 DWORD len_result;
1832 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1833 URL_COMPONENTSW uc;
1835 buffer.dwStructSize = sizeof(buffer);
1836 buffer.lpszScriptBuffer = script;
1837 buffer.dwScriptBufferSize = size;
1839 if (!(urlA = strdupWA( url ))) return FALSE;
1840 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1842 heap_free( urlA );
1843 return FALSE;
1846 memset( &uc, 0, sizeof(uc) );
1847 uc.dwStructSize = sizeof(uc);
1848 uc.dwHostNameLength = -1;
1850 if (WinHttpCrackUrl( url, 0, 0, &uc ))
1852 char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
1854 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
1855 hostnameA, strlen(hostnameA), &result, &len_result )))
1857 ret = parse_script_result( result, info );
1858 heap_free( result );
1861 heap_free( hostnameA );
1863 heap_free( urlA );
1864 return InternetDeInitializeAutoProxyDll( NULL, 0 );
1867 /***********************************************************************
1868 * WinHttpGetProxyForUrl (winhttp.@)
1870 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1871 WINHTTP_PROXY_INFO *info )
1873 WCHAR *detected_pac_url = NULL;
1874 const WCHAR *pac_url;
1875 session_t *session;
1876 char *script;
1877 DWORD size;
1878 BOOL ret = FALSE;
1880 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1882 if (!(session = (session_t *)grab_object( hsession )))
1884 set_last_error( ERROR_INVALID_HANDLE );
1885 return FALSE;
1887 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1889 release_object( &session->hdr );
1890 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1891 return FALSE;
1893 if (!url || !options || !info ||
1894 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1895 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1896 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1897 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1899 release_object( &session->hdr );
1900 set_last_error( ERROR_INVALID_PARAMETER );
1901 return FALSE;
1903 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1904 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1905 goto done;
1907 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1908 else pac_url = detected_pac_url;
1910 if ((script = download_script( pac_url, &size )))
1912 ret = run_script( script, size, url, info );
1913 heap_free( script );
1916 done:
1917 GlobalFree( detected_pac_url );
1918 release_object( &session->hdr );
1919 if (ret) set_last_error( ERROR_SUCCESS );
1920 return ret;
1923 /***********************************************************************
1924 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
1926 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1928 LONG l;
1929 HKEY key;
1930 BOOL ret = FALSE;
1931 const WCHAR *src;
1933 TRACE("%p\n", info);
1935 if (!info)
1937 set_last_error( ERROR_INVALID_PARAMETER );
1938 return FALSE;
1940 switch (info->dwAccessType)
1942 case WINHTTP_ACCESS_TYPE_NO_PROXY:
1943 break;
1944 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1945 if (!info->lpszProxy)
1947 set_last_error( ERROR_INVALID_PARAMETER );
1948 return FALSE;
1950 /* Only ASCII characters are allowed */
1951 for (src = info->lpszProxy; *src; src++)
1952 if (*src > 0x7f)
1954 set_last_error( ERROR_INVALID_PARAMETER );
1955 return FALSE;
1957 if (info->lpszProxyBypass)
1959 for (src = info->lpszProxyBypass; *src; src++)
1960 if (*src > 0x7f)
1962 set_last_error( ERROR_INVALID_PARAMETER );
1963 return FALSE;
1966 break;
1967 default:
1968 set_last_error( ERROR_INVALID_PARAMETER );
1969 return FALSE;
1972 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1973 KEY_WRITE, NULL, &key, NULL );
1974 if (!l)
1976 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1977 BYTE *buf;
1979 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1981 size += strlenW( info->lpszProxy );
1982 if (info->lpszProxyBypass)
1983 size += strlenW( info->lpszProxyBypass );
1985 buf = heap_alloc( size );
1986 if (buf)
1988 struct connection_settings_header *hdr =
1989 (struct connection_settings_header *)buf;
1990 DWORD *len = (DWORD *)(hdr + 1);
1992 hdr->magic = WINHTTP_SETTINGS_MAGIC;
1993 hdr->unknown = 0;
1994 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1996 BYTE *dst;
1998 hdr->flags = PROXY_TYPE_PROXY;
1999 *len++ = strlenW( info->lpszProxy );
2000 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
2001 src++, dst++)
2002 *dst = *src;
2003 len = (DWORD *)dst;
2004 if (info->lpszProxyBypass)
2006 *len++ = strlenW( info->lpszProxyBypass );
2007 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
2008 src++, dst++)
2009 *dst = *src;
2011 else
2012 *len++ = 0;
2014 else
2016 hdr->flags = PROXY_TYPE_DIRECT;
2017 *len++ = 0;
2018 *len++ = 0;
2020 l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
2021 if (!l)
2022 ret = TRUE;
2023 heap_free( buf );
2025 RegCloseKey( key );
2027 if (ret) set_last_error( ERROR_SUCCESS );
2028 return ret;
2031 /***********************************************************************
2032 * WinHttpSetStatusCallback (winhttp.@)
2034 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2035 DWORD flags, DWORD_PTR reserved )
2037 object_header_t *hdr;
2038 WINHTTP_STATUS_CALLBACK ret;
2040 TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
2042 if (!(hdr = grab_object( handle )))
2044 set_last_error( ERROR_INVALID_HANDLE );
2045 return WINHTTP_INVALID_STATUS_CALLBACK;
2047 ret = hdr->callback;
2048 hdr->callback = callback;
2049 hdr->notify_mask = flags;
2051 release_object( hdr );
2052 set_last_error( ERROR_SUCCESS );
2053 return ret;
2056 /***********************************************************************
2057 * WinHttpSetTimeouts (winhttp.@)
2059 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2061 BOOL ret = TRUE;
2062 object_header_t *hdr;
2063 request_t *request;
2064 session_t *session;
2066 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2068 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2070 set_last_error( ERROR_INVALID_PARAMETER );
2071 return FALSE;
2074 if (!(hdr = grab_object( handle )))
2076 set_last_error( ERROR_INVALID_HANDLE );
2077 return FALSE;
2080 switch(hdr->type)
2082 case WINHTTP_HANDLE_TYPE_REQUEST:
2083 request = (request_t *)hdr;
2084 request->connect_timeout = connect;
2086 if (resolve < 0) resolve = 0;
2087 request->resolve_timeout = resolve;
2089 if (send < 0) send = 0;
2090 request->send_timeout = send;
2092 if (receive < 0) receive = 0;
2093 request->recv_timeout = receive;
2095 if (request->netconn)
2097 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2098 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2100 break;
2102 case WINHTTP_HANDLE_TYPE_SESSION:
2103 session = (session_t *)hdr;
2104 session->connect_timeout = connect;
2106 if (resolve < 0) resolve = 0;
2107 session->resolve_timeout = resolve;
2109 if (send < 0) send = 0;
2110 session->send_timeout = send;
2112 if (receive < 0) receive = 0;
2113 session->recv_timeout = receive;
2114 break;
2116 default:
2117 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2118 ret = FALSE;
2120 release_object( hdr );
2121 if (ret) set_last_error( ERROR_SUCCESS );
2122 return ret;
2125 static const WCHAR wkday[7][4] =
2126 {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2127 {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2128 static const WCHAR month[12][4] =
2129 {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2130 {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2131 {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2133 /***********************************************************************
2134 * WinHttpTimeFromSystemTime (WININET.@)
2136 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2138 static const WCHAR format[] =
2139 {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2140 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2142 TRACE("%p, %p\n", time, string);
2144 if (!time || !string)
2146 set_last_error( ERROR_INVALID_PARAMETER );
2147 return FALSE;
2150 sprintfW( string, format,
2151 wkday[time->wDayOfWeek],
2152 time->wDay,
2153 month[time->wMonth - 1],
2154 time->wYear,
2155 time->wHour,
2156 time->wMinute,
2157 time->wSecond );
2159 set_last_error( ERROR_SUCCESS );
2160 return TRUE;
2163 /***********************************************************************
2164 * WinHttpTimeToSystemTime (WININET.@)
2166 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2168 unsigned int i;
2169 const WCHAR *s = string;
2170 WCHAR *end;
2172 TRACE("%s, %p\n", debugstr_w(string), time);
2174 if (!string || !time)
2176 set_last_error( ERROR_INVALID_PARAMETER );
2177 return FALSE;
2180 /* Windows does this too */
2181 GetSystemTime( time );
2183 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2184 * a SYSTEMTIME structure.
2187 set_last_error( ERROR_SUCCESS );
2189 while (*s && !isalphaW( *s )) s++;
2190 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2191 time->wDayOfWeek = 7;
2193 for (i = 0; i < 7; i++)
2195 if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2196 toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2197 toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2199 time->wDayOfWeek = i;
2200 break;
2204 if (time->wDayOfWeek > 6) return TRUE;
2205 while (*s && !isdigitW( *s )) s++;
2206 time->wDay = strtolW( s, &end, 10 );
2207 s = end;
2209 while (*s && !isalphaW( *s )) s++;
2210 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2211 time->wMonth = 0;
2213 for (i = 0; i < 12; i++)
2215 if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2216 toupperW( month[i][1]) == toupperW( s[1] ) &&
2217 toupperW( month[i][2]) == toupperW( s[2] ) )
2219 time->wMonth = i + 1;
2220 break;
2223 if (time->wMonth == 0) return TRUE;
2225 while (*s && !isdigitW( *s )) s++;
2226 if (*s == '\0') return TRUE;
2227 time->wYear = strtolW( s, &end, 10 );
2228 s = end;
2230 while (*s && !isdigitW( *s )) s++;
2231 if (*s == '\0') return TRUE;
2232 time->wHour = strtolW( s, &end, 10 );
2233 s = end;
2235 while (*s && !isdigitW( *s )) s++;
2236 if (*s == '\0') return TRUE;
2237 time->wMinute = strtolW( s, &end, 10 );
2238 s = end;
2240 while (*s && !isdigitW( *s )) s++;
2241 if (*s == '\0') return TRUE;
2242 time->wSecond = strtolW( s, &end, 10 );
2244 time->wMilliseconds = 0;
2245 return TRUE;