ntdll: Pass the server context to get/set_thread_context().
[wine.git] / dlls / winhttp / session.c
blobfb815682c25a460ae69ed0b17bbc0b0d548439e9
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #ifdef HAVE_CORESERVICES_CORESERVICES_H
27 #define GetCurrentThread MacGetCurrentThread
28 #define LoadResource MacLoadResource
29 #include <CoreServices/CoreServices.h>
30 #undef GetCurrentThread
31 #undef LoadResource
32 #undef DPRINTF
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #ifndef __MINGW32__
38 #define USE_WS_PREFIX
39 #endif
40 #include "winsock2.h"
41 #include "ws2ipdef.h"
42 #include "winhttp.h"
43 #include "winreg.h"
44 #define COBJMACROS
45 #include "ole2.h"
46 #include "dispex.h"
47 #include "activscp.h"
49 #include "winhttp_private.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
53 #define DEFAULT_RESOLVE_TIMEOUT 0
54 #define DEFAULT_CONNECT_TIMEOUT 20000
55 #define DEFAULT_SEND_TIMEOUT 30000
56 #define DEFAULT_RECEIVE_TIMEOUT 30000
58 void set_last_error( DWORD error )
60 /* FIXME */
61 SetLastError( error );
64 DWORD get_last_error( void )
66 /* FIXME */
67 return GetLastError();
70 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
72 if (hdr->callback && (hdr->notify_mask & status))
74 TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
75 hdr->callback( hdr->handle, hdr->context, status, info, buflen );
76 TRACE("returning from 0x%08x callback\n", status);
80 /***********************************************************************
81 * WinHttpCheckPlatform (winhttp.@)
83 BOOL WINAPI WinHttpCheckPlatform( void )
85 TRACE("\n");
86 return TRUE;
89 /***********************************************************************
90 * session_destroy (internal)
92 static void session_destroy( object_header_t *hdr )
94 session_t *session = (session_t *)hdr;
95 struct list *item, *next;
96 domain_t *domain;
98 TRACE("%p\n", session);
100 if (session->unload_event) SetEvent( session->unload_event );
101 if (session->cred_handle_initialized) FreeCredentialsHandle( &session->cred_handle );
103 LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
105 domain = LIST_ENTRY( item, domain_t, entry );
106 delete_domain( domain );
108 heap_free( session->agent );
109 heap_free( session->proxy_server );
110 heap_free( session->proxy_bypass );
111 heap_free( session->proxy_username );
112 heap_free( session->proxy_password );
113 heap_free( session );
116 static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
118 session_t *session = (session_t *)hdr;
120 switch (option)
122 case WINHTTP_OPTION_REDIRECT_POLICY:
124 if (!buffer || *buflen < sizeof(DWORD))
126 *buflen = sizeof(DWORD);
127 set_last_error( ERROR_INSUFFICIENT_BUFFER );
128 return FALSE;
131 *(DWORD *)buffer = hdr->redirect_policy;
132 *buflen = sizeof(DWORD);
133 return TRUE;
135 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
136 *(DWORD *)buffer = session->resolve_timeout;
137 *buflen = sizeof(DWORD);
138 return TRUE;
139 case WINHTTP_OPTION_CONNECT_TIMEOUT:
140 *(DWORD *)buffer = session->connect_timeout;
141 *buflen = sizeof(DWORD);
142 return TRUE;
143 case WINHTTP_OPTION_SEND_TIMEOUT:
144 *(DWORD *)buffer = session->send_timeout;
145 *buflen = sizeof(DWORD);
146 return TRUE;
147 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
148 *(DWORD *)buffer = session->recv_timeout;
149 *buflen = sizeof(DWORD);
150 return TRUE;
151 default:
152 FIXME("unimplemented option %u\n", option);
153 set_last_error( ERROR_INVALID_PARAMETER );
154 return FALSE;
158 static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
160 session_t *session = (session_t *)hdr;
162 switch (option)
164 case WINHTTP_OPTION_PROXY:
166 WINHTTP_PROXY_INFO *pi = buffer;
168 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
169 return TRUE;
171 case WINHTTP_OPTION_REDIRECT_POLICY:
173 DWORD policy;
175 if (buflen != sizeof(policy))
177 set_last_error( ERROR_INSUFFICIENT_BUFFER );
178 return FALSE;
181 policy = *(DWORD *)buffer;
182 TRACE("0x%x\n", policy);
183 hdr->redirect_policy = policy;
184 return TRUE;
186 case WINHTTP_OPTION_SECURE_PROTOCOLS:
188 if (buflen != sizeof(session->secure_protocols))
190 set_last_error( ERROR_INSUFFICIENT_BUFFER );
191 return FALSE;
193 session->secure_protocols = *(DWORD *)buffer;
194 TRACE("0x%x\n", session->secure_protocols);
195 return TRUE;
197 case WINHTTP_OPTION_DISABLE_FEATURE:
198 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
199 return FALSE;
200 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
201 session->resolve_timeout = *(DWORD *)buffer;
202 return TRUE;
203 case WINHTTP_OPTION_CONNECT_TIMEOUT:
204 session->connect_timeout = *(DWORD *)buffer;
205 return TRUE;
206 case WINHTTP_OPTION_SEND_TIMEOUT:
207 session->send_timeout = *(DWORD *)buffer;
208 return TRUE;
209 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
210 session->recv_timeout = *(DWORD *)buffer;
211 return TRUE;
212 case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
213 FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
214 return TRUE;
215 case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
216 TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
217 session->unload_event = *(HANDLE *)buffer;
218 return TRUE;
219 case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
220 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %d\n", *(DWORD *)buffer);
221 return TRUE;
222 case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
223 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %d\n", *(DWORD *)buffer);
224 return TRUE;
225 default:
226 FIXME("unimplemented option %u\n", option);
227 set_last_error( ERROR_WINHTTP_INVALID_OPTION );
228 return FALSE;
232 static const object_vtbl_t session_vtbl =
234 session_destroy,
235 session_query_option,
236 session_set_option
239 /***********************************************************************
240 * WinHttpOpen (winhttp.@)
242 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
244 session_t *session;
245 HINTERNET handle = NULL;
247 TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
249 if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
251 session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
252 session->hdr.vtbl = &session_vtbl;
253 session->hdr.flags = flags;
254 session->hdr.refs = 1;
255 session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
256 list_init( &session->hdr.children );
257 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
258 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
259 session->send_timeout = DEFAULT_SEND_TIMEOUT;
260 session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
261 list_init( &session->cookie_cache );
263 if (agent && !(session->agent = strdupW( agent ))) goto end;
264 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
266 WINHTTP_PROXY_INFO info;
268 WinHttpGetDefaultProxyConfiguration( &info );
269 session->access = info.dwAccessType;
270 if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
272 GlobalFree( info.lpszProxy );
273 GlobalFree( info.lpszProxyBypass );
274 goto end;
276 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
278 GlobalFree( info.lpszProxy );
279 GlobalFree( info.lpszProxyBypass );
280 goto end;
283 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
285 session->access = access;
286 if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
287 if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
290 if (!(handle = alloc_handle( &session->hdr ))) goto end;
291 session->hdr.handle = handle;
293 end:
294 release_object( &session->hdr );
295 TRACE("returning %p\n", handle);
296 if (handle) set_last_error( ERROR_SUCCESS );
297 return handle;
300 /***********************************************************************
301 * connect_destroy (internal)
303 static void connect_destroy( object_header_t *hdr )
305 connect_t *connect = (connect_t *)hdr;
307 TRACE("%p\n", connect);
309 release_object( &connect->session->hdr );
311 heap_free( connect->hostname );
312 heap_free( connect->servername );
313 heap_free( connect->username );
314 heap_free( connect->password );
315 heap_free( connect );
318 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
320 connect_t *connect = (connect_t *)hdr;
322 switch (option)
324 case WINHTTP_OPTION_PARENT_HANDLE:
326 if (!buffer || *buflen < sizeof(HINTERNET))
328 *buflen = sizeof(HINTERNET);
329 set_last_error( ERROR_INSUFFICIENT_BUFFER );
330 return FALSE;
333 *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
334 *buflen = sizeof(HINTERNET);
335 return TRUE;
337 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
338 *(DWORD *)buffer = connect->session->resolve_timeout;
339 *buflen = sizeof(DWORD);
340 return TRUE;
341 case WINHTTP_OPTION_CONNECT_TIMEOUT:
342 *(DWORD *)buffer = connect->session->connect_timeout;
343 *buflen = sizeof(DWORD);
344 return TRUE;
345 case WINHTTP_OPTION_SEND_TIMEOUT:
346 *(DWORD *)buffer = connect->session->send_timeout;
347 *buflen = sizeof(DWORD);
348 return TRUE;
349 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
350 *(DWORD *)buffer = connect->session->recv_timeout;
351 *buflen = sizeof(DWORD);
352 return TRUE;
353 default:
354 FIXME("unimplemented option %u\n", option);
355 set_last_error( ERROR_INVALID_PARAMETER );
356 return FALSE;
360 static const object_vtbl_t connect_vtbl =
362 connect_destroy,
363 connect_query_option,
364 NULL
367 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
369 static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
370 BOOL ret = FALSE;
372 if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
373 ret = TRUE;
374 else if (*domain == '*')
376 if (domain[1] == '.')
378 LPCWSTR dot;
380 /* For a hostname to match a wildcard, the last domain must match
381 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
382 * hostname is www.foo.a.b, it matches, but a.b does not.
384 dot = strchrW( server, '.' );
385 if (dot)
387 int len = strlenW( dot + 1 );
389 if (len > strlenW( domain + 2 ))
391 LPCWSTR ptr;
393 /* The server's domain is longer than the wildcard, so it
394 * could be a subdomain. Compare the last portion of the
395 * server's domain.
397 ptr = dot + len + 1 - strlenW( domain + 2 );
398 if (!strcmpiW( ptr, domain + 2 ))
400 /* This is only a match if the preceding character is
401 * a '.', i.e. that it is a matching domain. E.g.
402 * if domain is '*.b.c' and server is 'www.ab.c' they
403 * do not match.
405 ret = *(ptr - 1) == '.';
408 else
409 ret = !strcmpiW( dot + 1, domain + 2 );
413 else
414 ret = !strcmpiW( server, domain );
415 return ret;
418 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
419 #define MAX_HOST_NAME_LENGTH 256
421 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
423 LPCWSTR ptr;
424 BOOL ret = FALSE;
426 if (!session->proxy_bypass) return FALSE;
427 ptr = session->proxy_bypass;
428 do {
429 LPCWSTR tmp = ptr;
431 ptr = strchrW( ptr, ';' );
432 if (!ptr)
433 ptr = strchrW( tmp, ' ' );
434 if (ptr)
436 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
438 WCHAR domain[MAX_HOST_NAME_LENGTH];
440 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
441 domain[ptr - tmp] = 0;
442 ret = domain_matches( server, domain );
444 ptr += 1;
446 else if (*tmp)
447 ret = domain_matches( server, tmp );
448 } while (ptr && !ret);
449 return ret;
452 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
454 session_t *session = connect->session;
455 BOOL ret = TRUE;
457 if (session->proxy_server && !should_bypass_proxy(session, server))
459 LPCWSTR colon;
461 if ((colon = strchrW( session->proxy_server, ':' )))
463 if (!connect->servername || strncmpiW( connect->servername,
464 session->proxy_server, colon - session->proxy_server - 1 ))
466 heap_free( connect->servername );
467 connect->resolved = FALSE;
468 if (!(connect->servername = heap_alloc(
469 (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
471 ret = FALSE;
472 goto end;
474 memcpy( connect->servername, session->proxy_server,
475 (colon - session->proxy_server) * sizeof(WCHAR) );
476 connect->servername[colon - session->proxy_server] = 0;
477 if (*(colon + 1))
478 connect->serverport = atoiW( colon + 1 );
479 else
480 connect->serverport = INTERNET_DEFAULT_PORT;
483 else
485 if (!connect->servername || strcmpiW( connect->servername,
486 session->proxy_server ))
488 heap_free( connect->servername );
489 connect->resolved = FALSE;
490 if (!(connect->servername = strdupW( session->proxy_server )))
492 ret = FALSE;
493 goto end;
495 connect->serverport = INTERNET_DEFAULT_PORT;
499 else if (server)
501 heap_free( connect->servername );
502 connect->resolved = FALSE;
503 if (!(connect->servername = strdupW( server )))
505 ret = FALSE;
506 goto end;
508 connect->serverport = port;
510 end:
511 return ret;
514 /***********************************************************************
515 * WinHttpConnect (winhttp.@)
517 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
519 connect_t *connect;
520 session_t *session;
521 HINTERNET hconnect = NULL;
523 TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
525 if (!server)
527 set_last_error( ERROR_INVALID_PARAMETER );
528 return NULL;
530 if (!(session = (session_t *)grab_object( hsession )))
532 set_last_error( ERROR_INVALID_HANDLE );
533 return NULL;
535 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
537 release_object( &session->hdr );
538 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
539 return NULL;
541 if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
543 release_object( &session->hdr );
544 return NULL;
546 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
547 connect->hdr.vtbl = &connect_vtbl;
548 connect->hdr.refs = 1;
549 connect->hdr.flags = session->hdr.flags;
550 connect->hdr.callback = session->hdr.callback;
551 connect->hdr.notify_mask = session->hdr.notify_mask;
552 connect->hdr.context = session->hdr.context;
553 connect->hdr.redirect_policy = session->hdr.redirect_policy;
554 list_init( &connect->hdr.children );
556 addref_object( &session->hdr );
557 connect->session = session;
558 list_add_head( &session->hdr.children, &connect->hdr.entry );
560 if (!(connect->hostname = strdupW( server ))) goto end;
561 connect->hostport = port;
562 if (!set_server_for_hostname( connect, server, port )) goto end;
564 if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
565 connect->hdr.handle = hconnect;
567 send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
569 end:
570 release_object( &connect->hdr );
571 release_object( &session->hdr );
572 TRACE("returning %p\n", hconnect);
573 if (hconnect) set_last_error( ERROR_SUCCESS );
574 return hconnect;
577 /***********************************************************************
578 * request_destroy (internal)
580 static void request_destroy( object_header_t *hdr )
582 request_t *request = (request_t *)hdr;
583 unsigned int i, j;
585 TRACE("%p\n", request);
587 if (request->task_thread)
589 /* Signal to the task proc to quit. It will call
590 this again when it does. */
591 HANDLE thread = request->task_thread;
592 request->task_thread = 0;
593 SetEvent( request->task_cancel );
594 CloseHandle( thread );
595 return;
597 release_object( &request->connect->hdr );
599 CertFreeCertificateContext( request->server_cert );
601 destroy_authinfo( request->authinfo );
602 destroy_authinfo( request->proxy_authinfo );
604 heap_free( request->verb );
605 heap_free( request->path );
606 heap_free( request->version );
607 heap_free( request->raw_headers );
608 heap_free( request->status_text );
609 for (i = 0; i < request->num_headers; i++)
611 heap_free( request->headers[i].field );
612 heap_free( request->headers[i].value );
614 heap_free( request->headers );
615 for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
616 heap_free( request->accept_types );
617 for (i = 0; i < TARGET_MAX; i++)
619 for (j = 0; j < SCHEME_MAX; j++)
621 heap_free( request->creds[i][j].username );
622 heap_free( request->creds[i][j].password );
625 heap_free( request );
628 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
630 int len = 0;
631 if (str) len = strlenW( str );
632 if (buffer && *buflen > len)
634 if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
635 buffer[len] = 0;
637 *buflen = len * sizeof(WCHAR);
640 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
642 WCHAR *ret;
643 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
645 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
646 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
647 CertNameToStrW( encoding, blob, format, ret, size );
649 return ret;
652 static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
654 #ifndef __MINGW32__
655 switch (addr->sa_family)
657 case AF_INET:
659 const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
660 struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
661 char *p;
663 addr_win->sin_family = WS_AF_INET;
664 addr_win->sin_port = addr_unix->sin_port;
665 memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
666 p = (char *)&addr_win->sin_addr + 4;
667 memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
668 return TRUE;
670 case AF_INET6:
672 const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
673 struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
675 addr_win->sin6_family = WS_AF_INET6;
676 addr_win->sin6_port = addr_unix->sin6_port;
677 addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
678 memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
679 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
680 addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
681 #else
682 addr_win->sin6_scope_id = 0;
683 #endif
684 memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
685 return TRUE;
687 default:
688 ERR("unhandled family %u\n", addr->sa_family);
689 return FALSE;
691 #else
692 switch (addr->sa_family)
694 case AF_INET:
696 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
698 memcpy( addr_in, addr, sizeof(*addr_in) );
699 memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
700 return TRUE;
702 case AF_INET6:
704 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
706 memcpy( addr_in6, addr, sizeof(*addr_in6) );
707 memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
708 return TRUE;
710 default:
711 ERR("unhandled family %u\n", addr->sa_family);
712 return FALSE;
714 #endif
717 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
719 request_t *request = (request_t *)hdr;
721 switch (option)
723 case WINHTTP_OPTION_SECURITY_FLAGS:
725 DWORD flags = 0;
726 int bits;
728 if (!buffer || *buflen < sizeof(flags))
730 *buflen = sizeof(flags);
731 set_last_error( ERROR_INSUFFICIENT_BUFFER );
732 return FALSE;
735 flags = 0;
736 if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
737 flags |= request->security_flags;
738 if (request->netconn)
740 bits = netconn_get_cipher_strength( request->netconn );
741 if (bits >= 128)
742 flags |= SECURITY_FLAG_STRENGTH_STRONG;
743 else if (bits >= 56)
744 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
745 else
746 flags |= SECURITY_FLAG_STRENGTH_WEAK;
748 *(DWORD *)buffer = flags;
749 *buflen = sizeof(flags);
750 return TRUE;
752 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
754 const CERT_CONTEXT *cert;
756 if (!buffer || *buflen < sizeof(cert))
758 *buflen = sizeof(cert);
759 set_last_error( ERROR_INSUFFICIENT_BUFFER );
760 return FALSE;
763 if (!(cert = CertDuplicateCertificateContext( request->server_cert ))) return FALSE;
764 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
765 *buflen = sizeof(cert);
766 return TRUE;
768 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
770 const CERT_CONTEXT *cert = request->server_cert;
771 const CRYPT_OID_INFO *oidInfo;
772 WINHTTP_CERTIFICATE_INFO *ci = buffer;
774 FIXME("partial stub\n");
776 if (!buffer || *buflen < sizeof(*ci))
778 *buflen = sizeof(*ci);
779 set_last_error( ERROR_INSUFFICIENT_BUFFER );
780 return FALSE;
782 if (!cert) return FALSE;
784 ci->ftExpiry = cert->pCertInfo->NotAfter;
785 ci->ftStart = cert->pCertInfo->NotBefore;
786 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
787 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
788 ci->lpszProtocolName = NULL;
789 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, cert->pCertInfo->SignatureAlgorithm.pszObjId, 0 );
790 if (oidInfo)
791 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
792 else
793 ci->lpszSignatureAlgName = NULL;
794 ci->lpszEncryptionAlgName = NULL;
795 ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
797 *buflen = sizeof(*ci);
798 return TRUE;
800 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
802 if (!buffer || *buflen < sizeof(DWORD))
804 *buflen = sizeof(DWORD);
805 set_last_error( ERROR_INSUFFICIENT_BUFFER );
806 return FALSE;
809 *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
810 *buflen = sizeof(DWORD);
811 return TRUE;
813 case WINHTTP_OPTION_CONNECTION_INFO:
815 WINHTTP_CONNECTION_INFO *info = buffer;
816 struct sockaddr local;
817 socklen_t len = sizeof(local);
818 const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
820 if (!buffer || *buflen < sizeof(*info))
822 *buflen = sizeof(*info);
823 set_last_error( ERROR_INSUFFICIENT_BUFFER );
824 return FALSE;
826 if (!request->netconn)
828 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
829 return FALSE;
831 if (getsockname( request->netconn->socket, &local, &len )) return FALSE;
832 if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
833 if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
834 info->cbSize = sizeof(*info);
835 return TRUE;
837 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
838 *(DWORD *)buffer = request->resolve_timeout;
839 *buflen = sizeof(DWORD);
840 return TRUE;
841 case WINHTTP_OPTION_CONNECT_TIMEOUT:
842 *(DWORD *)buffer = request->connect_timeout;
843 *buflen = sizeof(DWORD);
844 return TRUE;
845 case WINHTTP_OPTION_SEND_TIMEOUT:
846 *(DWORD *)buffer = request->send_timeout;
847 *buflen = sizeof(DWORD);
848 return TRUE;
849 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
850 *(DWORD *)buffer = request->recv_timeout;
851 *buflen = sizeof(DWORD);
852 return TRUE;
854 case WINHTTP_OPTION_USERNAME:
855 str_to_buffer( buffer, request->connect->username, buflen );
856 return TRUE;
858 case WINHTTP_OPTION_PASSWORD:
859 str_to_buffer( buffer, request->connect->password, buflen );
860 return TRUE;
862 case WINHTTP_OPTION_PROXY_USERNAME:
863 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
864 return TRUE;
866 case WINHTTP_OPTION_PROXY_PASSWORD:
867 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
868 return TRUE;
870 default:
871 FIXME("unimplemented option %u\n", option);
872 set_last_error( ERROR_INVALID_PARAMETER );
873 return FALSE;
877 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
879 WCHAR *ret;
880 if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
882 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
883 ret[buflen] = 0;
884 return ret;
886 set_last_error( ERROR_OUTOFMEMORY );
887 return NULL;
890 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
892 request_t *request = (request_t *)hdr;
894 switch (option)
896 case WINHTTP_OPTION_PROXY:
898 WINHTTP_PROXY_INFO *pi = buffer;
900 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
901 return TRUE;
903 case WINHTTP_OPTION_DISABLE_FEATURE:
905 DWORD disable;
907 if (buflen != sizeof(DWORD))
909 set_last_error( ERROR_INSUFFICIENT_BUFFER );
910 return FALSE;
913 disable = *(DWORD *)buffer;
914 TRACE("0x%x\n", disable);
915 hdr->disable_flags |= disable;
916 return TRUE;
918 case WINHTTP_OPTION_AUTOLOGON_POLICY:
920 DWORD policy;
922 if (buflen != sizeof(DWORD))
924 set_last_error( ERROR_INSUFFICIENT_BUFFER );
925 return FALSE;
928 policy = *(DWORD *)buffer;
929 TRACE("0x%x\n", policy);
930 hdr->logon_policy = policy;
931 return TRUE;
933 case WINHTTP_OPTION_REDIRECT_POLICY:
935 DWORD policy;
937 if (buflen != sizeof(DWORD))
939 set_last_error( ERROR_INSUFFICIENT_BUFFER );
940 return FALSE;
943 policy = *(DWORD *)buffer;
944 TRACE("0x%x\n", policy);
945 hdr->redirect_policy = policy;
946 return TRUE;
948 case WINHTTP_OPTION_SECURITY_FLAGS:
950 DWORD flags;
952 if (buflen < sizeof(DWORD))
954 set_last_error( ERROR_INSUFFICIENT_BUFFER );
955 return FALSE;
957 flags = *(DWORD *)buffer;
958 TRACE("0x%x\n", flags);
959 if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
960 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
961 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
962 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
964 set_last_error( ERROR_INVALID_PARAMETER );
965 return FALSE;
967 request->security_flags = flags;
968 return TRUE;
970 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
971 request->resolve_timeout = *(DWORD *)buffer;
972 return TRUE;
973 case WINHTTP_OPTION_CONNECT_TIMEOUT:
974 request->connect_timeout = *(DWORD *)buffer;
975 return TRUE;
976 case WINHTTP_OPTION_SEND_TIMEOUT:
977 request->send_timeout = *(DWORD *)buffer;
978 return TRUE;
979 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
980 request->recv_timeout = *(DWORD *)buffer;
981 return TRUE;
983 case WINHTTP_OPTION_USERNAME:
985 connect_t *connect = request->connect;
987 heap_free( connect->username );
988 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
989 return TRUE;
991 case WINHTTP_OPTION_PASSWORD:
993 connect_t *connect = request->connect;
995 heap_free( connect->password );
996 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
997 return TRUE;
999 case WINHTTP_OPTION_PROXY_USERNAME:
1001 session_t *session = request->connect->session;
1003 heap_free( session->proxy_username );
1004 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
1005 return TRUE;
1007 case WINHTTP_OPTION_PROXY_PASSWORD:
1009 session_t *session = request->connect->session;
1011 heap_free( session->proxy_password );
1012 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
1013 return TRUE;
1015 case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
1016 if (!(hdr->flags & WINHTTP_FLAG_SECURE))
1018 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
1019 return FALSE;
1021 FIXME("WINHTTP_OPTION_CLIENT_CERT_CONTEXT\n");
1022 return TRUE;
1023 default:
1024 FIXME("unimplemented option %u\n", option);
1025 set_last_error( ERROR_WINHTTP_INVALID_OPTION );
1026 return FALSE;
1030 static const object_vtbl_t request_vtbl =
1032 request_destroy,
1033 request_query_option,
1034 request_set_option
1037 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
1039 const WCHAR **types = accept_types;
1040 DWORD i;
1042 if (!types) return TRUE;
1043 while (*types)
1045 request->num_accept_types++;
1046 types++;
1048 if (!request->num_accept_types) return TRUE;
1049 if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
1051 request->num_accept_types = 0;
1052 return FALSE;
1054 types = accept_types;
1055 for (i = 0; i < request->num_accept_types; i++)
1057 if (!(request->accept_types[i] = strdupW( *types )))
1059 for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
1060 heap_free( request->accept_types );
1061 request->accept_types = NULL;
1062 request->num_accept_types = 0;
1063 return FALSE;
1065 types++;
1067 return TRUE;
1070 /***********************************************************************
1071 * WinHttpOpenRequest (winhttp.@)
1073 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
1074 LPCWSTR referrer, LPCWSTR *types, DWORD flags )
1076 request_t *request;
1077 connect_t *connect;
1078 HINTERNET hrequest = NULL;
1080 TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
1081 debugstr_w(version), debugstr_w(referrer), types, flags);
1083 if(types && TRACE_ON(winhttp)) {
1084 const WCHAR **iter;
1086 TRACE("accept types:\n");
1087 for(iter = types; *iter; iter++)
1088 TRACE(" %s\n", debugstr_w(*iter));
1091 if (!(connect = (connect_t *)grab_object( hconnect )))
1093 set_last_error( ERROR_INVALID_HANDLE );
1094 return NULL;
1096 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1098 release_object( &connect->hdr );
1099 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1100 return NULL;
1102 if (!(request = heap_alloc_zero( sizeof(request_t) )))
1104 release_object( &connect->hdr );
1105 return NULL;
1107 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1108 request->hdr.vtbl = &request_vtbl;
1109 request->hdr.refs = 1;
1110 request->hdr.flags = flags;
1111 request->hdr.callback = connect->hdr.callback;
1112 request->hdr.notify_mask = connect->hdr.notify_mask;
1113 request->hdr.context = connect->hdr.context;
1114 request->hdr.redirect_policy = connect->hdr.redirect_policy;
1115 list_init( &request->hdr.children );
1116 list_init( &request->task_queue );
1118 addref_object( &connect->hdr );
1119 request->connect = connect;
1120 list_add_head( &connect->hdr.children, &request->hdr.entry );
1122 request->resolve_timeout = connect->session->resolve_timeout;
1123 request->connect_timeout = connect->session->connect_timeout;
1124 request->send_timeout = connect->session->send_timeout;
1125 request->recv_timeout = connect->session->recv_timeout;
1127 if (!verb || !verb[0]) verb = getW;
1128 if (!(request->verb = strdupW( verb ))) goto end;
1130 if (object)
1132 WCHAR *path, *p;
1133 unsigned int len;
1135 len = strlenW( object ) + 1;
1136 if (object[0] != '/') len++;
1137 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
1139 if (object[0] != '/') *p++ = '/';
1140 strcpyW( p, object );
1141 request->path = path;
1143 else if (!(request->path = strdupW( slashW ))) goto end;
1145 if (!version || !version[0]) version = http1_1;
1146 if (!(request->version = strdupW( version ))) goto end;
1147 if (!(store_accept_types( request, types ))) goto end;
1149 if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
1150 request->hdr.handle = hrequest;
1152 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1154 end:
1155 release_object( &request->hdr );
1156 release_object( &connect->hdr );
1157 TRACE("returning %p\n", hrequest);
1158 if (hrequest) set_last_error( ERROR_SUCCESS );
1159 return hrequest;
1162 /***********************************************************************
1163 * WinHttpCloseHandle (winhttp.@)
1165 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1167 object_header_t *hdr;
1169 TRACE("%p\n", handle);
1171 if (!(hdr = grab_object( handle )))
1173 set_last_error( ERROR_INVALID_HANDLE );
1174 return FALSE;
1176 release_object( hdr );
1177 free_handle( handle );
1178 set_last_error( ERROR_SUCCESS );
1179 return TRUE;
1182 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1184 BOOL ret = FALSE;
1186 if (!buflen)
1188 set_last_error( ERROR_INVALID_PARAMETER );
1189 return FALSE;
1192 switch (option)
1194 case WINHTTP_OPTION_CONTEXT_VALUE:
1196 if (!buffer || *buflen < sizeof(DWORD_PTR))
1198 *buflen = sizeof(DWORD_PTR);
1199 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1200 return FALSE;
1203 *(DWORD_PTR *)buffer = hdr->context;
1204 *buflen = sizeof(DWORD_PTR);
1205 return TRUE;
1207 default:
1208 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1209 else
1211 FIXME("unimplemented option %u\n", option);
1212 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1213 return FALSE;
1215 break;
1217 return ret;
1220 /***********************************************************************
1221 * WinHttpQueryOption (winhttp.@)
1223 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1225 BOOL ret = FALSE;
1226 object_header_t *hdr;
1228 TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1230 if (!(hdr = grab_object( handle )))
1232 set_last_error( ERROR_INVALID_HANDLE );
1233 return FALSE;
1236 ret = query_option( hdr, option, buffer, buflen );
1238 release_object( hdr );
1239 if (ret) set_last_error( ERROR_SUCCESS );
1240 return ret;
1243 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1245 BOOL ret = TRUE;
1247 if (!buffer && buflen)
1249 set_last_error( ERROR_INVALID_PARAMETER );
1250 return FALSE;
1253 switch (option)
1255 case WINHTTP_OPTION_CONTEXT_VALUE:
1257 if (buflen != sizeof(DWORD_PTR))
1259 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1260 return FALSE;
1263 hdr->context = *(DWORD_PTR *)buffer;
1264 return TRUE;
1266 default:
1267 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1268 else
1270 FIXME("unimplemented option %u\n", option);
1271 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1272 return FALSE;
1274 break;
1276 return ret;
1279 /***********************************************************************
1280 * WinHttpSetOption (winhttp.@)
1282 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1284 BOOL ret = FALSE;
1285 object_header_t *hdr;
1287 TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1289 if (!(hdr = grab_object( handle )))
1291 set_last_error( ERROR_INVALID_HANDLE );
1292 return FALSE;
1295 ret = set_option( hdr, option, buffer, buflen );
1297 release_object( hdr );
1298 if (ret) set_last_error( ERROR_SUCCESS );
1299 return ret;
1302 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1304 char *ret;
1305 DWORD size = 0;
1307 GetComputerNameExA( format, NULL, &size );
1308 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1309 if (!(ret = heap_alloc( size ))) return NULL;
1310 if (!GetComputerNameExA( format, ret, &size ))
1312 heap_free( ret );
1313 return NULL;
1315 return ret;
1318 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1320 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1322 if (len_suffix > len_domain) return FALSE;
1323 if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1324 return FALSE;
1327 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1329 int ret = -1;
1330 #ifdef HAVE_GETNAMEINFO
1331 ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1332 #endif
1333 return ret;
1336 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1338 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1339 static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
1340 char name[NI_MAXHOST];
1341 WCHAR *ret, *p;
1342 int len;
1344 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1345 if (!ai) return NULL;
1347 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1349 len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
1350 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1351 strcpyW( p, httpW );
1352 p += strlenW( httpW );
1353 while (*hostname) { *p++ = *hostname++; }
1354 strcpyW( p, wpadW );
1355 return ret;
1358 static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen )
1360 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1361 CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
1362 const void *ref;
1363 BOOL ret = FALSE;
1365 if (!settings) return FALSE;
1367 if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
1369 CFRelease( settings );
1370 return FALSE;
1372 if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII ))
1374 TRACE( "returning %s\n", debugstr_a(buf) );
1375 ret = TRUE;
1377 CFRelease( settings );
1378 return ret;
1379 #else
1380 static BOOL first = TRUE;
1381 if (first)
1383 FIXME( "no support on this platform\n" );
1384 first = FALSE;
1386 else
1387 TRACE( "no support on this platform\n" );
1388 return FALSE;
1389 #endif
1392 #define INTERNET_MAX_URL_LENGTH 2084
1394 /***********************************************************************
1395 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1397 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1399 BOOL ret = FALSE;
1400 char system_url[INTERNET_MAX_URL_LENGTH + 1];
1402 TRACE("0x%08x, %p\n", flags, url);
1404 if (!flags || !url)
1406 set_last_error( ERROR_INVALID_PARAMETER );
1407 return FALSE;
1409 if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) ))
1411 WCHAR *urlW;
1413 if (!(urlW = strdupAW( system_url ))) return FALSE;
1414 *url = urlW;
1415 set_last_error( ERROR_SUCCESS );
1416 return TRUE;
1418 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1420 static int fixme_shown;
1421 if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
1423 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1425 #ifdef HAVE_GETADDRINFO
1426 char *fqdn, *domain, *p;
1428 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1429 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1431 heap_free( fqdn );
1432 return FALSE;
1434 p = fqdn;
1435 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1437 struct addrinfo *ai;
1438 char *name;
1439 int res;
1441 if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1443 heap_free( fqdn );
1444 heap_free( domain );
1445 return FALSE;
1447 strcpy( name, "wpad" );
1448 strcat( name, p );
1449 res = getaddrinfo( name, NULL, NULL, &ai );
1450 if (!res)
1452 *url = build_wpad_url( name, ai );
1453 freeaddrinfo( ai );
1454 if (*url)
1456 TRACE("returning %s\n", debugstr_w(*url));
1457 heap_free( name );
1458 ret = TRUE;
1459 break;
1462 heap_free( name );
1463 p++;
1465 heap_free( domain );
1466 heap_free( fqdn );
1467 #else
1468 FIXME("getaddrinfo not found at build time\n");
1469 #endif
1471 if (!ret)
1473 set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1474 *url = NULL;
1476 else set_last_error( ERROR_SUCCESS );
1477 return ret;
1480 static const WCHAR Connections[] = {
1481 'S','o','f','t','w','a','r','e','\\',
1482 'M','i','c','r','o','s','o','f','t','\\',
1483 'W','i','n','d','o','w','s','\\',
1484 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1485 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1486 'C','o','n','n','e','c','t','i','o','n','s',0 };
1487 static const WCHAR WinHttpSettings[] = {
1488 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1489 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1490 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1491 static const DWORD PROXY_TYPE_DIRECT = 1;
1492 static const DWORD PROXY_TYPE_PROXY = 2;
1493 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1494 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1496 struct connection_settings_header
1498 DWORD magic;
1499 DWORD unknown; /* always zero? */
1500 DWORD flags; /* one or more of PROXY_* */
1503 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1505 const BYTE *begin;
1507 for (begin = src; src - begin < len; src++, dst++)
1508 *dst = *src;
1509 *dst = 0;
1512 /***********************************************************************
1513 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1515 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1517 LONG l;
1518 HKEY key;
1519 BOOL got_from_reg = FALSE, direct = TRUE;
1520 char *envproxy;
1522 TRACE("%p\n", info);
1524 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1525 if (!l)
1527 DWORD type, size = 0;
1529 l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1530 if (!l && type == REG_BINARY &&
1531 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1533 BYTE *buf = heap_alloc( size );
1535 if (buf)
1537 struct connection_settings_header *hdr =
1538 (struct connection_settings_header *)buf;
1539 DWORD *len = (DWORD *)(hdr + 1);
1541 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1542 &size );
1543 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1544 hdr->unknown == 0)
1546 if (hdr->flags & PROXY_TYPE_PROXY)
1548 BOOL sane = FALSE;
1549 LPWSTR proxy = NULL;
1550 LPWSTR proxy_bypass = NULL;
1552 /* Sanity-check length of proxy string */
1553 if ((BYTE *)len - buf + *len <= size)
1555 sane = TRUE;
1556 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1557 if (proxy)
1558 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1559 len = (DWORD *)((BYTE *)(len + 1) + *len);
1561 if (sane)
1563 /* Sanity-check length of proxy bypass string */
1564 if ((BYTE *)len - buf + *len <= size)
1566 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1567 if (proxy_bypass)
1568 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1570 else
1572 sane = FALSE;
1573 GlobalFree( proxy );
1574 proxy = NULL;
1577 info->lpszProxy = proxy;
1578 info->lpszProxyBypass = proxy_bypass;
1579 if (sane)
1581 got_from_reg = TRUE;
1582 direct = FALSE;
1583 info->dwAccessType =
1584 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1585 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1586 debugstr_w(info->lpszProxy),
1587 debugstr_w(info->lpszProxyBypass));
1591 heap_free( buf );
1594 RegCloseKey( key );
1596 if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1598 char *colon, *http_proxy = NULL;
1600 if (!(colon = strchr( envproxy, ':' ))) http_proxy = envproxy;
1601 else
1603 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1605 /* It's a scheme, check that it's http */
1606 if (!strncmp( envproxy, "http://", 7 )) http_proxy = envproxy + 7;
1607 else WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1609 else http_proxy = envproxy;
1612 if (http_proxy && http_proxy[0])
1614 WCHAR *http_proxyW;
1615 int len;
1617 len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1618 if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1620 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1621 direct = FALSE;
1622 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1623 info->lpszProxy = http_proxyW;
1624 info->lpszProxyBypass = NULL;
1625 TRACE("http proxy (from environment) = %s\n", debugstr_w(info->lpszProxy));
1629 if (direct)
1631 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1632 info->lpszProxy = NULL;
1633 info->lpszProxyBypass = NULL;
1635 set_last_error( ERROR_SUCCESS );
1636 return TRUE;
1639 /***********************************************************************
1640 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1642 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1644 static const WCHAR settingsW[] =
1645 {'D','e','f','a','u','l','t','C','o','n','n','e','c','t','i','o','n','S','e','t','t','i','n','g','s',0};
1646 HKEY hkey = NULL;
1647 struct connection_settings_header *hdr = NULL;
1648 DWORD type, offset, len, size = 0;
1649 BOOL ret = FALSE;
1651 TRACE("%p\n", config);
1653 if (!config)
1655 set_last_error( ERROR_INVALID_PARAMETER );
1656 return FALSE;
1658 memset( config, 0, sizeof(*config) );
1659 config->fAutoDetect = TRUE;
1661 if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1662 RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1663 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1665 ret = TRUE;
1666 goto done;
1668 if (!(hdr = heap_alloc( size ))) goto done;
1669 if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1670 hdr->magic != WININET_SETTINGS_MAGIC)
1672 ret = TRUE;
1673 goto done;
1676 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1677 offset = sizeof(*hdr);
1678 if (offset + sizeof(DWORD) > size) goto done;
1679 len = *(DWORD *)((char *)hdr + offset);
1680 offset += sizeof(DWORD);
1681 if (len && hdr->flags & PROXY_TYPE_PROXY)
1683 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1684 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1686 offset += len;
1687 if (offset + sizeof(DWORD) > size) goto done;
1688 len = *(DWORD *)((char *)hdr + offset);
1689 offset += sizeof(DWORD);
1690 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1692 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1693 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1695 offset += len;
1696 if (offset + sizeof(DWORD) > size) goto done;
1697 len = *(DWORD *)((char *)hdr + offset);
1698 offset += sizeof(DWORD);
1699 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1701 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1702 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1704 ret = TRUE;
1706 done:
1707 RegCloseKey( hkey );
1708 heap_free( hdr );
1709 if (!ret)
1711 GlobalFree( config->lpszAutoConfigUrl );
1712 config->lpszAutoConfigUrl = NULL;
1713 GlobalFree( config->lpszProxy );
1714 config->lpszProxy = NULL;
1715 GlobalFree( config->lpszProxyBypass );
1716 config->lpszProxyBypass = NULL;
1718 else set_last_error( ERROR_SUCCESS );
1719 return ret;
1722 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1724 const char *p;
1725 WCHAR *q;
1726 int len;
1728 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1729 info->lpszProxy = NULL;
1730 info->lpszProxyBypass = NULL;
1732 TRACE("%s\n", debugstr_a( result ));
1734 p = result;
1735 while (*p == ' ') p++;
1736 len = strlen( p );
1737 if (len >= 5 && !strncasecmp( p, "PROXY", sizeof("PROXY") - 1 ))
1739 p += 5;
1740 while (*p == ' ') p++;
1741 if (!*p || *p == ';') return TRUE;
1742 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1743 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1744 for (; *q; q++)
1746 if (*q == ' ' || *q == ';')
1748 *q = 0;
1749 break;
1753 return TRUE;
1756 static char *download_script( const WCHAR *url, DWORD *out_size )
1758 static const WCHAR typeW[] = {'*','/','*',0};
1759 static const WCHAR *acceptW[] = {typeW, NULL};
1760 HINTERNET ses, con = NULL, req = NULL;
1761 WCHAR *hostname;
1762 URL_COMPONENTSW uc;
1763 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1764 char *tmp, *buffer = NULL;
1766 *out_size = 0;
1768 memset( &uc, 0, sizeof(uc) );
1769 uc.dwStructSize = sizeof(uc);
1770 uc.dwHostNameLength = -1;
1771 uc.dwUrlPathLength = -1;
1772 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1773 if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1774 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1775 hostname[uc.dwHostNameLength] = 0;
1777 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1778 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1779 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1780 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1781 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1783 if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1784 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1785 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1787 size = 4096;
1788 if (!(buffer = heap_alloc( size ))) goto done;
1789 to_read = size;
1790 offset = 0;
1791 for (;;)
1793 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1794 if (!bytes_read) break;
1795 to_read -= bytes_read;
1796 offset += bytes_read;
1797 *out_size += bytes_read;
1798 if (!to_read)
1800 to_read = size;
1801 size *= 2;
1802 if (!(tmp = heap_realloc( buffer, size ))) goto done;
1803 buffer = tmp;
1807 done:
1808 WinHttpCloseHandle( req );
1809 WinHttpCloseHandle( con );
1810 WinHttpCloseHandle( ses );
1811 heap_free( hostname );
1812 if (!buffer) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1813 return buffer;
1816 struct AUTO_PROXY_SCRIPT_BUFFER
1818 DWORD dwStructSize;
1819 LPSTR lpszScriptBuffer;
1820 DWORD dwScriptBufferSize;
1823 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1824 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1825 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1827 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1829 BOOL ret;
1830 char *result, *urlA;
1831 DWORD len_result;
1832 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1833 URL_COMPONENTSW uc;
1835 buffer.dwStructSize = sizeof(buffer);
1836 buffer.lpszScriptBuffer = script;
1837 buffer.dwScriptBufferSize = size;
1839 if (!(urlA = strdupWA( url ))) return FALSE;
1840 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1842 heap_free( urlA );
1843 return FALSE;
1846 memset( &uc, 0, sizeof(uc) );
1847 uc.dwStructSize = sizeof(uc);
1848 uc.dwHostNameLength = -1;
1850 if (WinHttpCrackUrl( url, 0, 0, &uc ))
1852 char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
1854 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
1855 hostnameA, strlen(hostnameA), &result, &len_result )))
1857 ret = parse_script_result( result, info );
1858 heap_free( result );
1861 heap_free( hostnameA );
1863 heap_free( urlA );
1864 return InternetDeInitializeAutoProxyDll( NULL, 0 );
1867 /***********************************************************************
1868 * WinHttpGetProxyForUrl (winhttp.@)
1870 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1871 WINHTTP_PROXY_INFO *info )
1873 WCHAR *detected_pac_url = NULL;
1874 const WCHAR *pac_url;
1875 session_t *session;
1876 char *script;
1877 DWORD size;
1878 BOOL ret = FALSE;
1880 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1882 if (!(session = (session_t *)grab_object( hsession )))
1884 set_last_error( ERROR_INVALID_HANDLE );
1885 return FALSE;
1887 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1889 release_object( &session->hdr );
1890 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1891 return FALSE;
1893 if (!url || !options || !info ||
1894 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1895 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1896 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1897 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1899 release_object( &session->hdr );
1900 set_last_error( ERROR_INVALID_PARAMETER );
1901 return FALSE;
1903 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1904 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1905 goto done;
1907 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1908 else pac_url = detected_pac_url;
1910 if ((script = download_script( pac_url, &size )))
1912 ret = run_script( script, size, url, info );
1913 heap_free( script );
1916 done:
1917 GlobalFree( detected_pac_url );
1918 release_object( &session->hdr );
1919 if (ret) set_last_error( ERROR_SUCCESS );
1920 return ret;
1923 /***********************************************************************
1924 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
1926 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1928 LONG l;
1929 HKEY key;
1930 BOOL ret = FALSE;
1931 const WCHAR *src;
1933 TRACE("%p\n", info);
1935 if (!info)
1937 set_last_error( ERROR_INVALID_PARAMETER );
1938 return FALSE;
1940 switch (info->dwAccessType)
1942 case WINHTTP_ACCESS_TYPE_NO_PROXY:
1943 break;
1944 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1945 if (!info->lpszProxy)
1947 set_last_error( ERROR_INVALID_PARAMETER );
1948 return FALSE;
1950 /* Only ASCII characters are allowed */
1951 for (src = info->lpszProxy; *src; src++)
1952 if (*src > 0x7f)
1954 set_last_error( ERROR_INVALID_PARAMETER );
1955 return FALSE;
1957 if (info->lpszProxyBypass)
1959 for (src = info->lpszProxyBypass; *src; src++)
1960 if (*src > 0x7f)
1962 set_last_error( ERROR_INVALID_PARAMETER );
1963 return FALSE;
1966 break;
1967 default:
1968 set_last_error( ERROR_INVALID_PARAMETER );
1969 return FALSE;
1972 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1973 KEY_WRITE, NULL, &key, NULL );
1974 if (!l)
1976 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1977 BYTE *buf;
1979 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1981 size += strlenW( info->lpszProxy );
1982 if (info->lpszProxyBypass)
1983 size += strlenW( info->lpszProxyBypass );
1985 buf = heap_alloc( size );
1986 if (buf)
1988 struct connection_settings_header *hdr =
1989 (struct connection_settings_header *)buf;
1990 DWORD *len = (DWORD *)(hdr + 1);
1992 hdr->magic = WINHTTP_SETTINGS_MAGIC;
1993 hdr->unknown = 0;
1994 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1996 BYTE *dst;
1998 hdr->flags = PROXY_TYPE_PROXY;
1999 *len++ = strlenW( info->lpszProxy );
2000 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
2001 src++, dst++)
2002 *dst = *src;
2003 len = (DWORD *)dst;
2004 if (info->lpszProxyBypass)
2006 *len++ = strlenW( info->lpszProxyBypass );
2007 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
2008 src++, dst++)
2009 *dst = *src;
2011 else
2012 *len++ = 0;
2014 else
2016 hdr->flags = PROXY_TYPE_DIRECT;
2017 *len++ = 0;
2018 *len++ = 0;
2020 l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
2021 if (!l)
2022 ret = TRUE;
2023 heap_free( buf );
2025 RegCloseKey( key );
2027 if (ret) set_last_error( ERROR_SUCCESS );
2028 return ret;
2031 /***********************************************************************
2032 * WinHttpSetStatusCallback (winhttp.@)
2034 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2035 DWORD flags, DWORD_PTR reserved )
2037 object_header_t *hdr;
2038 WINHTTP_STATUS_CALLBACK ret;
2040 TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
2042 if (!(hdr = grab_object( handle )))
2044 set_last_error( ERROR_INVALID_HANDLE );
2045 return WINHTTP_INVALID_STATUS_CALLBACK;
2047 ret = hdr->callback;
2048 hdr->callback = callback;
2049 hdr->notify_mask = flags;
2051 release_object( hdr );
2052 set_last_error( ERROR_SUCCESS );
2053 return ret;
2056 /***********************************************************************
2057 * WinHttpSetTimeouts (winhttp.@)
2059 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2061 BOOL ret = TRUE;
2062 object_header_t *hdr;
2063 request_t *request;
2064 session_t *session;
2066 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2068 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2070 set_last_error( ERROR_INVALID_PARAMETER );
2071 return FALSE;
2074 if (!(hdr = grab_object( handle )))
2076 set_last_error( ERROR_INVALID_HANDLE );
2077 return FALSE;
2080 switch(hdr->type)
2082 case WINHTTP_HANDLE_TYPE_REQUEST:
2083 request = (request_t *)hdr;
2084 request->connect_timeout = connect;
2086 if (resolve < 0) resolve = 0;
2087 request->resolve_timeout = resolve;
2089 if (send < 0) send = 0;
2090 request->send_timeout = send;
2092 if (receive < 0) receive = 0;
2093 request->recv_timeout = receive;
2095 if (request->netconn)
2097 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2098 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2100 break;
2102 case WINHTTP_HANDLE_TYPE_SESSION:
2103 session = (session_t *)hdr;
2104 session->connect_timeout = connect;
2106 if (resolve < 0) resolve = 0;
2107 session->resolve_timeout = resolve;
2109 if (send < 0) send = 0;
2110 session->send_timeout = send;
2112 if (receive < 0) receive = 0;
2113 session->recv_timeout = receive;
2114 break;
2116 default:
2117 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2118 ret = FALSE;
2120 release_object( hdr );
2121 if (ret) set_last_error( ERROR_SUCCESS );
2122 return ret;
2125 static const WCHAR wkday[7][4] =
2126 {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2127 {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2128 static const WCHAR month[12][4] =
2129 {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2130 {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2131 {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2133 /***********************************************************************
2134 * WinHttpTimeFromSystemTime (WININET.@)
2136 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2138 static const WCHAR format[] =
2139 {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2140 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2142 TRACE("%p, %p\n", time, string);
2144 if (!time || !string)
2146 set_last_error( ERROR_INVALID_PARAMETER );
2147 return FALSE;
2150 sprintfW( string, format,
2151 wkday[time->wDayOfWeek],
2152 time->wDay,
2153 month[time->wMonth - 1],
2154 time->wYear,
2155 time->wHour,
2156 time->wMinute,
2157 time->wSecond );
2159 set_last_error( ERROR_SUCCESS );
2160 return TRUE;
2163 /***********************************************************************
2164 * WinHttpTimeToSystemTime (WININET.@)
2166 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2168 unsigned int i;
2169 const WCHAR *s = string;
2170 WCHAR *end;
2172 TRACE("%s, %p\n", debugstr_w(string), time);
2174 if (!string || !time)
2176 set_last_error( ERROR_INVALID_PARAMETER );
2177 return FALSE;
2180 /* Windows does this too */
2181 GetSystemTime( time );
2183 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2184 * a SYSTEMTIME structure.
2187 set_last_error( ERROR_SUCCESS );
2189 while (*s && !isalphaW( *s )) s++;
2190 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2191 time->wDayOfWeek = 7;
2193 for (i = 0; i < 7; i++)
2195 if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2196 toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2197 toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2199 time->wDayOfWeek = i;
2200 break;
2204 if (time->wDayOfWeek > 6) return TRUE;
2205 while (*s && !isdigitW( *s )) s++;
2206 time->wDay = strtolW( s, &end, 10 );
2207 s = end;
2209 while (*s && !isalphaW( *s )) s++;
2210 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2211 time->wMonth = 0;
2213 for (i = 0; i < 12; i++)
2215 if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2216 toupperW( month[i][1]) == toupperW( s[1] ) &&
2217 toupperW( month[i][2]) == toupperW( s[2] ) )
2219 time->wMonth = i + 1;
2220 break;
2223 if (time->wMonth == 0) return TRUE;
2225 while (*s && !isdigitW( *s )) s++;
2226 if (*s == '\0') return TRUE;
2227 time->wYear = strtolW( s, &end, 10 );
2228 s = end;
2230 while (*s && !isdigitW( *s )) s++;
2231 if (*s == '\0') return TRUE;
2232 time->wHour = strtolW( s, &end, 10 );
2233 s = end;
2235 while (*s && !isdigitW( *s )) s++;
2236 if (*s == '\0') return TRUE;
2237 time->wMinute = strtolW( s, &end, 10 );
2238 s = end;
2240 while (*s && !isdigitW( *s )) s++;
2241 if (*s == '\0') return TRUE;
2242 time->wSecond = strtolW( s, &end, 10 );
2244 time->wMilliseconds = 0;
2245 return TRUE;