vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / winhttp / session.c
blob6b426bee220f2c312f40c24469097afbb17e0cca
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 <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winsock2.h"
24 #include "ws2ipdef.h"
25 #include "ws2tcpip.h"
26 #include "winhttp.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "iphlpapi.h"
30 #include "dhcpcsdk.h"
31 #define COBJMACROS
32 #include "ole2.h"
33 #include "dispex.h"
34 #include "activscp.h"
36 #include "wine/debug.h"
37 #include "winhttp_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
41 #define DEFAULT_RESOLVE_TIMEOUT 0
42 #define DEFAULT_CONNECT_TIMEOUT 20000
43 #define DEFAULT_SEND_TIMEOUT 30000
44 #define DEFAULT_RECEIVE_TIMEOUT 30000
45 #define DEFAULT_RECEIVE_RESPONSE_TIMEOUT ~0u
47 void send_callback( struct object_header *hdr, DWORD status, void *info, DWORD buflen )
49 if (hdr->callback && (hdr->notify_mask & status))
51 TRACE( "%p, %#lx, %p, %lu, %lu\n", hdr, status, info, buflen, hdr->recursion_count );
52 InterlockedIncrement( &hdr->recursion_count );
53 hdr->callback( hdr->handle, hdr->context, status, info, buflen );
54 InterlockedDecrement( &hdr->recursion_count );
55 TRACE("returning from %#lx callback\n", status);
59 /***********************************************************************
60 * WinHttpCheckPlatform (winhttp.@)
62 BOOL WINAPI WinHttpCheckPlatform( void )
64 TRACE("\n");
65 return TRUE;
68 static void session_destroy( struct object_header *hdr )
70 struct session *session = (struct session *)hdr;
72 TRACE("%p\n", session);
74 if (session->unload_event) SetEvent( session->unload_event );
75 destroy_cookies( session );
77 session->cs.DebugInfo->Spare[0] = 0;
78 DeleteCriticalSection( &session->cs );
79 free( session->agent );
80 free( session->proxy_server );
81 free( session->proxy_bypass );
82 free( session->proxy_username );
83 free( session->proxy_password );
84 free( session );
87 static BOOL validate_buffer( void *buffer, DWORD *buflen, DWORD required )
89 if (!buffer || *buflen < required)
91 *buflen = required;
92 SetLastError( ERROR_INSUFFICIENT_BUFFER );
93 return FALSE;
95 return TRUE;
98 static BOOL session_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
100 struct session *session = (struct session *)hdr;
102 switch (option)
104 case WINHTTP_OPTION_REDIRECT_POLICY:
106 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
108 *(DWORD *)buffer = hdr->redirect_policy;
109 *buflen = sizeof(DWORD);
110 return TRUE;
112 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
113 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
115 *(DWORD *)buffer = session->resolve_timeout;
116 *buflen = sizeof(DWORD);
117 return TRUE;
119 case WINHTTP_OPTION_CONNECT_TIMEOUT:
120 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
122 *(DWORD *)buffer = session->connect_timeout;
123 *buflen = sizeof(DWORD);
124 return TRUE;
126 case WINHTTP_OPTION_SEND_TIMEOUT:
127 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
129 *(DWORD *)buffer = session->send_timeout;
130 *buflen = sizeof(DWORD);
131 return TRUE;
133 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
134 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
136 *(DWORD *)buffer = session->receive_timeout;
137 *buflen = sizeof(DWORD);
138 return TRUE;
140 case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
141 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
143 *(DWORD *)buffer = session->receive_response_timeout;
144 *buflen = sizeof(DWORD);
145 return TRUE;
147 case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
148 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
150 *(DWORD *)buffer = session->websocket_receive_buffer_size;
151 *buflen = sizeof(DWORD);
152 return TRUE;
154 case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
155 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
157 *(DWORD *)buffer = session->websocket_send_buffer_size;
158 *buflen = sizeof(DWORD);
159 return TRUE;
161 default:
162 FIXME( "unimplemented option %lu\n", option );
163 SetLastError( ERROR_INVALID_PARAMETER );
164 return FALSE;
168 static BOOL session_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
170 struct session *session = (struct session *)hdr;
172 switch (option)
174 case WINHTTP_OPTION_PROXY:
176 WINHTTP_PROXY_INFO *pi = buffer;
178 FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) );
179 return TRUE;
181 case WINHTTP_OPTION_REDIRECT_POLICY:
183 DWORD policy;
185 if (buflen != sizeof(policy))
187 SetLastError( ERROR_INSUFFICIENT_BUFFER );
188 return FALSE;
191 policy = *(DWORD *)buffer;
192 TRACE( "%#lx\n", policy );
193 hdr->redirect_policy = policy;
194 return TRUE;
196 case WINHTTP_OPTION_SECURE_PROTOCOLS:
198 if (buflen != sizeof(session->secure_protocols))
200 SetLastError( ERROR_INSUFFICIENT_BUFFER );
201 return FALSE;
203 EnterCriticalSection( &session->cs );
204 session->secure_protocols = *(DWORD *)buffer;
205 LeaveCriticalSection( &session->cs );
206 TRACE( "%#lx\n", session->secure_protocols );
207 return TRUE;
209 case WINHTTP_OPTION_DISABLE_FEATURE:
210 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
211 return FALSE;
213 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
214 session->resolve_timeout = *(DWORD *)buffer;
215 return TRUE;
217 case WINHTTP_OPTION_CONNECT_TIMEOUT:
218 session->connect_timeout = *(DWORD *)buffer;
219 return TRUE;
221 case WINHTTP_OPTION_SEND_TIMEOUT:
222 session->send_timeout = *(DWORD *)buffer;
223 return TRUE;
225 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
226 session->receive_timeout = *(DWORD *)buffer;
227 return TRUE;
229 case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
230 session->receive_response_timeout = *(DWORD *)buffer;
231 return TRUE;
233 case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
234 session->passport_flags = *(DWORD *)buffer;
235 return TRUE;
237 case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
238 TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
239 session->unload_event = *(HANDLE *)buffer;
240 return TRUE;
242 case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
243 FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %lu\n", *(DWORD *)buffer );
244 return TRUE;
246 case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
247 FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %lu\n", *(DWORD *)buffer );
248 return TRUE;
250 case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
252 DWORD buffer_size;
254 if (buflen != sizeof(buffer_size))
256 SetLastError( ERROR_INSUFFICIENT_BUFFER );
257 return FALSE;
260 buffer_size = *(DWORD *)buffer;
261 TRACE( "%#lx\n", buffer_size );
262 session->websocket_receive_buffer_size = buffer_size;
263 return TRUE;
266 case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
268 DWORD buffer_size;
270 if (buflen != sizeof(buffer_size))
272 SetLastError( ERROR_INSUFFICIENT_BUFFER );
273 return FALSE;
276 buffer_size = *(DWORD *)buffer;
277 TRACE( "%#lx\n", buffer_size );
278 session->websocket_send_buffer_size = buffer_size;
279 return TRUE;
282 default:
283 FIXME( "unimplemented option %lu\n", option );
284 SetLastError( ERROR_WINHTTP_INVALID_OPTION );
285 return FALSE;
289 static const struct object_vtbl session_vtbl =
291 NULL,
292 session_destroy,
293 session_query_option,
294 session_set_option
297 /***********************************************************************
298 * WinHttpOpen (winhttp.@)
300 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
302 struct session *session;
303 HINTERNET handle = NULL;
305 TRACE( "%s, %lu, %s, %s, %#lx\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags );
307 if (!(session = calloc( 1, sizeof(*session) ))) return NULL;
309 session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
310 session->hdr.vtbl = &session_vtbl;
311 session->hdr.flags = flags;
312 session->hdr.refs = 1;
313 session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
314 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
315 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
316 session->send_timeout = DEFAULT_SEND_TIMEOUT;
317 session->receive_timeout = DEFAULT_RECEIVE_TIMEOUT;
318 session->receive_response_timeout = DEFAULT_RECEIVE_RESPONSE_TIMEOUT;
319 session->websocket_receive_buffer_size = 32768;
320 session->websocket_send_buffer_size = 32768;
321 list_init( &session->cookie_cache );
322 InitializeCriticalSection( &session->cs );
323 session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": session.cs");
325 if (agent && !(session->agent = wcsdup( agent ))) goto end;
326 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
328 WINHTTP_PROXY_INFO info;
330 WinHttpGetDefaultProxyConfiguration( &info );
331 session->access = info.dwAccessType;
332 if (info.lpszProxy && !(session->proxy_server = wcsdup( info.lpszProxy )))
334 GlobalFree( info.lpszProxy );
335 GlobalFree( info.lpszProxyBypass );
336 goto end;
338 if (info.lpszProxyBypass && !(session->proxy_bypass = wcsdup( info.lpszProxyBypass )))
340 GlobalFree( info.lpszProxy );
341 GlobalFree( info.lpszProxyBypass );
342 goto end;
345 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
347 session->access = access;
348 if (proxy && !(session->proxy_server = wcsdup( proxy ))) goto end;
349 if (bypass && !(session->proxy_bypass = wcsdup( bypass ))) goto end;
352 handle = alloc_handle( &session->hdr );
354 end:
355 release_object( &session->hdr );
356 TRACE("returning %p\n", handle);
357 if (handle) SetLastError( ERROR_SUCCESS );
358 return handle;
361 static void connect_destroy( struct object_header *hdr )
363 struct connect *connect = (struct connect *)hdr;
365 TRACE("%p\n", connect);
367 release_object( &connect->session->hdr );
369 free( connect->hostname );
370 free( connect->servername );
371 free( connect->username );
372 free( connect->password );
373 free( connect );
376 static BOOL connect_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
378 struct connect *connect = (struct connect *)hdr;
380 switch (option)
382 case WINHTTP_OPTION_PARENT_HANDLE:
384 if (!validate_buffer( buffer, buflen, sizeof(HINTERNET) )) return FALSE;
386 *(HINTERNET *)buffer = ((struct object_header *)connect->session)->handle;
387 *buflen = sizeof(HINTERNET);
388 return TRUE;
390 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
391 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
393 *(DWORD *)buffer = connect->session->resolve_timeout;
394 *buflen = sizeof(DWORD);
395 return TRUE;
397 case WINHTTP_OPTION_CONNECT_TIMEOUT:
398 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
400 *(DWORD *)buffer = connect->session->connect_timeout;
401 *buflen = sizeof(DWORD);
402 return TRUE;
404 case WINHTTP_OPTION_SEND_TIMEOUT:
405 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
407 *(DWORD *)buffer = connect->session->send_timeout;
408 *buflen = sizeof(DWORD);
409 return TRUE;
411 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
412 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
414 *(DWORD *)buffer = connect->session->receive_timeout;
415 *buflen = sizeof(DWORD);
416 return TRUE;
418 case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
419 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
421 *(DWORD *)buffer = connect->session->receive_response_timeout;
422 *buflen = sizeof(DWORD);
423 return TRUE;
425 default:
426 FIXME( "unimplemented option %lu\n", option );
427 SetLastError( ERROR_INVALID_PARAMETER );
428 return FALSE;
432 static const struct object_vtbl connect_vtbl =
434 NULL,
435 connect_destroy,
436 connect_query_option,
437 NULL
440 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
442 BOOL ret = FALSE;
444 if (!wcsicmp( domain, L"<local>" ) && !wcschr( server, '.' ))
445 ret = TRUE;
446 else if (*domain == '*')
448 if (domain[1] == '.')
450 LPCWSTR dot;
452 /* For a hostname to match a wildcard, the last domain must match
453 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
454 * hostname is www.foo.a.b, it matches, but a.b does not.
456 dot = wcschr( server, '.' );
457 if (dot)
459 int len = lstrlenW( dot + 1 );
461 if (len > lstrlenW( domain + 2 ))
463 LPCWSTR ptr;
465 /* The server's domain is longer than the wildcard, so it
466 * could be a subdomain. Compare the last portion of the
467 * server's domain.
469 ptr = dot + len + 1 - lstrlenW( domain + 2 );
470 if (!wcsicmp( ptr, domain + 2 ))
472 /* This is only a match if the preceding character is
473 * a '.', i.e. that it is a matching domain. E.g.
474 * if domain is '*.b.c' and server is 'www.ab.c' they
475 * do not match.
477 ret = *(ptr - 1) == '.';
480 else
481 ret = !wcsicmp( dot + 1, domain + 2 );
485 else
486 ret = !wcsicmp( server, domain );
487 return ret;
490 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
491 #define MAX_HOST_NAME_LENGTH 256
493 static BOOL should_bypass_proxy(struct session *session, LPCWSTR server)
495 LPCWSTR ptr;
496 BOOL ret = FALSE;
498 if (!session->proxy_bypass) return FALSE;
499 ptr = session->proxy_bypass;
500 do {
501 LPCWSTR tmp = ptr;
503 ptr = wcschr( ptr, ';' );
504 if (!ptr)
505 ptr = wcschr( tmp, ' ' );
506 if (ptr)
508 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
510 WCHAR domain[MAX_HOST_NAME_LENGTH];
512 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
513 domain[ptr - tmp] = 0;
514 ret = domain_matches( server, domain );
516 ptr += 1;
518 else if (*tmp)
519 ret = domain_matches( server, tmp );
520 } while (ptr && !ret);
521 return ret;
524 BOOL set_server_for_hostname( struct connect *connect, const WCHAR *server, INTERNET_PORT port )
526 struct session *session = connect->session;
527 BOOL ret = TRUE;
529 if (session->proxy_server && !should_bypass_proxy(session, server))
531 LPCWSTR colon;
533 if ((colon = wcschr( session->proxy_server, ':' )))
535 if (!connect->servername || wcsnicmp( connect->servername,
536 session->proxy_server, colon - session->proxy_server - 1 ))
538 free( connect->servername );
539 connect->resolved = FALSE;
540 if (!(connect->servername = malloc( (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
542 ret = FALSE;
543 goto end;
545 memcpy( connect->servername, session->proxy_server, (colon - session->proxy_server) * sizeof(WCHAR) );
546 connect->servername[colon - session->proxy_server] = 0;
547 if (*(colon + 1))
548 connect->serverport = wcstol( colon + 1, NULL, 10 );
549 else
550 connect->serverport = INTERNET_DEFAULT_PORT;
553 else
555 if (!connect->servername || wcsicmp( connect->servername, session->proxy_server ))
557 free( connect->servername );
558 connect->resolved = FALSE;
559 if (!(connect->servername = wcsdup( session->proxy_server )))
561 ret = FALSE;
562 goto end;
564 connect->serverport = INTERNET_DEFAULT_PORT;
568 else if (server)
570 free( connect->servername );
571 connect->resolved = FALSE;
572 if (!(connect->servername = wcsdup( server )))
574 ret = FALSE;
575 goto end;
577 connect->serverport = port;
579 end:
580 return ret;
583 /***********************************************************************
584 * WinHttpConnect (winhttp.@)
586 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, const WCHAR *server, INTERNET_PORT port, DWORD reserved )
588 struct connect *connect;
589 struct session *session;
590 HINTERNET hconnect = NULL;
592 TRACE( "%p, %s, %u, %#lx\n", hsession, debugstr_w(server), port, reserved );
594 if (!server)
596 SetLastError( ERROR_INVALID_PARAMETER );
597 return NULL;
599 if (!(session = (struct session *)grab_object( hsession )))
601 SetLastError( ERROR_INVALID_HANDLE );
602 return NULL;
604 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
606 release_object( &session->hdr );
607 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
608 return NULL;
610 if (!(connect = calloc( 1, sizeof(*connect) )))
612 release_object( &session->hdr );
613 return NULL;
615 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
616 connect->hdr.vtbl = &connect_vtbl;
617 connect->hdr.refs = 1;
618 connect->hdr.flags = session->hdr.flags;
619 connect->hdr.callback = session->hdr.callback;
620 connect->hdr.notify_mask = session->hdr.notify_mask;
621 connect->hdr.context = session->hdr.context;
622 connect->hdr.redirect_policy = session->hdr.redirect_policy;
624 addref_object( &session->hdr );
625 connect->session = session;
627 if (!(connect->hostname = wcsdup( server ))) goto end;
628 connect->hostport = port;
629 if (!set_server_for_hostname( connect, server, port )) goto end;
631 if ((hconnect = alloc_handle( &connect->hdr )))
633 send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
636 end:
637 release_object( &connect->hdr );
638 release_object( &session->hdr );
639 TRACE("returning %p\n", hconnect);
640 if (hconnect) SetLastError( ERROR_SUCCESS );
641 return hconnect;
644 static void request_destroy( struct object_header *hdr )
646 struct request *request = (struct request *)hdr;
647 unsigned int i, j;
649 TRACE("%p\n", request);
651 stop_queue( &request->queue );
652 release_object( &request->connect->hdr );
654 if (request->cred_handle_initialized) FreeCredentialsHandle( &request->cred_handle );
655 CertFreeCertificateContext( request->server_cert );
656 CertFreeCertificateContext( request->client_cert );
658 destroy_authinfo( request->authinfo );
659 destroy_authinfo( request->proxy_authinfo );
661 free( request->verb );
662 free( request->path );
663 free( request->version );
664 free( request->raw_headers );
665 free( request->status_text );
666 for (i = 0; i < request->num_headers; i++)
668 free( request->headers[i].field );
669 free( request->headers[i].value );
671 free( request->headers );
672 for (i = 0; i < TARGET_MAX; i++)
674 for (j = 0; j < SCHEME_MAX; j++)
676 free( request->creds[i][j].username );
677 free( request->creds[i][j].password );
681 free( request );
684 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
686 int len = 0;
687 if (str) len = lstrlenW( str );
688 if (buffer && *buflen > len)
690 if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
691 buffer[len] = 0;
693 *buflen = len * sizeof(WCHAR);
696 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
698 WCHAR *ret;
699 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
701 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
702 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
703 CertNameToStrW( encoding, blob, format, ret, size );
705 return ret;
708 static BOOL copy_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
710 switch (addr->sa_family)
712 case AF_INET:
714 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
716 memcpy( addr_in, addr, sizeof(*addr_in) );
717 memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
718 return TRUE;
720 case AF_INET6:
722 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
724 memcpy( addr_in6, addr, sizeof(*addr_in6) );
725 memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
726 return TRUE;
728 default:
729 ERR("unhandled family %u\n", addr->sa_family);
730 return FALSE;
734 static BOOL request_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
736 struct request *request = (struct request *)hdr;
738 switch (option)
740 case WINHTTP_OPTION_SECURITY_FLAGS:
742 DWORD flags;
743 int bits;
745 if (!validate_buffer( buffer, buflen, sizeof(flags) )) return FALSE;
747 flags = request->security_flags;
748 if (request->netconn)
750 bits = netconn_get_cipher_strength( request->netconn );
751 if (bits >= 128)
752 flags |= SECURITY_FLAG_STRENGTH_STRONG;
753 else if (bits >= 56)
754 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
755 else
756 flags |= SECURITY_FLAG_STRENGTH_WEAK;
758 *(DWORD *)buffer = flags;
759 *buflen = sizeof(flags);
760 return TRUE;
762 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
764 const CERT_CONTEXT *cert;
766 if (!validate_buffer( buffer, buflen, sizeof(cert) )) return FALSE;
768 if (!(cert = CertDuplicateCertificateContext( request->server_cert ))) return FALSE;
769 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
770 *buflen = sizeof(cert);
771 return TRUE;
773 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
775 const CERT_CONTEXT *cert = request->server_cert;
776 const CRYPT_OID_INFO *oidInfo;
777 WINHTTP_CERTIFICATE_INFO *ci = buffer;
779 FIXME("partial stub\n");
781 if (!validate_buffer( buffer, buflen, sizeof(*ci) ) || !cert) return FALSE;
783 ci->ftExpiry = cert->pCertInfo->NotAfter;
784 ci->ftStart = cert->pCertInfo->NotBefore;
785 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
786 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
787 ci->lpszProtocolName = NULL;
788 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, cert->pCertInfo->SignatureAlgorithm.pszObjId, 0 );
789 if (oidInfo)
790 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
791 else
792 ci->lpszSignatureAlgName = NULL;
793 ci->lpszEncryptionAlgName = NULL;
794 ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
796 *buflen = sizeof(*ci);
797 return TRUE;
799 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
801 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
803 *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
804 *buflen = sizeof(DWORD);
805 return TRUE;
807 case WINHTTP_OPTION_CONNECTION_INFO:
809 WINHTTP_CONNECTION_INFO *info = buffer;
810 struct sockaddr local;
811 socklen_t len = sizeof(local);
812 const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
814 if (!validate_buffer( buffer, buflen, sizeof(*info) )) return FALSE;
816 if (!request->netconn)
818 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
819 return FALSE;
821 if (getsockname( request->netconn->socket, &local, &len )) return FALSE;
822 if (!copy_sockaddr( &local, &info->LocalAddress )) return FALSE;
823 if (!copy_sockaddr( remote, &info->RemoteAddress )) return FALSE;
824 info->cbSize = sizeof(*info);
825 return TRUE;
827 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
828 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
830 *(DWORD *)buffer = request->resolve_timeout;
831 *buflen = sizeof(DWORD);
832 return TRUE;
834 case WINHTTP_OPTION_CONNECT_TIMEOUT:
835 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
837 *(DWORD *)buffer = request->connect_timeout;
838 *buflen = sizeof(DWORD);
839 return TRUE;
841 case WINHTTP_OPTION_SEND_TIMEOUT:
842 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
844 *(DWORD *)buffer = request->send_timeout;
845 *buflen = sizeof(DWORD);
846 return TRUE;
848 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
849 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
851 *(DWORD *)buffer = request->receive_timeout;
852 *buflen = sizeof(DWORD);
853 return TRUE;
855 case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
856 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
858 *(DWORD *)buffer = request->receive_response_timeout;
859 *buflen = sizeof(DWORD);
860 return TRUE;
862 case WINHTTP_OPTION_USERNAME:
863 str_to_buffer( buffer, request->connect->username, buflen );
864 return TRUE;
866 case WINHTTP_OPTION_PASSWORD:
867 str_to_buffer( buffer, request->connect->password, buflen );
868 return TRUE;
870 case WINHTTP_OPTION_PROXY_USERNAME:
871 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
872 return TRUE;
874 case WINHTTP_OPTION_PROXY_PASSWORD:
875 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
876 return TRUE;
878 case WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS:
879 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
881 *(DWORD *)buffer = request->max_redirects;
882 *buflen = sizeof(DWORD);
883 return TRUE;
885 case WINHTTP_OPTION_HTTP_PROTOCOL_USED:
886 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
888 FIXME("WINHTTP_OPTION_HTTP_PROTOCOL_USED\n");
889 *(DWORD *)buffer = 0;
890 *buflen = sizeof(DWORD);
891 return TRUE;
893 case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
894 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
896 *(DWORD *)buffer = request->websocket_receive_buffer_size;
897 *buflen = sizeof(DWORD);
898 return TRUE;
900 case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
901 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
903 *(DWORD *)buffer = request->websocket_set_send_buffer_size;
904 *buflen = sizeof(DWORD);
905 return TRUE;
907 default:
908 FIXME( "unimplemented option %lu\n", option );
909 SetLastError( ERROR_INVALID_PARAMETER );
910 return FALSE;
914 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
916 WCHAR *ret;
917 if ((ret = malloc( (buflen + 1) * sizeof(WCHAR))))
919 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
920 ret[buflen] = 0;
921 return ret;
923 SetLastError( ERROR_OUTOFMEMORY );
924 return NULL;
927 static BOOL request_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
929 struct request *request = (struct request *)hdr;
931 switch (option)
933 case WINHTTP_OPTION_PROXY:
935 WINHTTP_PROXY_INFO *pi = buffer;
937 FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) );
938 return TRUE;
940 case WINHTTP_OPTION_DISABLE_FEATURE:
942 DWORD disable;
944 if (buflen != sizeof(DWORD))
946 SetLastError( ERROR_INSUFFICIENT_BUFFER );
947 return FALSE;
950 disable = *(DWORD *)buffer;
951 TRACE( "%#lx\n", disable );
952 hdr->disable_flags |= disable;
953 return TRUE;
955 case WINHTTP_OPTION_AUTOLOGON_POLICY:
957 DWORD policy;
959 if (buflen != sizeof(DWORD))
961 SetLastError( ERROR_INSUFFICIENT_BUFFER );
962 return FALSE;
965 policy = *(DWORD *)buffer;
966 TRACE( "%#lx\n", policy );
967 hdr->logon_policy = policy;
968 return TRUE;
970 case WINHTTP_OPTION_REDIRECT_POLICY:
972 DWORD policy;
974 if (buflen != sizeof(DWORD))
976 SetLastError( ERROR_INSUFFICIENT_BUFFER );
977 return FALSE;
980 policy = *(DWORD *)buffer;
981 TRACE( "%#lx\n", policy );
982 hdr->redirect_policy = policy;
983 return TRUE;
985 case WINHTTP_OPTION_SECURITY_FLAGS:
987 DWORD flags;
988 static const DWORD accepted = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
989 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
990 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
991 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
993 if (buflen < sizeof(DWORD))
995 SetLastError( ERROR_INSUFFICIENT_BUFFER );
996 return FALSE;
998 flags = *(DWORD *)buffer;
999 TRACE( "%#lx\n", flags );
1000 if (flags && (flags & ~accepted))
1002 SetLastError( ERROR_INVALID_PARAMETER );
1003 return FALSE;
1005 request->security_flags = flags;
1006 return TRUE;
1008 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
1009 request->resolve_timeout = *(DWORD *)buffer;
1010 return TRUE;
1012 case WINHTTP_OPTION_CONNECT_TIMEOUT:
1013 request->connect_timeout = *(DWORD *)buffer;
1014 return TRUE;
1016 case WINHTTP_OPTION_SEND_TIMEOUT:
1017 request->send_timeout = *(DWORD *)buffer;
1018 return TRUE;
1020 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
1021 request->receive_timeout = *(DWORD *)buffer;
1022 return TRUE;
1024 case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
1025 request->receive_response_timeout = *(DWORD *)buffer;
1026 return TRUE;
1028 case WINHTTP_OPTION_USERNAME:
1030 struct connect *connect = request->connect;
1032 free( connect->username );
1033 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
1034 return TRUE;
1036 case WINHTTP_OPTION_PASSWORD:
1038 struct connect *connect = request->connect;
1040 free( connect->password );
1041 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
1042 return TRUE;
1044 case WINHTTP_OPTION_PROXY_USERNAME:
1046 struct session *session = request->connect->session;
1048 free( session->proxy_username );
1049 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
1050 return TRUE;
1052 case WINHTTP_OPTION_PROXY_PASSWORD:
1054 struct session *session = request->connect->session;
1056 free( session->proxy_password );
1057 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
1058 return TRUE;
1060 case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
1062 const CERT_CONTEXT *cert;
1064 if (!(hdr->flags & WINHTTP_FLAG_SECURE))
1066 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
1067 return FALSE;
1069 if (!buffer)
1071 CertFreeCertificateContext( request->client_cert );
1072 request->client_cert = NULL;
1074 else if (buflen >= sizeof(*cert))
1076 if (!(cert = CertDuplicateCertificateContext( buffer ))) return FALSE;
1077 CertFreeCertificateContext( request->client_cert );
1078 request->client_cert = cert;
1080 else
1082 SetLastError( ERROR_INVALID_PARAMETER );
1083 return FALSE;
1086 if (request->cred_handle_initialized)
1088 FreeCredentialsHandle( &request->cred_handle );
1089 request->cred_handle_initialized = FALSE;
1092 return TRUE;
1094 case WINHTTP_OPTION_ENABLE_FEATURE:
1095 if(buflen == sizeof( DWORD ) && *(DWORD *)buffer == WINHTTP_ENABLE_SSL_REVOCATION)
1097 request->check_revocation = TRUE;
1098 SetLastError( NO_ERROR );
1099 return TRUE;
1101 else
1103 SetLastError( ERROR_INVALID_PARAMETER );
1104 return FALSE;
1107 case WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET:
1108 request->flags |= REQUEST_FLAG_WEBSOCKET_UPGRADE;
1109 return TRUE;
1111 case WINHTTP_OPTION_CONNECT_RETRIES:
1112 FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n");
1113 return TRUE;
1115 case WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS:
1116 if (buflen == sizeof(DWORD))
1118 request->max_redirects = *(DWORD *)buffer;
1119 SetLastError(NO_ERROR);
1120 return TRUE;
1123 SetLastError(ERROR_INVALID_PARAMETER);
1124 return FALSE;
1126 case WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE:
1127 FIXME("WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE\n");
1128 return TRUE;
1130 case WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE:
1131 FIXME("WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE\n");
1132 return TRUE;
1134 case WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL:
1135 if (buflen == sizeof(DWORD))
1137 FIXME( "WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL %#lx\n", *(DWORD *)buffer );
1138 return TRUE;
1140 SetLastError(ERROR_INVALID_PARAMETER);
1141 return FALSE;
1143 case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
1145 DWORD buffer_size;
1147 if (buflen != sizeof(buffer_size))
1149 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1150 return FALSE;
1153 buffer_size = *(DWORD *)buffer;
1154 WARN( "Setting websocket receive buffer size currently has not effct, size %lu\n", buffer_size );
1155 request->websocket_receive_buffer_size = buffer_size;
1156 return TRUE;
1159 case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
1161 DWORD buffer_size;
1163 if (buflen != sizeof(buffer_size))
1165 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1166 return FALSE;
1169 buffer_size = *(DWORD *)buffer;
1170 request->websocket_set_send_buffer_size = buffer_size;
1171 TRACE( "Websocket send buffer size %lu.\n", buffer_size);
1172 return TRUE;
1175 default:
1176 FIXME( "unimplemented option %lu\n", option );
1177 SetLastError( ERROR_WINHTTP_INVALID_OPTION );
1178 return FALSE;
1182 static const struct object_vtbl request_vtbl =
1184 NULL,
1185 request_destroy,
1186 request_query_option,
1187 request_set_option
1190 static BOOL add_accept_types_header( struct request *request, const WCHAR **types )
1192 static const DWORD flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA;
1194 if (!types) return TRUE;
1195 while (*types)
1197 if (process_header( request, L"Accept", *types, flags, TRUE )) return FALSE;
1198 types++;
1200 return TRUE;
1203 static WCHAR *get_request_path( const WCHAR *object )
1205 int len = object ? lstrlenW(object) : 0;
1206 WCHAR *p, *ret;
1208 if (!object || object[0] != '/') len++;
1209 if (!(p = ret = malloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
1210 if (!object || object[0] != '/') *p++ = '/';
1211 if (object) lstrcpyW( p, object );
1212 ret[len] = 0;
1213 return ret;
1216 /***********************************************************************
1217 * WinHttpOpenRequest (winhttp.@)
1219 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, const WCHAR *object, const WCHAR *version,
1220 const WCHAR *referrer, const WCHAR **types, DWORD flags )
1222 struct request *request;
1223 struct connect *connect;
1224 HINTERNET hrequest = NULL;
1226 TRACE( "%p, %s, %s, %s, %s, %p, %#lx\n", hconnect, debugstr_w(verb), debugstr_w(object),
1227 debugstr_w(version), debugstr_w(referrer), types, flags );
1229 if (types && TRACE_ON(winhttp))
1231 const WCHAR **iter;
1232 TRACE("accept types:\n");
1233 for (iter = types; *iter; iter++) TRACE(" %s\n", debugstr_w(*iter));
1236 if (!(connect = (struct connect *)grab_object( hconnect )))
1238 SetLastError( ERROR_INVALID_HANDLE );
1239 return NULL;
1241 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1243 release_object( &connect->hdr );
1244 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1245 return NULL;
1247 if (!(request = calloc( 1, sizeof(*request) )))
1249 release_object( &connect->hdr );
1250 return NULL;
1252 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1253 request->hdr.vtbl = &request_vtbl;
1254 request->hdr.refs = 1;
1255 request->hdr.flags = flags;
1256 request->hdr.callback = connect->hdr.callback;
1257 request->hdr.notify_mask = connect->hdr.notify_mask;
1258 request->hdr.context = connect->hdr.context;
1259 request->hdr.redirect_policy = connect->hdr.redirect_policy;
1260 init_queue( &request->queue );
1262 addref_object( &connect->hdr );
1263 request->connect = connect;
1265 request->resolve_timeout = connect->session->resolve_timeout;
1266 request->connect_timeout = connect->session->connect_timeout;
1267 request->send_timeout = connect->session->send_timeout;
1268 request->receive_timeout = connect->session->receive_timeout;
1269 request->receive_response_timeout = connect->session->receive_response_timeout;
1270 request->max_redirects = 10;
1271 request->websocket_receive_buffer_size = connect->session->websocket_receive_buffer_size;
1272 request->websocket_send_buffer_size = connect->session->websocket_send_buffer_size;
1273 request->websocket_set_send_buffer_size = request->websocket_send_buffer_size;
1274 request->read_reply_status = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
1276 if (!verb || !verb[0]) verb = L"GET";
1277 if (!(request->verb = wcsdup( verb ))) goto end;
1278 if (!(request->path = get_request_path( object ))) goto end;
1280 if (!version || !version[0]) version = L"HTTP/1.1";
1281 if (!(request->version = wcsdup( version ))) goto end;
1282 if (!(add_accept_types_header( request, types ))) goto end;
1284 if ((hrequest = alloc_handle( &request->hdr )))
1286 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1289 end:
1290 release_object( &request->hdr );
1291 release_object( &connect->hdr );
1292 TRACE("returning %p\n", hrequest);
1293 if (hrequest) SetLastError( ERROR_SUCCESS );
1294 return hrequest;
1297 /***********************************************************************
1298 * WinHttpCloseHandle (winhttp.@)
1300 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1302 struct object_header *hdr;
1304 TRACE("%p\n", handle);
1306 if (!(hdr = grab_object( handle )))
1308 SetLastError( ERROR_INVALID_HANDLE );
1309 return FALSE;
1311 release_object( hdr );
1312 free_handle( handle );
1313 SetLastError( ERROR_SUCCESS );
1314 return TRUE;
1317 static BOOL query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
1319 BOOL ret = FALSE;
1321 if (!buflen)
1323 SetLastError( ERROR_INVALID_PARAMETER );
1324 return FALSE;
1327 switch (option)
1329 case WINHTTP_OPTION_WORKER_THREAD_COUNT:
1331 FIXME( "WINHTTP_OPTION_WORKER_THREAD_COUNT semi-stub.\n" );
1332 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
1334 *(DWORD *)buffer = 0;
1335 *buflen = sizeof(DWORD);
1336 return TRUE;
1338 case WINHTTP_OPTION_CONTEXT_VALUE:
1340 if (!validate_buffer( buffer, buflen, sizeof(DWORD_PTR) )) return FALSE;
1342 *(DWORD_PTR *)buffer = hdr->context;
1343 *buflen = sizeof(DWORD_PTR);
1344 return TRUE;
1346 default:
1347 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1348 else
1350 FIXME( "unimplemented option %lu\n", option );
1351 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1352 return FALSE;
1354 break;
1356 return ret;
1359 /***********************************************************************
1360 * WinHttpQueryOption (winhttp.@)
1362 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, void *buffer, DWORD *buflen )
1364 BOOL ret = FALSE;
1365 struct object_header *hdr;
1367 TRACE( "%p, %lu, %p, %p\n", handle, option, buffer, buflen );
1369 if (!(hdr = grab_object( handle )))
1371 SetLastError( ERROR_INVALID_HANDLE );
1372 return FALSE;
1375 ret = query_option( hdr, option, buffer, buflen );
1377 release_object( hdr );
1378 if (ret) SetLastError( ERROR_SUCCESS );
1379 return ret;
1382 static BOOL set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
1384 BOOL ret = TRUE;
1386 if (!buffer && buflen)
1388 SetLastError( ERROR_INVALID_PARAMETER );
1389 return FALSE;
1392 switch (option)
1394 case WINHTTP_OPTION_CONTEXT_VALUE:
1396 if (buflen != sizeof(DWORD_PTR))
1398 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1399 return FALSE;
1402 hdr->context = *(DWORD_PTR *)buffer;
1403 return TRUE;
1405 default:
1406 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1407 else
1409 FIXME( "unimplemented option %lu\n", option );
1410 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1411 return FALSE;
1413 break;
1415 return ret;
1418 /***********************************************************************
1419 * WinHttpSetOption (winhttp.@)
1421 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, void *buffer, DWORD buflen )
1423 BOOL ret = FALSE;
1424 struct object_header *hdr;
1426 TRACE( "%p, %lu, %p, %lu\n", handle, option, buffer, buflen );
1428 if (!(hdr = grab_object( handle )))
1430 SetLastError( ERROR_INVALID_HANDLE );
1431 return FALSE;
1434 ret = set_option( hdr, option, buffer, buflen );
1436 release_object( hdr );
1437 if (ret) SetLastError( ERROR_SUCCESS );
1438 return ret;
1441 static IP_ADAPTER_ADDRESSES *get_adapters(void)
1443 ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
1444 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
1445 IP_ADAPTER_ADDRESSES *tmp, *ret;
1447 if (!(ret = malloc( size ))) return NULL;
1448 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
1449 while (err == ERROR_BUFFER_OVERFLOW)
1451 if (!(tmp = realloc( ret, size ))) break;
1452 ret = tmp;
1453 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
1455 if (err == ERROR_SUCCESS) return ret;
1456 free( ret );
1457 return NULL;
1460 static WCHAR *detect_autoproxyconfig_url_dhcp(void)
1462 IP_ADAPTER_ADDRESSES *adapters, *ptr;
1463 DHCPCAPI_PARAMS_ARRAY send_params, recv_params;
1464 DHCPCAPI_PARAMS param;
1465 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL;
1466 DWORD err, size;
1467 BYTE *tmp, *buf = NULL;
1469 if (!(adapters = get_adapters())) return NULL;
1471 memset( &send_params, 0, sizeof(send_params) );
1472 memset( &param, 0, sizeof(param) );
1473 param.OptionId = OPTION_MSFT_IE_PROXY;
1474 recv_params.nParams = 1;
1475 recv_params.Params = &param;
1477 for (ptr = adapters; ptr; ptr = ptr->Next)
1479 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
1480 TRACE( "adapter '%s' type %lu dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled );
1482 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1483 /* FIXME: also skip adapters where DHCP is disabled */
1485 size = 256;
1486 if (!(buf = malloc( size ))) goto done;
1487 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
1488 buf, &size, NULL );
1489 while (err == ERROR_MORE_DATA)
1491 if (!(tmp = realloc( buf, size ))) goto done;
1492 buf = tmp;
1493 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
1494 buf, &size, NULL );
1496 if (err == ERROR_SUCCESS && param.nBytesData)
1498 int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 );
1499 if ((ret = malloc( (len + 1) * sizeof(WCHAR) )))
1501 MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len );
1502 ret[len] = 0;
1504 TRACE("returning %s\n", debugstr_w(ret));
1505 break;
1509 done:
1510 free( buf );
1511 free( adapters );
1512 return ret;
1515 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1517 char *ret;
1518 DWORD size = 0;
1520 GetComputerNameExA( format, NULL, &size );
1521 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1522 if (!(ret = malloc( size ))) return NULL;
1523 if (!GetComputerNameExA( format, ret, &size ))
1525 free( ret );
1526 return NULL;
1528 return ret;
1531 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1533 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1535 if (len_suffix > len_domain) return FALSE;
1536 if (!stricmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1537 return FALSE;
1540 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1542 return getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1545 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1547 char name[NI_MAXHOST];
1548 WCHAR *ret, *p;
1549 int len;
1551 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1552 if (!ai) return NULL;
1554 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1556 len = lstrlenW( L"http://" ) + strlen( hostname ) + lstrlenW( L"/wpad.dat" );
1557 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1558 lstrcpyW( p, L"http://" );
1559 p += lstrlenW( L"http://" );
1560 while (*hostname) { *p++ = *hostname++; }
1561 lstrcpyW( p, L"/wpad.dat" );
1562 return ret;
1565 static WCHAR *detect_autoproxyconfig_url_dns(void)
1567 char *fqdn, *domain, *p;
1568 WCHAR *ret = NULL;
1570 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL;
1571 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1573 free( fqdn );
1574 return NULL;
1576 p = fqdn;
1577 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1579 char *name;
1580 struct addrinfo *ai, hints;
1581 int res;
1583 if (!(name = malloc( sizeof("wpad") + strlen(p) )))
1585 free( fqdn );
1586 free( domain );
1587 return NULL;
1589 strcpy( name, "wpad" );
1590 strcat( name, p );
1591 memset( &hints, 0, sizeof(hints) );
1592 hints.ai_flags = AI_ALL | AI_DNS_ONLY;
1593 hints.ai_family = AF_UNSPEC;
1594 res = getaddrinfo( name, NULL, &hints, &ai );
1595 if (!res)
1597 ret = build_wpad_url( name, ai );
1598 freeaddrinfo( ai );
1599 if (ret)
1601 TRACE("returning %s\n", debugstr_w(ret));
1602 free( name );
1603 break;
1606 free( name );
1607 p++;
1609 free( domain );
1610 free( fqdn );
1611 return ret;
1614 /***********************************************************************
1615 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1617 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, WCHAR **url )
1619 TRACE( "%#lx, %p\n", flags, url );
1621 if (!flags || !url)
1623 SetLastError( ERROR_INVALID_PARAMETER );
1624 return FALSE;
1626 *url = NULL;
1627 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1629 *url = detect_autoproxyconfig_url_dhcp();
1631 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1633 if (!*url) *url = detect_autoproxyconfig_url_dns();
1635 if (!*url)
1637 SetLastError( ERROR_WINHTTP_AUTODETECTION_FAILED );
1638 return FALSE;
1640 SetLastError( ERROR_SUCCESS );
1641 return TRUE;
1644 static const WCHAR path_connections[] =
1645 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections";
1647 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1648 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1649 static const DWORD PROXY_TYPE_DIRECT = 1;
1650 static const DWORD PROXY_TYPE_PROXY = 2;
1651 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1652 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1654 struct connection_settings_header
1656 DWORD magic;
1657 DWORD unknown; /* always zero? */
1658 DWORD flags; /* one or more of PROXY_* */
1661 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1663 const BYTE *begin;
1665 for (begin = src; src - begin < len; src++, dst++)
1666 *dst = *src;
1667 *dst = 0;
1670 /***********************************************************************
1671 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1673 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1675 LONG l;
1676 HKEY key;
1677 BOOL got_from_reg = FALSE, direct = TRUE;
1678 WCHAR *envproxy;
1680 TRACE("%p\n", info);
1682 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, KEY_READ, &key );
1683 if (!l)
1685 DWORD type, size = 0;
1687 l = RegQueryValueExW( key, L"WinHttpSettings", NULL, &type, NULL, &size );
1688 if (!l && type == REG_BINARY &&
1689 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1691 BYTE *buf = malloc( size );
1693 if (buf)
1695 struct connection_settings_header *hdr =
1696 (struct connection_settings_header *)buf;
1697 DWORD *len = (DWORD *)(hdr + 1);
1699 l = RegQueryValueExW( key, L"WinHttpSettings", NULL, NULL, buf,
1700 &size );
1701 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1702 hdr->unknown == 0)
1704 if (hdr->flags & PROXY_TYPE_PROXY)
1706 BOOL sane = FALSE;
1707 LPWSTR proxy = NULL;
1708 LPWSTR proxy_bypass = NULL;
1710 /* Sanity-check length of proxy string */
1711 if ((BYTE *)len - buf + *len <= size)
1713 sane = TRUE;
1714 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1715 if (proxy)
1716 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1717 len = (DWORD *)((BYTE *)(len + 1) + *len);
1719 if (sane)
1721 /* Sanity-check length of proxy bypass string */
1722 if ((BYTE *)len - buf + *len <= size)
1724 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1725 if (proxy_bypass)
1726 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1728 else
1730 sane = FALSE;
1731 GlobalFree( proxy );
1732 proxy = NULL;
1735 info->lpszProxy = proxy;
1736 info->lpszProxyBypass = proxy_bypass;
1737 if (sane)
1739 got_from_reg = TRUE;
1740 direct = FALSE;
1741 info->dwAccessType =
1742 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1743 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1744 debugstr_w(info->lpszProxy),
1745 debugstr_w(info->lpszProxyBypass));
1749 free( buf );
1752 RegCloseKey( key );
1754 if (!got_from_reg && (envproxy = _wgetenv( L"http_proxy" )))
1756 WCHAR *colon, *http_proxy = NULL;
1758 if (!(colon = wcschr( envproxy, ':' ))) http_proxy = envproxy;
1759 else
1761 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1763 /* It's a scheme, check that it's http */
1764 if (!wcsncmp( envproxy, L"http://", 7 )) http_proxy = envproxy + 7;
1765 else WARN("unsupported scheme in $http_proxy: %s\n", debugstr_w(envproxy));
1767 else http_proxy = envproxy;
1770 if (http_proxy && http_proxy[0])
1772 direct = FALSE;
1773 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1774 info->lpszProxy = GlobalAlloc( 0, (lstrlenW(http_proxy) + 1) * sizeof(WCHAR) );
1775 wcscpy( info->lpszProxy, http_proxy );
1776 info->lpszProxyBypass = NULL;
1777 TRACE("http proxy (from environment) = %s\n", debugstr_w(info->lpszProxy));
1780 if (direct)
1782 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1783 info->lpszProxy = NULL;
1784 info->lpszProxyBypass = NULL;
1786 SetLastError( ERROR_SUCCESS );
1787 return TRUE;
1790 /***********************************************************************
1791 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1793 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1795 HKEY hkey = NULL;
1796 struct connection_settings_header *hdr = NULL;
1797 DWORD type, offset, len, size = 0;
1798 BOOL ret = FALSE;
1800 TRACE("%p\n", config);
1802 if (!config)
1804 SetLastError( ERROR_INVALID_PARAMETER );
1805 return FALSE;
1807 memset( config, 0, sizeof(*config) );
1808 config->fAutoDetect = TRUE;
1810 if (RegOpenKeyExW( HKEY_CURRENT_USER, path_connections, 0, KEY_READ, &hkey ) ||
1811 RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, NULL, &size ) ||
1812 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1814 ret = TRUE;
1815 goto done;
1817 if (!(hdr = malloc( size ))) goto done;
1818 if (RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, (BYTE *)hdr, &size ) ||
1819 hdr->magic != WININET_SETTINGS_MAGIC)
1821 ret = TRUE;
1822 goto done;
1825 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1826 offset = sizeof(*hdr);
1827 if (offset + sizeof(DWORD) > size) goto done;
1828 len = *(DWORD *)((char *)hdr + offset);
1829 offset += sizeof(DWORD);
1830 if (len && hdr->flags & PROXY_TYPE_PROXY)
1832 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1833 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1835 offset += len;
1836 if (offset + sizeof(DWORD) > size) goto done;
1837 len = *(DWORD *)((char *)hdr + offset);
1838 offset += sizeof(DWORD);
1839 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1841 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1842 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1844 offset += len;
1845 if (offset + sizeof(DWORD) > size) goto done;
1846 len = *(DWORD *)((char *)hdr + offset);
1847 offset += sizeof(DWORD);
1848 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1850 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1851 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1853 ret = TRUE;
1855 done:
1856 RegCloseKey( hkey );
1857 free( hdr );
1858 if (!ret)
1860 GlobalFree( config->lpszAutoConfigUrl );
1861 config->lpszAutoConfigUrl = NULL;
1862 GlobalFree( config->lpszProxy );
1863 config->lpszProxy = NULL;
1864 GlobalFree( config->lpszProxyBypass );
1865 config->lpszProxyBypass = NULL;
1867 else SetLastError( ERROR_SUCCESS );
1868 return ret;
1871 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1873 const char *p;
1874 WCHAR *q;
1875 int len;
1877 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1878 info->lpszProxy = NULL;
1879 info->lpszProxyBypass = NULL;
1881 TRACE("%s\n", debugstr_a( result ));
1883 p = result;
1884 while (*p == ' ') p++;
1885 len = strlen( p );
1886 if (len >= 5 && !_strnicmp( p, "PROXY", sizeof("PROXY") - 1 ))
1888 p += 5;
1889 while (*p == ' ') p++;
1890 if (!*p || *p == ';') return TRUE;
1891 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1892 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1893 for (; *q; q++)
1895 if (*q == ' ' || *q == ';')
1897 *q = 0;
1898 break;
1902 return TRUE;
1905 static SRWLOCK cache_lock = SRWLOCK_INIT;
1906 static DWORD cached_script_size;
1907 static ULONGLONG cache_update_time;
1908 static char *cached_script;
1909 static WCHAR *cached_url;
1911 static BOOL get_cached_script( const WCHAR *url, char **buffer, DWORD *out_size )
1913 BOOL ret = FALSE;
1915 *buffer = NULL;
1916 *out_size = 0;
1918 AcquireSRWLockExclusive( &cache_lock );
1919 if (cached_url && !wcscmp( cached_url, url ) && GetTickCount64() - cache_update_time < 60000)
1921 ret = TRUE;
1922 if (cached_script && (*buffer = malloc( cached_script_size )))
1924 memcpy( *buffer, cached_script, cached_script_size );
1925 *out_size = cached_script_size;
1928 ReleaseSRWLockExclusive( &cache_lock );
1929 return ret;
1932 static void cache_script( const WCHAR *url, char *buffer, DWORD size )
1934 AcquireSRWLockExclusive( &cache_lock );
1935 free( cached_url );
1936 free( cached_script );
1937 cached_script_size = 0;
1938 cached_script = NULL;
1940 if ((cached_url = wcsdup( url )) && buffer && (cached_script = malloc( size )))
1942 memcpy( cached_script, buffer, size );
1943 cached_script_size = size;
1945 cache_update_time = GetTickCount64();
1946 ReleaseSRWLockExclusive( &cache_lock );
1949 static char *download_script( const WCHAR *url, DWORD *out_size )
1951 static const WCHAR *acceptW[] = {L"*/*", NULL};
1952 HINTERNET ses, con = NULL, req = NULL;
1953 WCHAR *hostname;
1954 URL_COMPONENTSW uc;
1955 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1956 char *tmp, *buffer;
1958 if (get_cached_script( url, &buffer, out_size ))
1960 TRACE( "Returning cached result.\n" );
1961 if (!buffer) SetLastError( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1962 return buffer;
1965 memset( &uc, 0, sizeof(uc) );
1966 uc.dwStructSize = sizeof(uc);
1967 uc.dwHostNameLength = -1;
1968 uc.dwUrlPathLength = -1;
1969 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1970 if (!(hostname = malloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1971 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1972 hostname[uc.dwHostNameLength] = 0;
1974 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1975 WinHttpSetTimeouts( ses, 5000, 60000, 30000, 30000 );
1976 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1977 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1978 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1979 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1981 if (!WinHttpReceiveResponse( req, 0 )) goto done;
1982 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1983 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1985 size = 4096;
1986 if (!(buffer = malloc( size ))) goto done;
1987 to_read = size;
1988 offset = 0;
1989 for (;;)
1991 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1992 if (!bytes_read) break;
1993 to_read -= bytes_read;
1994 offset += bytes_read;
1995 *out_size += bytes_read;
1996 if (!to_read)
1998 to_read = size;
1999 size *= 2;
2000 if (!(tmp = realloc( buffer, size ))) goto done;
2001 buffer = tmp;
2005 done:
2006 WinHttpCloseHandle( req );
2007 WinHttpCloseHandle( con );
2008 WinHttpCloseHandle( ses );
2009 free( hostname );
2010 cache_script( url, buffer, *out_size );
2011 if (!buffer) SetLastError( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
2012 return buffer;
2015 struct AUTO_PROXY_SCRIPT_BUFFER
2017 DWORD dwStructSize;
2018 LPSTR lpszScriptBuffer;
2019 DWORD dwScriptBufferSize;
2022 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
2023 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
2024 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
2026 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
2028 BOOL ret;
2029 char *result, *urlA;
2030 DWORD len_result;
2031 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
2032 URL_COMPONENTSW uc;
2034 buffer.dwStructSize = sizeof(buffer);
2035 buffer.lpszScriptBuffer = script;
2036 buffer.dwScriptBufferSize = size;
2038 if (!(urlA = strdupWA( url ))) return FALSE;
2039 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
2041 free( urlA );
2042 return FALSE;
2045 memset( &uc, 0, sizeof(uc) );
2046 uc.dwStructSize = sizeof(uc);
2047 uc.dwHostNameLength = -1;
2049 if ((ret = WinHttpCrackUrl( url, 0, 0, &uc )))
2051 char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
2053 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
2054 hostnameA, strlen(hostnameA), &result, &len_result )))
2056 ret = parse_script_result( result, info );
2057 free( result );
2060 free( hostnameA );
2062 free( urlA );
2063 InternetDeInitializeAutoProxyDll( NULL, 0 );
2064 return ret;
2067 /***********************************************************************
2068 * WinHttpGetProxyForUrl (winhttp.@)
2070 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
2071 WINHTTP_PROXY_INFO *info )
2073 WCHAR *detected_pac_url = NULL;
2074 const WCHAR *pac_url;
2075 struct session *session;
2076 char *script;
2077 DWORD size;
2078 BOOL ret = FALSE;
2080 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
2082 if (!(session = (struct session *)grab_object( hsession )))
2084 SetLastError( ERROR_INVALID_HANDLE );
2085 return FALSE;
2087 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
2089 release_object( &session->hdr );
2090 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2091 return FALSE;
2093 if (!url || !options || !info ||
2094 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
2095 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
2096 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
2097 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)) ||
2098 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL && !options->lpszAutoConfigUrl))
2100 release_object( &session->hdr );
2101 SetLastError( ERROR_INVALID_PARAMETER );
2102 return FALSE;
2104 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
2105 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
2106 goto done;
2108 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
2109 else pac_url = detected_pac_url;
2111 if ((script = download_script( pac_url, &size )))
2113 ret = run_script( script, size, url, info );
2114 free( script );
2117 done:
2118 GlobalFree( detected_pac_url );
2119 release_object( &session->hdr );
2120 if (ret) SetLastError( ERROR_SUCCESS );
2121 return ret;
2124 /***********************************************************************
2125 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
2127 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
2129 LONG l;
2130 HKEY key;
2131 BOOL ret = FALSE;
2132 const WCHAR *src;
2134 TRACE("%p\n", info);
2136 if (!info)
2138 SetLastError( ERROR_INVALID_PARAMETER );
2139 return FALSE;
2141 switch (info->dwAccessType)
2143 case WINHTTP_ACCESS_TYPE_NO_PROXY:
2144 break;
2145 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
2146 if (!info->lpszProxy)
2148 SetLastError( ERROR_INVALID_PARAMETER );
2149 return FALSE;
2151 /* Only ASCII characters are allowed */
2152 for (src = info->lpszProxy; *src; src++)
2153 if (*src > 0x7f)
2155 SetLastError( ERROR_INVALID_PARAMETER );
2156 return FALSE;
2158 if (info->lpszProxyBypass)
2160 for (src = info->lpszProxyBypass; *src; src++)
2161 if (*src > 0x7f)
2163 SetLastError( ERROR_INVALID_PARAMETER );
2164 return FALSE;
2167 break;
2168 default:
2169 SetLastError( ERROR_INVALID_PARAMETER );
2170 return FALSE;
2173 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, NULL, 0,
2174 KEY_WRITE, NULL, &key, NULL );
2175 if (!l)
2177 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
2178 BYTE *buf;
2180 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
2182 size += lstrlenW( info->lpszProxy );
2183 if (info->lpszProxyBypass)
2184 size += lstrlenW( info->lpszProxyBypass );
2186 if ((buf = malloc( size )))
2188 struct connection_settings_header *hdr =
2189 (struct connection_settings_header *)buf;
2190 DWORD *len = (DWORD *)(hdr + 1);
2192 hdr->magic = WINHTTP_SETTINGS_MAGIC;
2193 hdr->unknown = 0;
2194 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
2196 BYTE *dst;
2198 hdr->flags = PROXY_TYPE_PROXY;
2199 *len++ = lstrlenW( info->lpszProxy );
2200 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
2201 src++, dst++)
2202 *dst = *src;
2203 len = (DWORD *)dst;
2204 if (info->lpszProxyBypass)
2206 *len++ = lstrlenW( info->lpszProxyBypass );
2207 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
2208 src++, dst++)
2209 *dst = *src;
2211 else
2212 *len++ = 0;
2214 else
2216 hdr->flags = PROXY_TYPE_DIRECT;
2217 *len++ = 0;
2218 *len++ = 0;
2220 l = RegSetValueExW( key, L"WinHttpSettings", 0, REG_BINARY, buf, size );
2221 if (!l)
2222 ret = TRUE;
2223 free( buf );
2225 RegCloseKey( key );
2227 if (ret) SetLastError( ERROR_SUCCESS );
2228 return ret;
2231 /***********************************************************************
2232 * WinHttpCreateProxyResolver (winhttp.@)
2234 DWORD WINAPI WinHttpCreateProxyResolver( HINTERNET hsession, HINTERNET *hresolver )
2236 FIXME("%p, %p\n", hsession, hresolver);
2237 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2240 /***********************************************************************
2241 * WinHttpFreeProxyResult (winhttp.@)
2243 void WINAPI WinHttpFreeProxyResult( WINHTTP_PROXY_RESULT *result )
2245 FIXME("%p\n", result);
2248 /***********************************************************************
2249 * WinHttpFreeProxyResultEx (winhttp.@)
2251 void WINAPI WinHttpFreeProxyResultEx( WINHTTP_PROXY_RESULT_EX *result )
2253 FIXME("%p\n", result);
2256 /***********************************************************************
2257 * WinHttpFreeProxySettings (winhttp.@)
2259 void WINAPI WinHttpFreeProxySettings( WINHTTP_PROXY_SETTINGS *settings )
2261 FIXME("%p\n", settings);
2264 /***********************************************************************
2265 * WinHttpGetProxyForUrlEx (winhttp.@)
2267 DWORD WINAPI WinHttpGetProxyForUrlEx( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options,
2268 DWORD_PTR ctx )
2270 FIXME( "%p, %s, %p, %Ix\n", hresolver, debugstr_w(url), options, ctx );
2271 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2274 /***********************************************************************
2275 * WinHttpGetProxyForUrlEx2 (winhttp.@)
2277 DWORD WINAPI WinHttpGetProxyForUrlEx2( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options,
2278 DWORD selection_len, BYTE *selection, DWORD_PTR ctx )
2280 FIXME( "%p, %s, %p, %lu, %p, %Ix\n", hresolver, debugstr_w(url), options, selection_len, selection, ctx );
2281 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2284 /***********************************************************************
2285 * WinHttpGetProxyResult (winhttp.@)
2287 DWORD WINAPI WinHttpGetProxyResult( HINTERNET hresolver, WINHTTP_PROXY_RESULT *result )
2289 FIXME("%p, %p\n", hresolver, result);
2290 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2293 /***********************************************************************
2294 * WinHttpGetProxyResultEx (winhttp.@)
2296 DWORD WINAPI WinHttpGetProxyResultEx( HINTERNET hresolver, WINHTTP_PROXY_RESULT_EX *result )
2298 FIXME("%p, %p\n", hresolver, result);
2299 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2302 /***********************************************************************
2303 * WinHttpGetProxySettingsVersion (winhttp.@)
2305 DWORD WINAPI WinHttpGetProxySettingsVersion( HINTERNET hsession, DWORD *version )
2307 FIXME("%p, %p\n", hsession, version);
2308 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2311 /***********************************************************************
2312 * WinHttpReadProxySettings (winhttp.@)
2314 DWORD WINAPI WinHttpReadProxySettings( HINTERNET hsession, const WCHAR *connection, BOOL use_defaults,
2315 BOOL set_autodiscover, DWORD *version, BOOL *defaults_returned,
2316 WINHTTP_PROXY_SETTINGS *settings)
2318 FIXME("%p, %s, %d, %d, %p, %p, %p\n", hsession, debugstr_w(connection), use_defaults, set_autodiscover,
2319 version, defaults_returned, settings);
2320 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2323 /***********************************************************************
2324 * WinHttpResetAutoProxy (winhttp.@)
2326 DWORD WINAPI WinHttpResetAutoProxy( HINTERNET hsession, DWORD flags )
2328 FIXME( "%p, %#lx\n", hsession, flags );
2329 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2332 DWORD WINAPI WinHttpWriteProxySettings( HINTERNET hsession, BOOL force, WINHTTP_PROXY_SETTINGS *settings )
2334 FIXME("%p, %d, %p\n", hsession, force, settings);
2335 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2338 /***********************************************************************
2339 * WinHttpSetStatusCallback (winhttp.@)
2341 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2342 DWORD flags, DWORD_PTR reserved )
2344 struct object_header *hdr;
2345 WINHTTP_STATUS_CALLBACK ret;
2347 TRACE( "%p, %p, %#lx, %Ix\n", handle, callback, flags, reserved );
2349 if (!(hdr = grab_object( handle )))
2351 SetLastError( ERROR_INVALID_HANDLE );
2352 return WINHTTP_INVALID_STATUS_CALLBACK;
2354 ret = hdr->callback;
2355 hdr->callback = callback;
2356 hdr->notify_mask = flags;
2358 release_object( hdr );
2359 SetLastError( ERROR_SUCCESS );
2360 return ret;
2363 /***********************************************************************
2364 * WinHttpSetTimeouts (winhttp.@)
2366 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2368 BOOL ret = TRUE;
2369 struct object_header *hdr;
2371 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2373 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2375 SetLastError( ERROR_INVALID_PARAMETER );
2376 return FALSE;
2379 if (!(hdr = grab_object( handle )))
2381 SetLastError( ERROR_INVALID_HANDLE );
2382 return FALSE;
2385 switch(hdr->type)
2387 case WINHTTP_HANDLE_TYPE_REQUEST:
2389 struct request *request = (struct request *)hdr;
2390 request->connect_timeout = connect;
2392 if (resolve < 0) resolve = 0;
2393 request->resolve_timeout = resolve;
2395 if (send < 0) send = 0;
2396 request->send_timeout = send;
2398 if (receive < 0) receive = 0;
2399 request->receive_timeout = receive;
2401 if (request->netconn)
2403 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2404 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2406 break;
2408 case WINHTTP_HANDLE_TYPE_SESSION:
2410 struct session *session = (struct session *)hdr;
2411 session->connect_timeout = connect;
2413 if (resolve < 0) resolve = 0;
2414 session->resolve_timeout = resolve;
2416 if (send < 0) send = 0;
2417 session->send_timeout = send;
2419 if (receive < 0) receive = 0;
2420 session->receive_timeout = receive;
2421 break;
2423 default:
2424 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2425 ret = FALSE;
2427 release_object( hdr );
2428 if (ret) SetLastError( ERROR_SUCCESS );
2429 return ret;
2432 static const WCHAR wkday[7][4] =
2433 {L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"};
2434 static const WCHAR month[12][4] =
2435 {L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"};
2437 /***********************************************************************
2438 * WinHttpTimeFromSystemTime (WININET.@)
2440 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2442 TRACE("%p, %p\n", time, string);
2444 if (!time || !string)
2446 SetLastError( ERROR_INVALID_PARAMETER );
2447 return FALSE;
2450 swprintf( string, WINHTTP_TIME_FORMAT_BUFSIZE / sizeof(WCHAR),
2451 L"%s, %02d %s %4d %02d:%02d:%02d GMT",
2452 wkday[time->wDayOfWeek],
2453 time->wDay,
2454 month[time->wMonth - 1],
2455 time->wYear,
2456 time->wHour,
2457 time->wMinute,
2458 time->wSecond );
2460 SetLastError( ERROR_SUCCESS );
2461 return TRUE;
2464 /***********************************************************************
2465 * WinHttpTimeToSystemTime (WININET.@)
2467 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2469 unsigned int i;
2470 const WCHAR *s = string;
2471 WCHAR *end;
2473 TRACE("%s, %p\n", debugstr_w(string), time);
2475 if (!string || !time)
2477 SetLastError( ERROR_INVALID_PARAMETER );
2478 return FALSE;
2481 /* Windows does this too */
2482 GetSystemTime( time );
2484 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2485 * a SYSTEMTIME structure.
2488 SetLastError( ERROR_SUCCESS );
2490 while (*s && !iswalpha( *s )) s++;
2491 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2492 time->wDayOfWeek = 7;
2494 for (i = 0; i < 7; i++)
2496 if (towupper( wkday[i][0] ) == towupper( s[0] ) &&
2497 towupper( wkday[i][1] ) == towupper( s[1] ) &&
2498 towupper( wkday[i][2] ) == towupper( s[2] ) )
2500 time->wDayOfWeek = i;
2501 break;
2505 if (time->wDayOfWeek > 6) return TRUE;
2506 while (*s && !iswdigit( *s )) s++;
2507 time->wDay = wcstol( s, &end, 10 );
2508 s = end;
2510 while (*s && !iswalpha( *s )) s++;
2511 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2512 time->wMonth = 0;
2514 for (i = 0; i < 12; i++)
2516 if (towupper( month[i][0]) == towupper( s[0] ) &&
2517 towupper( month[i][1]) == towupper( s[1] ) &&
2518 towupper( month[i][2]) == towupper( s[2] ) )
2520 time->wMonth = i + 1;
2521 break;
2524 if (time->wMonth == 0) return TRUE;
2526 while (*s && !iswdigit( *s )) s++;
2527 if (*s == '\0') return TRUE;
2528 time->wYear = wcstol( s, &end, 10 );
2529 s = end;
2531 while (*s && !iswdigit( *s )) s++;
2532 if (*s == '\0') return TRUE;
2533 time->wHour = wcstol( s, &end, 10 );
2534 s = end;
2536 while (*s && !iswdigit( *s )) s++;
2537 if (*s == '\0') return TRUE;
2538 time->wMinute = wcstol( s, &end, 10 );
2539 s = end;
2541 while (*s && !iswdigit( *s )) s++;
2542 if (*s == '\0') return TRUE;
2543 time->wSecond = wcstol( s, &end, 10 );
2545 time->wMilliseconds = 0;
2546 return TRUE;