winhttp: Support WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE.
[wine.git] / dlls / winhttp / session.c
blobe95d24c190172211beb5fdfa36cbe03a31f631e7
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 = strdupW( 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 = strdupW( info.lpszProxy )))
334 GlobalFree( info.lpszProxy );
335 GlobalFree( info.lpszProxyBypass );
336 goto end;
338 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( 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 = strdupW( proxy ))) goto end;
349 if (bypass && !(session->proxy_bypass = strdupW( 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 = strdupW( 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 = strdupW( 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 = strdupW( 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;
1275 if (!verb || !verb[0]) verb = L"GET";
1276 if (!(request->verb = strdupW( verb ))) goto end;
1277 if (!(request->path = get_request_path( object ))) goto end;
1279 if (!version || !version[0]) version = L"HTTP/1.1";
1280 if (!(request->version = strdupW( version ))) goto end;
1281 if (!(add_accept_types_header( request, types ))) goto end;
1283 if ((hrequest = alloc_handle( &request->hdr )))
1285 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1288 end:
1289 release_object( &request->hdr );
1290 release_object( &connect->hdr );
1291 TRACE("returning %p\n", hrequest);
1292 if (hrequest) SetLastError( ERROR_SUCCESS );
1293 return hrequest;
1296 /***********************************************************************
1297 * WinHttpCloseHandle (winhttp.@)
1299 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1301 struct object_header *hdr;
1303 TRACE("%p\n", handle);
1305 if (!(hdr = grab_object( handle )))
1307 SetLastError( ERROR_INVALID_HANDLE );
1308 return FALSE;
1310 release_object( hdr );
1311 free_handle( handle );
1312 SetLastError( ERROR_SUCCESS );
1313 return TRUE;
1316 static BOOL query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
1318 BOOL ret = FALSE;
1320 if (!buflen)
1322 SetLastError( ERROR_INVALID_PARAMETER );
1323 return FALSE;
1326 switch (option)
1328 case WINHTTP_OPTION_WORKER_THREAD_COUNT:
1330 FIXME( "WINHTTP_OPTION_WORKER_THREAD_COUNT semi-stub.\n" );
1331 if (!validate_buffer( buffer, buflen, sizeof(DWORD) )) return FALSE;
1333 *(DWORD *)buffer = 0;
1334 *buflen = sizeof(DWORD);
1335 return TRUE;
1337 case WINHTTP_OPTION_CONTEXT_VALUE:
1339 if (!validate_buffer( buffer, buflen, sizeof(DWORD_PTR) )) return FALSE;
1341 *(DWORD_PTR *)buffer = hdr->context;
1342 *buflen = sizeof(DWORD_PTR);
1343 return TRUE;
1345 default:
1346 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1347 else
1349 FIXME( "unimplemented option %lu\n", option );
1350 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1351 return FALSE;
1353 break;
1355 return ret;
1358 /***********************************************************************
1359 * WinHttpQueryOption (winhttp.@)
1361 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, void *buffer, DWORD *buflen )
1363 BOOL ret = FALSE;
1364 struct object_header *hdr;
1366 TRACE( "%p, %lu, %p, %p\n", handle, option, buffer, buflen );
1368 if (!(hdr = grab_object( handle )))
1370 SetLastError( ERROR_INVALID_HANDLE );
1371 return FALSE;
1374 ret = query_option( hdr, option, buffer, buflen );
1376 release_object( hdr );
1377 if (ret) SetLastError( ERROR_SUCCESS );
1378 return ret;
1381 static BOOL set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
1383 BOOL ret = TRUE;
1385 if (!buffer && buflen)
1387 SetLastError( ERROR_INVALID_PARAMETER );
1388 return FALSE;
1391 switch (option)
1393 case WINHTTP_OPTION_CONTEXT_VALUE:
1395 if (buflen != sizeof(DWORD_PTR))
1397 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1398 return FALSE;
1401 hdr->context = *(DWORD_PTR *)buffer;
1402 return TRUE;
1404 default:
1405 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1406 else
1408 FIXME( "unimplemented option %lu\n", option );
1409 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1410 return FALSE;
1412 break;
1414 return ret;
1417 /***********************************************************************
1418 * WinHttpSetOption (winhttp.@)
1420 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, void *buffer, DWORD buflen )
1422 BOOL ret = FALSE;
1423 struct object_header *hdr;
1425 TRACE( "%p, %lu, %p, %lu\n", handle, option, buffer, buflen );
1427 if (!(hdr = grab_object( handle )))
1429 SetLastError( ERROR_INVALID_HANDLE );
1430 return FALSE;
1433 ret = set_option( hdr, option, buffer, buflen );
1435 release_object( hdr );
1436 if (ret) SetLastError( ERROR_SUCCESS );
1437 return ret;
1440 static IP_ADAPTER_ADDRESSES *get_adapters(void)
1442 ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
1443 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
1444 IP_ADAPTER_ADDRESSES *tmp, *ret;
1446 if (!(ret = malloc( size ))) return NULL;
1447 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
1448 while (err == ERROR_BUFFER_OVERFLOW)
1450 if (!(tmp = realloc( ret, size ))) break;
1451 ret = tmp;
1452 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
1454 if (err == ERROR_SUCCESS) return ret;
1455 free( ret );
1456 return NULL;
1459 static WCHAR *detect_autoproxyconfig_url_dhcp(void)
1461 IP_ADAPTER_ADDRESSES *adapters, *ptr;
1462 DHCPCAPI_PARAMS_ARRAY send_params, recv_params;
1463 DHCPCAPI_PARAMS param;
1464 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL;
1465 DWORD err, size;
1466 BYTE *tmp, *buf = NULL;
1468 if (!(adapters = get_adapters())) return NULL;
1470 memset( &send_params, 0, sizeof(send_params) );
1471 memset( &param, 0, sizeof(param) );
1472 param.OptionId = OPTION_MSFT_IE_PROXY;
1473 recv_params.nParams = 1;
1474 recv_params.Params = &param;
1476 for (ptr = adapters; ptr; ptr = ptr->Next)
1478 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
1479 TRACE( "adapter '%s' type %lu dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled );
1481 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1482 /* FIXME: also skip adapters where DHCP is disabled */
1484 size = 256;
1485 if (!(buf = malloc( size ))) goto done;
1486 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
1487 buf, &size, NULL );
1488 while (err == ERROR_MORE_DATA)
1490 if (!(tmp = realloc( buf, size ))) goto done;
1491 buf = tmp;
1492 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
1493 buf, &size, NULL );
1495 if (err == ERROR_SUCCESS && param.nBytesData)
1497 int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 );
1498 if ((ret = malloc( (len + 1) * sizeof(WCHAR) )))
1500 MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len );
1501 ret[len] = 0;
1503 TRACE("returning %s\n", debugstr_w(ret));
1504 break;
1508 done:
1509 free( buf );
1510 free( adapters );
1511 return ret;
1514 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1516 char *ret;
1517 DWORD size = 0;
1519 GetComputerNameExA( format, NULL, &size );
1520 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1521 if (!(ret = malloc( size ))) return NULL;
1522 if (!GetComputerNameExA( format, ret, &size ))
1524 free( ret );
1525 return NULL;
1527 return ret;
1530 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1532 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1534 if (len_suffix > len_domain) return FALSE;
1535 if (!stricmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1536 return FALSE;
1539 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1541 return getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1544 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1546 char name[NI_MAXHOST];
1547 WCHAR *ret, *p;
1548 int len;
1550 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1551 if (!ai) return NULL;
1553 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1555 len = lstrlenW( L"http://" ) + strlen( hostname ) + lstrlenW( L"/wpad.dat" );
1556 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1557 lstrcpyW( p, L"http://" );
1558 p += lstrlenW( L"http://" );
1559 while (*hostname) { *p++ = *hostname++; }
1560 lstrcpyW( p, L"/wpad.dat" );
1561 return ret;
1564 static WCHAR *detect_autoproxyconfig_url_dns(void)
1566 char *fqdn, *domain, *p;
1567 WCHAR *ret = NULL;
1569 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL;
1570 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1572 free( fqdn );
1573 return NULL;
1575 p = fqdn;
1576 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1578 char *name;
1579 struct addrinfo *ai, hints;
1580 int res;
1582 if (!(name = malloc( sizeof("wpad") + strlen(p) )))
1584 free( fqdn );
1585 free( domain );
1586 return NULL;
1588 strcpy( name, "wpad" );
1589 strcat( name, p );
1590 memset( &hints, 0, sizeof(hints) );
1591 hints.ai_flags = AI_ALL | AI_DNS_ONLY;
1592 hints.ai_family = AF_UNSPEC;
1593 res = getaddrinfo( name, NULL, &hints, &ai );
1594 if (!res)
1596 ret = build_wpad_url( name, ai );
1597 freeaddrinfo( ai );
1598 if (ret)
1600 TRACE("returning %s\n", debugstr_w(ret));
1601 free( name );
1602 break;
1605 free( name );
1606 p++;
1608 free( domain );
1609 free( fqdn );
1610 return ret;
1613 /***********************************************************************
1614 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1616 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, WCHAR **url )
1618 TRACE( "%#lx, %p\n", flags, url );
1620 if (!flags || !url)
1622 SetLastError( ERROR_INVALID_PARAMETER );
1623 return FALSE;
1625 *url = NULL;
1626 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1628 *url = detect_autoproxyconfig_url_dhcp();
1630 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1632 if (!*url) *url = detect_autoproxyconfig_url_dns();
1634 if (!*url)
1636 SetLastError( ERROR_WINHTTP_AUTODETECTION_FAILED );
1637 return FALSE;
1639 SetLastError( ERROR_SUCCESS );
1640 return TRUE;
1643 static const WCHAR path_connections[] =
1644 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections";
1646 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1647 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1648 static const DWORD PROXY_TYPE_DIRECT = 1;
1649 static const DWORD PROXY_TYPE_PROXY = 2;
1650 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1651 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1653 struct connection_settings_header
1655 DWORD magic;
1656 DWORD unknown; /* always zero? */
1657 DWORD flags; /* one or more of PROXY_* */
1660 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1662 const BYTE *begin;
1664 for (begin = src; src - begin < len; src++, dst++)
1665 *dst = *src;
1666 *dst = 0;
1669 /***********************************************************************
1670 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1672 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1674 LONG l;
1675 HKEY key;
1676 BOOL got_from_reg = FALSE, direct = TRUE;
1677 WCHAR *envproxy;
1679 TRACE("%p\n", info);
1681 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, KEY_READ, &key );
1682 if (!l)
1684 DWORD type, size = 0;
1686 l = RegQueryValueExW( key, L"WinHttpSettings", NULL, &type, NULL, &size );
1687 if (!l && type == REG_BINARY &&
1688 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1690 BYTE *buf = malloc( size );
1692 if (buf)
1694 struct connection_settings_header *hdr =
1695 (struct connection_settings_header *)buf;
1696 DWORD *len = (DWORD *)(hdr + 1);
1698 l = RegQueryValueExW( key, L"WinHttpSettings", NULL, NULL, buf,
1699 &size );
1700 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1701 hdr->unknown == 0)
1703 if (hdr->flags & PROXY_TYPE_PROXY)
1705 BOOL sane = FALSE;
1706 LPWSTR proxy = NULL;
1707 LPWSTR proxy_bypass = NULL;
1709 /* Sanity-check length of proxy string */
1710 if ((BYTE *)len - buf + *len <= size)
1712 sane = TRUE;
1713 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1714 if (proxy)
1715 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1716 len = (DWORD *)((BYTE *)(len + 1) + *len);
1718 if (sane)
1720 /* Sanity-check length of proxy bypass string */
1721 if ((BYTE *)len - buf + *len <= size)
1723 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1724 if (proxy_bypass)
1725 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1727 else
1729 sane = FALSE;
1730 GlobalFree( proxy );
1731 proxy = NULL;
1734 info->lpszProxy = proxy;
1735 info->lpszProxyBypass = proxy_bypass;
1736 if (sane)
1738 got_from_reg = TRUE;
1739 direct = FALSE;
1740 info->dwAccessType =
1741 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1742 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1743 debugstr_w(info->lpszProxy),
1744 debugstr_w(info->lpszProxyBypass));
1748 free( buf );
1751 RegCloseKey( key );
1753 if (!got_from_reg && (envproxy = _wgetenv( L"http_proxy" )))
1755 WCHAR *colon, *http_proxy = NULL;
1757 if (!(colon = wcschr( envproxy, ':' ))) http_proxy = envproxy;
1758 else
1760 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1762 /* It's a scheme, check that it's http */
1763 if (!wcsncmp( envproxy, L"http://", 7 )) http_proxy = envproxy + 7;
1764 else WARN("unsupported scheme in $http_proxy: %s\n", debugstr_w(envproxy));
1766 else http_proxy = envproxy;
1769 if (http_proxy && http_proxy[0])
1771 direct = FALSE;
1772 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1773 info->lpszProxy = GlobalAlloc( 0, (lstrlenW(http_proxy) + 1) * sizeof(WCHAR) );
1774 wcscpy( info->lpszProxy, http_proxy );
1775 info->lpszProxyBypass = NULL;
1776 TRACE("http proxy (from environment) = %s\n", debugstr_w(info->lpszProxy));
1779 if (direct)
1781 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1782 info->lpszProxy = NULL;
1783 info->lpszProxyBypass = NULL;
1785 SetLastError( ERROR_SUCCESS );
1786 return TRUE;
1789 /***********************************************************************
1790 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1792 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1794 HKEY hkey = NULL;
1795 struct connection_settings_header *hdr = NULL;
1796 DWORD type, offset, len, size = 0;
1797 BOOL ret = FALSE;
1799 TRACE("%p\n", config);
1801 if (!config)
1803 SetLastError( ERROR_INVALID_PARAMETER );
1804 return FALSE;
1806 memset( config, 0, sizeof(*config) );
1807 config->fAutoDetect = TRUE;
1809 if (RegOpenKeyExW( HKEY_CURRENT_USER, path_connections, 0, KEY_READ, &hkey ) ||
1810 RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, NULL, &size ) ||
1811 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1813 ret = TRUE;
1814 goto done;
1816 if (!(hdr = malloc( size ))) goto done;
1817 if (RegQueryValueExW( hkey, L"DefaultConnectionSettings", NULL, &type, (BYTE *)hdr, &size ) ||
1818 hdr->magic != WININET_SETTINGS_MAGIC)
1820 ret = TRUE;
1821 goto done;
1824 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1825 offset = sizeof(*hdr);
1826 if (offset + sizeof(DWORD) > size) goto done;
1827 len = *(DWORD *)((char *)hdr + offset);
1828 offset += sizeof(DWORD);
1829 if (len && hdr->flags & PROXY_TYPE_PROXY)
1831 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1832 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1834 offset += len;
1835 if (offset + sizeof(DWORD) > size) goto done;
1836 len = *(DWORD *)((char *)hdr + offset);
1837 offset += sizeof(DWORD);
1838 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1840 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1841 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1843 offset += len;
1844 if (offset + sizeof(DWORD) > size) goto done;
1845 len = *(DWORD *)((char *)hdr + offset);
1846 offset += sizeof(DWORD);
1847 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1849 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1850 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1852 ret = TRUE;
1854 done:
1855 RegCloseKey( hkey );
1856 free( hdr );
1857 if (!ret)
1859 GlobalFree( config->lpszAutoConfigUrl );
1860 config->lpszAutoConfigUrl = NULL;
1861 GlobalFree( config->lpszProxy );
1862 config->lpszProxy = NULL;
1863 GlobalFree( config->lpszProxyBypass );
1864 config->lpszProxyBypass = NULL;
1866 else SetLastError( ERROR_SUCCESS );
1867 return ret;
1870 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1872 const char *p;
1873 WCHAR *q;
1874 int len;
1876 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1877 info->lpszProxy = NULL;
1878 info->lpszProxyBypass = NULL;
1880 TRACE("%s\n", debugstr_a( result ));
1882 p = result;
1883 while (*p == ' ') p++;
1884 len = strlen( p );
1885 if (len >= 5 && !_strnicmp( p, "PROXY", sizeof("PROXY") - 1 ))
1887 p += 5;
1888 while (*p == ' ') p++;
1889 if (!*p || *p == ';') return TRUE;
1890 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1891 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1892 for (; *q; q++)
1894 if (*q == ' ' || *q == ';')
1896 *q = 0;
1897 break;
1901 return TRUE;
1904 static char *download_script( const WCHAR *url, DWORD *out_size )
1906 static const WCHAR *acceptW[] = {L"*/*", NULL};
1907 HINTERNET ses, con = NULL, req = NULL;
1908 WCHAR *hostname;
1909 URL_COMPONENTSW uc;
1910 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1911 char *tmp, *buffer = NULL;
1913 *out_size = 0;
1915 memset( &uc, 0, sizeof(uc) );
1916 uc.dwStructSize = sizeof(uc);
1917 uc.dwHostNameLength = -1;
1918 uc.dwUrlPathLength = -1;
1919 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1920 if (!(hostname = malloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1921 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1922 hostname[uc.dwHostNameLength] = 0;
1924 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1925 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1926 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1927 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1928 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1930 if (!WinHttpReceiveResponse( req, 0 )) goto done;
1931 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1932 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1934 size = 4096;
1935 if (!(buffer = malloc( size ))) goto done;
1936 to_read = size;
1937 offset = 0;
1938 for (;;)
1940 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1941 if (!bytes_read) break;
1942 to_read -= bytes_read;
1943 offset += bytes_read;
1944 *out_size += bytes_read;
1945 if (!to_read)
1947 to_read = size;
1948 size *= 2;
1949 if (!(tmp = realloc( buffer, size ))) goto done;
1950 buffer = tmp;
1954 done:
1955 WinHttpCloseHandle( req );
1956 WinHttpCloseHandle( con );
1957 WinHttpCloseHandle( ses );
1958 free( hostname );
1959 if (!buffer) SetLastError( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1960 return buffer;
1963 struct AUTO_PROXY_SCRIPT_BUFFER
1965 DWORD dwStructSize;
1966 LPSTR lpszScriptBuffer;
1967 DWORD dwScriptBufferSize;
1970 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1971 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1972 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1974 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1976 BOOL ret;
1977 char *result, *urlA;
1978 DWORD len_result;
1979 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1980 URL_COMPONENTSW uc;
1982 buffer.dwStructSize = sizeof(buffer);
1983 buffer.lpszScriptBuffer = script;
1984 buffer.dwScriptBufferSize = size;
1986 if (!(urlA = strdupWA( url ))) return FALSE;
1987 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1989 free( urlA );
1990 return FALSE;
1993 memset( &uc, 0, sizeof(uc) );
1994 uc.dwStructSize = sizeof(uc);
1995 uc.dwHostNameLength = -1;
1997 if ((ret = WinHttpCrackUrl( url, 0, 0, &uc )))
1999 char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
2001 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
2002 hostnameA, strlen(hostnameA), &result, &len_result )))
2004 ret = parse_script_result( result, info );
2005 free( result );
2008 free( hostnameA );
2010 free( urlA );
2011 InternetDeInitializeAutoProxyDll( NULL, 0 );
2012 return ret;
2015 /***********************************************************************
2016 * WinHttpGetProxyForUrl (winhttp.@)
2018 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
2019 WINHTTP_PROXY_INFO *info )
2021 WCHAR *detected_pac_url = NULL;
2022 const WCHAR *pac_url;
2023 struct session *session;
2024 char *script;
2025 DWORD size;
2026 BOOL ret = FALSE;
2028 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
2030 if (!(session = (struct session *)grab_object( hsession )))
2032 SetLastError( ERROR_INVALID_HANDLE );
2033 return FALSE;
2035 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
2037 release_object( &session->hdr );
2038 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2039 return FALSE;
2041 if (!url || !options || !info ||
2042 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
2043 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
2044 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
2045 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
2047 release_object( &session->hdr );
2048 SetLastError( ERROR_INVALID_PARAMETER );
2049 return FALSE;
2051 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
2052 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
2053 goto done;
2055 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
2056 else pac_url = detected_pac_url;
2058 if ((script = download_script( pac_url, &size )))
2060 ret = run_script( script, size, url, info );
2061 free( script );
2064 done:
2065 GlobalFree( detected_pac_url );
2066 release_object( &session->hdr );
2067 if (ret) SetLastError( ERROR_SUCCESS );
2068 return ret;
2071 /***********************************************************************
2072 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
2074 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
2076 LONG l;
2077 HKEY key;
2078 BOOL ret = FALSE;
2079 const WCHAR *src;
2081 TRACE("%p\n", info);
2083 if (!info)
2085 SetLastError( ERROR_INVALID_PARAMETER );
2086 return FALSE;
2088 switch (info->dwAccessType)
2090 case WINHTTP_ACCESS_TYPE_NO_PROXY:
2091 break;
2092 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
2093 if (!info->lpszProxy)
2095 SetLastError( ERROR_INVALID_PARAMETER );
2096 return FALSE;
2098 /* Only ASCII characters are allowed */
2099 for (src = info->lpszProxy; *src; src++)
2100 if (*src > 0x7f)
2102 SetLastError( ERROR_INVALID_PARAMETER );
2103 return FALSE;
2105 if (info->lpszProxyBypass)
2107 for (src = info->lpszProxyBypass; *src; src++)
2108 if (*src > 0x7f)
2110 SetLastError( ERROR_INVALID_PARAMETER );
2111 return FALSE;
2114 break;
2115 default:
2116 SetLastError( ERROR_INVALID_PARAMETER );
2117 return FALSE;
2120 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, path_connections, 0, NULL, 0,
2121 KEY_WRITE, NULL, &key, NULL );
2122 if (!l)
2124 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
2125 BYTE *buf;
2127 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
2129 size += lstrlenW( info->lpszProxy );
2130 if (info->lpszProxyBypass)
2131 size += lstrlenW( info->lpszProxyBypass );
2133 if ((buf = malloc( size )))
2135 struct connection_settings_header *hdr =
2136 (struct connection_settings_header *)buf;
2137 DWORD *len = (DWORD *)(hdr + 1);
2139 hdr->magic = WINHTTP_SETTINGS_MAGIC;
2140 hdr->unknown = 0;
2141 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
2143 BYTE *dst;
2145 hdr->flags = PROXY_TYPE_PROXY;
2146 *len++ = lstrlenW( info->lpszProxy );
2147 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
2148 src++, dst++)
2149 *dst = *src;
2150 len = (DWORD *)dst;
2151 if (info->lpszProxyBypass)
2153 *len++ = lstrlenW( info->lpszProxyBypass );
2154 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
2155 src++, dst++)
2156 *dst = *src;
2158 else
2159 *len++ = 0;
2161 else
2163 hdr->flags = PROXY_TYPE_DIRECT;
2164 *len++ = 0;
2165 *len++ = 0;
2167 l = RegSetValueExW( key, L"WinHttpSettings", 0, REG_BINARY, buf, size );
2168 if (!l)
2169 ret = TRUE;
2170 free( buf );
2172 RegCloseKey( key );
2174 if (ret) SetLastError( ERROR_SUCCESS );
2175 return ret;
2178 /***********************************************************************
2179 * WinHttpCreateProxyResolver (winhttp.@)
2181 DWORD WINAPI WinHttpCreateProxyResolver( HINTERNET hsession, HINTERNET *hresolver )
2183 FIXME("%p, %p\n", hsession, hresolver);
2184 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2187 /***********************************************************************
2188 * WinHttpFreeProxyResult (winhttp.@)
2190 void WINAPI WinHttpFreeProxyResult( WINHTTP_PROXY_RESULT *result )
2192 FIXME("%p\n", result);
2195 /***********************************************************************
2196 * WinHttpFreeProxyResultEx (winhttp.@)
2198 void WINAPI WinHttpFreeProxyResultEx( WINHTTP_PROXY_RESULT_EX *result )
2200 FIXME("%p\n", result);
2203 /***********************************************************************
2204 * WinHttpFreeProxySettings (winhttp.@)
2206 void WINAPI WinHttpFreeProxySettings( WINHTTP_PROXY_SETTINGS *settings )
2208 FIXME("%p\n", settings);
2211 /***********************************************************************
2212 * WinHttpGetProxyForUrlEx (winhttp.@)
2214 DWORD WINAPI WinHttpGetProxyForUrlEx( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options,
2215 DWORD_PTR ctx )
2217 FIXME( "%p, %s, %p, %Ix\n", hresolver, debugstr_w(url), options, ctx );
2218 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2221 /***********************************************************************
2222 * WinHttpGetProxyForUrlEx2 (winhttp.@)
2224 DWORD WINAPI WinHttpGetProxyForUrlEx2( HINTERNET hresolver, const WCHAR *url, WINHTTP_AUTOPROXY_OPTIONS *options,
2225 DWORD selection_len, BYTE *selection, DWORD_PTR ctx )
2227 FIXME( "%p, %s, %p, %lu, %p, %Ix\n", hresolver, debugstr_w(url), options, selection_len, selection, ctx );
2228 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2231 /***********************************************************************
2232 * WinHttpGetProxyResult (winhttp.@)
2234 DWORD WINAPI WinHttpGetProxyResult( HINTERNET hresolver, WINHTTP_PROXY_RESULT *result )
2236 FIXME("%p, %p\n", hresolver, result);
2237 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2240 /***********************************************************************
2241 * WinHttpGetProxyResultEx (winhttp.@)
2243 DWORD WINAPI WinHttpGetProxyResultEx( HINTERNET hresolver, WINHTTP_PROXY_RESULT_EX *result )
2245 FIXME("%p, %p\n", hresolver, result);
2246 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2249 /***********************************************************************
2250 * WinHttpGetProxySettingsVersion (winhttp.@)
2252 DWORD WINAPI WinHttpGetProxySettingsVersion( HINTERNET hsession, DWORD *version )
2254 FIXME("%p, %p\n", hsession, version);
2255 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2258 /***********************************************************************
2259 * WinHttpReadProxySettings (winhttp.@)
2261 DWORD WINAPI WinHttpReadProxySettings( HINTERNET hsession, const WCHAR *connection, BOOL use_defaults,
2262 BOOL set_autodiscover, DWORD *version, BOOL *defaults_returned,
2263 WINHTTP_PROXY_SETTINGS *settings)
2265 FIXME("%p, %s, %d, %d, %p, %p, %p\n", hsession, debugstr_w(connection), use_defaults, set_autodiscover,
2266 version, defaults_returned, settings);
2267 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2270 /***********************************************************************
2271 * WinHttpResetAutoProxy (winhttp.@)
2273 DWORD WINAPI WinHttpResetAutoProxy( HINTERNET hsession, DWORD flags )
2275 FIXME( "%p, %#lx\n", hsession, flags );
2276 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2279 DWORD WINAPI WinHttpWriteProxySettings( HINTERNET hsession, BOOL force, WINHTTP_PROXY_SETTINGS *settings )
2281 FIXME("%p, %d, %p\n", hsession, force, settings);
2282 return ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
2285 /***********************************************************************
2286 * WinHttpSetStatusCallback (winhttp.@)
2288 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2289 DWORD flags, DWORD_PTR reserved )
2291 struct object_header *hdr;
2292 WINHTTP_STATUS_CALLBACK ret;
2294 TRACE( "%p, %p, %#lx, %Ix\n", handle, callback, flags, reserved );
2296 if (!(hdr = grab_object( handle )))
2298 SetLastError( ERROR_INVALID_HANDLE );
2299 return WINHTTP_INVALID_STATUS_CALLBACK;
2301 ret = hdr->callback;
2302 hdr->callback = callback;
2303 hdr->notify_mask = flags;
2305 release_object( hdr );
2306 SetLastError( ERROR_SUCCESS );
2307 return ret;
2310 /***********************************************************************
2311 * WinHttpSetTimeouts (winhttp.@)
2313 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2315 BOOL ret = TRUE;
2316 struct object_header *hdr;
2318 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2320 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2322 SetLastError( ERROR_INVALID_PARAMETER );
2323 return FALSE;
2326 if (!(hdr = grab_object( handle )))
2328 SetLastError( ERROR_INVALID_HANDLE );
2329 return FALSE;
2332 switch(hdr->type)
2334 case WINHTTP_HANDLE_TYPE_REQUEST:
2336 struct request *request = (struct request *)hdr;
2337 request->connect_timeout = connect;
2339 if (resolve < 0) resolve = 0;
2340 request->resolve_timeout = resolve;
2342 if (send < 0) send = 0;
2343 request->send_timeout = send;
2345 if (receive < 0) receive = 0;
2346 request->receive_timeout = receive;
2348 if (request->netconn)
2350 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2351 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2353 break;
2355 case WINHTTP_HANDLE_TYPE_SESSION:
2357 struct session *session = (struct session *)hdr;
2358 session->connect_timeout = connect;
2360 if (resolve < 0) resolve = 0;
2361 session->resolve_timeout = resolve;
2363 if (send < 0) send = 0;
2364 session->send_timeout = send;
2366 if (receive < 0) receive = 0;
2367 session->receive_timeout = receive;
2368 break;
2370 default:
2371 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2372 ret = FALSE;
2374 release_object( hdr );
2375 if (ret) SetLastError( ERROR_SUCCESS );
2376 return ret;
2379 static const WCHAR wkday[7][4] =
2380 {L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"};
2381 static const WCHAR month[12][4] =
2382 {L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"};
2384 /***********************************************************************
2385 * WinHttpTimeFromSystemTime (WININET.@)
2387 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2389 TRACE("%p, %p\n", time, string);
2391 if (!time || !string)
2393 SetLastError( ERROR_INVALID_PARAMETER );
2394 return FALSE;
2397 swprintf( string, WINHTTP_TIME_FORMAT_BUFSIZE / sizeof(WCHAR),
2398 L"%s, %02d %s %4d %02d:%02d:%02d GMT",
2399 wkday[time->wDayOfWeek],
2400 time->wDay,
2401 month[time->wMonth - 1],
2402 time->wYear,
2403 time->wHour,
2404 time->wMinute,
2405 time->wSecond );
2407 SetLastError( ERROR_SUCCESS );
2408 return TRUE;
2411 /***********************************************************************
2412 * WinHttpTimeToSystemTime (WININET.@)
2414 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2416 unsigned int i;
2417 const WCHAR *s = string;
2418 WCHAR *end;
2420 TRACE("%s, %p\n", debugstr_w(string), time);
2422 if (!string || !time)
2424 SetLastError( ERROR_INVALID_PARAMETER );
2425 return FALSE;
2428 /* Windows does this too */
2429 GetSystemTime( time );
2431 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2432 * a SYSTEMTIME structure.
2435 SetLastError( ERROR_SUCCESS );
2437 while (*s && !iswalpha( *s )) s++;
2438 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2439 time->wDayOfWeek = 7;
2441 for (i = 0; i < 7; i++)
2443 if (towupper( wkday[i][0] ) == towupper( s[0] ) &&
2444 towupper( wkday[i][1] ) == towupper( s[1] ) &&
2445 towupper( wkday[i][2] ) == towupper( s[2] ) )
2447 time->wDayOfWeek = i;
2448 break;
2452 if (time->wDayOfWeek > 6) return TRUE;
2453 while (*s && !iswdigit( *s )) s++;
2454 time->wDay = wcstol( s, &end, 10 );
2455 s = end;
2457 while (*s && !iswalpha( *s )) s++;
2458 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2459 time->wMonth = 0;
2461 for (i = 0; i < 12; i++)
2463 if (towupper( month[i][0]) == towupper( s[0] ) &&
2464 towupper( month[i][1]) == towupper( s[1] ) &&
2465 towupper( month[i][2]) == towupper( s[2] ) )
2467 time->wMonth = i + 1;
2468 break;
2471 if (time->wMonth == 0) return TRUE;
2473 while (*s && !iswdigit( *s )) s++;
2474 if (*s == '\0') return TRUE;
2475 time->wYear = wcstol( s, &end, 10 );
2476 s = end;
2478 while (*s && !iswdigit( *s )) s++;
2479 if (*s == '\0') return TRUE;
2480 time->wHour = wcstol( s, &end, 10 );
2481 s = end;
2483 while (*s && !iswdigit( *s )) s++;
2484 if (*s == '\0') return TRUE;
2485 time->wMinute = wcstol( s, &end, 10 );
2486 s = end;
2488 while (*s && !iswdigit( *s )) s++;
2489 if (*s == '\0') return TRUE;
2490 time->wSecond = wcstol( s, &end, 10 );
2492 time->wMilliseconds = 0;
2493 return TRUE;