winhttp: Avoid returning while holding a lock (Coverity).
[wine.git] / dlls / winhttp / session.c
blob877794af45bb5bd1c7fb70a3cbf1804f7f25db66
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #ifdef HAVE_CORESERVICES_CORESERVICES_H
27 #define GetCurrentThread MacGetCurrentThread
28 #define LoadResource MacLoadResource
29 #include <CoreServices/CoreServices.h>
30 #undef GetCurrentThread
31 #undef LoadResource
32 #undef DPRINTF
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #ifndef __MINGW32__
38 #define USE_WS_PREFIX
39 #endif
40 #include "winsock2.h"
41 #include "ws2ipdef.h"
42 #include "winhttp.h"
43 #include "wincrypt.h"
44 #include "winreg.h"
45 #define COBJMACROS
46 #include "ole2.h"
47 #include "dispex.h"
48 #include "activscp.h"
50 #include "winhttp_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
54 #define DEFAULT_RESOLVE_TIMEOUT 0
55 #define DEFAULT_CONNECT_TIMEOUT 20000
56 #define DEFAULT_SEND_TIMEOUT 30000
57 #define DEFAULT_RECEIVE_TIMEOUT 30000
59 void set_last_error( DWORD error )
61 /* FIXME */
62 SetLastError( error );
65 DWORD get_last_error( void )
67 /* FIXME */
68 return GetLastError();
71 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
73 if (hdr->callback && (hdr->notify_mask & status))
75 TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
76 hdr->callback( hdr->handle, hdr->context, status, info, buflen );
77 TRACE("returning from 0x%08x callback\n", status);
81 /***********************************************************************
82 * WinHttpCheckPlatform (winhttp.@)
84 BOOL WINAPI WinHttpCheckPlatform( void )
86 TRACE("\n");
87 return TRUE;
90 /***********************************************************************
91 * session_destroy (internal)
93 static void session_destroy( object_header_t *hdr )
95 session_t *session = (session_t *)hdr;
96 struct list *item, *next;
97 domain_t *domain;
99 TRACE("%p\n", session);
101 if (session->unload_event) SetEvent( session->unload_event );
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_DISABLE_FEATURE:
187 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
188 return FALSE;
189 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
190 session->resolve_timeout = *(DWORD *)buffer;
191 return TRUE;
192 case WINHTTP_OPTION_CONNECT_TIMEOUT:
193 session->connect_timeout = *(DWORD *)buffer;
194 return TRUE;
195 case WINHTTP_OPTION_SEND_TIMEOUT:
196 session->send_timeout = *(DWORD *)buffer;
197 return TRUE;
198 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
199 session->recv_timeout = *(DWORD *)buffer;
200 return TRUE;
201 case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
202 FIXME("WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: 0x%x\n", *(DWORD *)buffer);
203 return TRUE;
204 case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
205 TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
206 session->unload_event = *(HANDLE *)buffer;
207 return TRUE;
208 case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
209 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %d\n", *(DWORD *)buffer);
210 return TRUE;
211 case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
212 FIXME("WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %d\n", *(DWORD *)buffer);
213 return TRUE;
214 default:
215 FIXME("unimplemented option %u\n", option);
216 set_last_error( ERROR_INVALID_PARAMETER );
217 return FALSE;
221 static const object_vtbl_t session_vtbl =
223 session_destroy,
224 session_query_option,
225 session_set_option
228 /***********************************************************************
229 * WinHttpOpen (winhttp.@)
231 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
233 session_t *session;
234 HINTERNET handle = NULL;
236 TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
238 if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
240 session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
241 session->hdr.vtbl = &session_vtbl;
242 session->hdr.flags = flags;
243 session->hdr.refs = 1;
244 session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
245 list_init( &session->hdr.children );
246 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
247 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
248 session->send_timeout = DEFAULT_SEND_TIMEOUT;
249 session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
250 list_init( &session->cookie_cache );
252 if (agent && !(session->agent = strdupW( agent ))) goto end;
253 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
255 WINHTTP_PROXY_INFO info;
257 WinHttpGetDefaultProxyConfiguration( &info );
258 session->access = info.dwAccessType;
259 if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
261 GlobalFree( info.lpszProxy );
262 GlobalFree( info.lpszProxyBypass );
263 goto end;
265 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
267 GlobalFree( info.lpszProxy );
268 GlobalFree( info.lpszProxyBypass );
269 goto end;
272 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
274 session->access = access;
275 if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
276 if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
279 if (!(handle = alloc_handle( &session->hdr ))) goto end;
280 session->hdr.handle = handle;
282 end:
283 release_object( &session->hdr );
284 TRACE("returning %p\n", handle);
285 if (handle) set_last_error( ERROR_SUCCESS );
286 return handle;
289 /***********************************************************************
290 * connect_destroy (internal)
292 static void connect_destroy( object_header_t *hdr )
294 connect_t *connect = (connect_t *)hdr;
296 TRACE("%p\n", connect);
298 release_object( &connect->session->hdr );
300 heap_free( connect->hostname );
301 heap_free( connect->servername );
302 heap_free( connect->username );
303 heap_free( connect->password );
304 heap_free( connect );
307 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
309 connect_t *connect = (connect_t *)hdr;
311 switch (option)
313 case WINHTTP_OPTION_PARENT_HANDLE:
315 if (!buffer || *buflen < sizeof(HINTERNET))
317 *buflen = sizeof(HINTERNET);
318 set_last_error( ERROR_INSUFFICIENT_BUFFER );
319 return FALSE;
322 *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
323 *buflen = sizeof(HINTERNET);
324 return TRUE;
326 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
327 *(DWORD *)buffer = connect->session->resolve_timeout;
328 *buflen = sizeof(DWORD);
329 return TRUE;
330 case WINHTTP_OPTION_CONNECT_TIMEOUT:
331 *(DWORD *)buffer = connect->session->connect_timeout;
332 *buflen = sizeof(DWORD);
333 return TRUE;
334 case WINHTTP_OPTION_SEND_TIMEOUT:
335 *(DWORD *)buffer = connect->session->send_timeout;
336 *buflen = sizeof(DWORD);
337 return TRUE;
338 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
339 *(DWORD *)buffer = connect->session->recv_timeout;
340 *buflen = sizeof(DWORD);
341 return TRUE;
342 default:
343 FIXME("unimplemented option %u\n", option);
344 set_last_error( ERROR_INVALID_PARAMETER );
345 return FALSE;
349 static const object_vtbl_t connect_vtbl =
351 connect_destroy,
352 connect_query_option,
353 NULL
356 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
358 static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
359 BOOL ret = FALSE;
361 if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
362 ret = TRUE;
363 else if (*domain == '*')
365 if (domain[1] == '.')
367 LPCWSTR dot;
369 /* For a hostname to match a wildcard, the last domain must match
370 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
371 * hostname is www.foo.a.b, it matches, but a.b does not.
373 dot = strchrW( server, '.' );
374 if (dot)
376 int len = strlenW( dot + 1 );
378 if (len > strlenW( domain + 2 ))
380 LPCWSTR ptr;
382 /* The server's domain is longer than the wildcard, so it
383 * could be a subdomain. Compare the last portion of the
384 * server's domain.
386 ptr = dot + len + 1 - strlenW( domain + 2 );
387 if (!strcmpiW( ptr, domain + 2 ))
389 /* This is only a match if the preceding character is
390 * a '.', i.e. that it is a matching domain. E.g.
391 * if domain is '*.b.c' and server is 'www.ab.c' they
392 * do not match.
394 ret = *(ptr - 1) == '.';
397 else
398 ret = !strcmpiW( dot + 1, domain + 2 );
402 else
403 ret = !strcmpiW( server, domain );
404 return ret;
407 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
408 #define MAX_HOST_NAME_LENGTH 256
410 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
412 LPCWSTR ptr;
413 BOOL ret = FALSE;
415 if (!session->proxy_bypass) return FALSE;
416 ptr = session->proxy_bypass;
417 do {
418 LPCWSTR tmp = ptr;
420 ptr = strchrW( ptr, ';' );
421 if (!ptr)
422 ptr = strchrW( tmp, ' ' );
423 if (ptr)
425 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
427 WCHAR domain[MAX_HOST_NAME_LENGTH];
429 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
430 domain[ptr - tmp] = 0;
431 ret = domain_matches( server, domain );
433 ptr += 1;
435 else if (*tmp)
436 ret = domain_matches( server, tmp );
437 } while (ptr && !ret);
438 return ret;
441 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
443 session_t *session = connect->session;
444 BOOL ret = TRUE;
446 if (session->proxy_server && !should_bypass_proxy(session, server))
448 LPCWSTR colon;
450 if ((colon = strchrW( session->proxy_server, ':' )))
452 if (!connect->servername || strncmpiW( connect->servername,
453 session->proxy_server, colon - session->proxy_server - 1 ))
455 heap_free( connect->servername );
456 connect->resolved = FALSE;
457 if (!(connect->servername = heap_alloc(
458 (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
460 ret = FALSE;
461 goto end;
463 memcpy( connect->servername, session->proxy_server,
464 (colon - session->proxy_server) * sizeof(WCHAR) );
465 connect->servername[colon - session->proxy_server] = 0;
466 if (*(colon + 1))
467 connect->serverport = atoiW( colon + 1 );
468 else
469 connect->serverport = INTERNET_DEFAULT_PORT;
472 else
474 if (!connect->servername || strcmpiW( connect->servername,
475 session->proxy_server ))
477 heap_free( connect->servername );
478 connect->resolved = FALSE;
479 if (!(connect->servername = strdupW( session->proxy_server )))
481 ret = FALSE;
482 goto end;
484 connect->serverport = INTERNET_DEFAULT_PORT;
488 else if (server)
490 heap_free( connect->servername );
491 connect->resolved = FALSE;
492 if (!(connect->servername = strdupW( server )))
494 ret = FALSE;
495 goto end;
497 connect->serverport = port;
499 end:
500 return ret;
503 /***********************************************************************
504 * WinHttpConnect (winhttp.@)
506 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
508 connect_t *connect;
509 session_t *session;
510 HINTERNET hconnect = NULL;
512 TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
514 if (!server)
516 set_last_error( ERROR_INVALID_PARAMETER );
517 return NULL;
519 if (!(session = (session_t *)grab_object( hsession )))
521 set_last_error( ERROR_INVALID_HANDLE );
522 return NULL;
524 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
526 release_object( &session->hdr );
527 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
528 return NULL;
530 if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
532 release_object( &session->hdr );
533 return NULL;
535 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
536 connect->hdr.vtbl = &connect_vtbl;
537 connect->hdr.refs = 1;
538 connect->hdr.flags = session->hdr.flags;
539 connect->hdr.callback = session->hdr.callback;
540 connect->hdr.notify_mask = session->hdr.notify_mask;
541 connect->hdr.context = session->hdr.context;
542 connect->hdr.redirect_policy = session->hdr.redirect_policy;
543 list_init( &connect->hdr.children );
545 addref_object( &session->hdr );
546 connect->session = session;
547 list_add_head( &session->hdr.children, &connect->hdr.entry );
549 if (!(connect->hostname = strdupW( server ))) goto end;
550 connect->hostport = port;
551 if (!set_server_for_hostname( connect, server, port )) goto end;
553 if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
554 connect->hdr.handle = hconnect;
556 send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
558 end:
559 release_object( &connect->hdr );
560 release_object( &session->hdr );
561 TRACE("returning %p\n", hconnect);
562 if (hconnect) set_last_error( ERROR_SUCCESS );
563 return hconnect;
566 /***********************************************************************
567 * request_destroy (internal)
569 static void request_destroy( object_header_t *hdr )
571 request_t *request = (request_t *)hdr;
572 unsigned int i, j;
574 TRACE("%p\n", request);
576 if (request->task_thread)
578 /* Signal to the task proc to quit. It will call
579 this again when it does. */
580 HANDLE thread = request->task_thread;
581 request->task_thread = 0;
582 SetEvent( request->task_cancel );
583 CloseHandle( thread );
584 return;
586 release_object( &request->connect->hdr );
588 destroy_authinfo( request->authinfo );
589 destroy_authinfo( request->proxy_authinfo );
591 heap_free( request->verb );
592 heap_free( request->path );
593 heap_free( request->version );
594 heap_free( request->raw_headers );
595 heap_free( request->status_text );
596 for (i = 0; i < request->num_headers; i++)
598 heap_free( request->headers[i].field );
599 heap_free( request->headers[i].value );
601 heap_free( request->headers );
602 for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
603 heap_free( request->accept_types );
604 for (i = 0; i < TARGET_MAX; i++)
606 for (j = 0; j < SCHEME_MAX; j++)
608 heap_free( request->creds[i][j].username );
609 heap_free( request->creds[i][j].password );
612 heap_free( request );
615 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
617 int len = 0;
618 if (str) len = strlenW( str );
619 if (buffer && *buflen > len)
621 if (str) memcpy( buffer, str, len * sizeof(WCHAR) );
622 buffer[len] = 0;
624 *buflen = len * sizeof(WCHAR);
627 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
629 WCHAR *ret;
630 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
632 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
633 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
634 CertNameToStrW( encoding, blob, format, ret, size );
636 return ret;
639 static BOOL convert_sockaddr( const struct sockaddr *addr, SOCKADDR_STORAGE *addr_storage )
641 #ifndef __MINGW32__
642 switch (addr->sa_family)
644 case AF_INET:
646 const struct sockaddr_in *addr_unix = (const struct sockaddr_in *)addr;
647 struct WS_sockaddr_in *addr_win = (struct WS_sockaddr_in *)addr_storage;
648 char *p;
650 addr_win->sin_family = WS_AF_INET;
651 addr_win->sin_port = addr_unix->sin_port;
652 memcpy( &addr_win->sin_addr, &addr_unix->sin_addr, 4 );
653 p = (char *)&addr_win->sin_addr + 4;
654 memset( p, 0, sizeof(*addr_storage) - (p - (char *)addr_win) );
655 return TRUE;
657 case AF_INET6:
659 const struct sockaddr_in6 *addr_unix = (const struct sockaddr_in6 *)addr;
660 struct WS_sockaddr_in6 *addr_win = (struct WS_sockaddr_in6 *)addr_storage;
662 addr_win->sin6_family = WS_AF_INET6;
663 addr_win->sin6_port = addr_unix->sin6_port;
664 addr_win->sin6_flowinfo = addr_unix->sin6_flowinfo;
665 memcpy( &addr_win->sin6_addr, &addr_unix->sin6_addr, 16 );
666 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
667 addr_win->sin6_scope_id = addr_unix->sin6_scope_id;
668 #else
669 addr_win->sin6_scope_id = 0;
670 #endif
671 memset( addr_win + 1, 0, sizeof(*addr_storage) - sizeof(*addr_win) );
672 return TRUE;
674 default:
675 ERR("unhandled family %u\n", addr->sa_family);
676 return FALSE;
678 #else
679 switch (addr->sa_family)
681 case AF_INET:
683 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr_storage;
685 memcpy( addr_in, addr, sizeof(*addr_in) );
686 memset( addr_in + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in) );
687 return TRUE;
689 case AF_INET6:
691 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr_storage;
693 memcpy( addr_in6, addr, sizeof(*addr_in6) );
694 memset( addr_in6 + 1, 0, sizeof(*addr_storage) - sizeof(*addr_in6) );
695 return TRUE;
697 default:
698 ERR("unhandled family %u\n", addr->sa_family);
699 return FALSE;
701 #endif
704 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
706 request_t *request = (request_t *)hdr;
708 switch (option)
710 case WINHTTP_OPTION_SECURITY_FLAGS:
712 DWORD flags = 0;
713 int bits;
715 if (!buffer || *buflen < sizeof(flags))
717 *buflen = sizeof(flags);
718 set_last_error( ERROR_INSUFFICIENT_BUFFER );
719 return FALSE;
722 flags = 0;
723 if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
724 flags |= request->security_flags;
725 if (request->netconn)
727 bits = netconn_get_cipher_strength( request->netconn );
728 if (bits >= 128)
729 flags |= SECURITY_FLAG_STRENGTH_STRONG;
730 else if (bits >= 56)
731 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
732 else
733 flags |= SECURITY_FLAG_STRENGTH_WEAK;
735 *(DWORD *)buffer = flags;
736 *buflen = sizeof(flags);
737 return TRUE;
739 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
741 const CERT_CONTEXT *cert;
743 if (!buffer || *buflen < sizeof(cert))
745 *buflen = sizeof(cert);
746 set_last_error( ERROR_INSUFFICIENT_BUFFER );
747 return FALSE;
750 if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
751 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
752 *buflen = sizeof(cert);
753 return TRUE;
755 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
757 const CERT_CONTEXT *cert;
758 const CRYPT_OID_INFO *oidInfo;
759 WINHTTP_CERTIFICATE_INFO *ci = buffer;
761 FIXME("partial stub\n");
763 if (!buffer || *buflen < sizeof(*ci))
765 *buflen = sizeof(*ci);
766 set_last_error( ERROR_INSUFFICIENT_BUFFER );
767 return FALSE;
769 if (!request->netconn || !(cert = netconn_get_certificate( request->netconn ))) return FALSE;
771 ci->ftExpiry = cert->pCertInfo->NotAfter;
772 ci->ftStart = cert->pCertInfo->NotBefore;
773 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
774 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
775 ci->lpszProtocolName = NULL;
776 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
777 cert->pCertInfo->SignatureAlgorithm.pszObjId,
778 0 );
779 if (oidInfo)
780 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
781 else
782 ci->lpszSignatureAlgName = NULL;
783 ci->lpszEncryptionAlgName = NULL;
784 ci->dwKeySize = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
786 CertFreeCertificateContext( cert );
787 *buflen = sizeof(*ci);
788 return TRUE;
790 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
792 if (!buffer || *buflen < sizeof(DWORD))
794 *buflen = sizeof(DWORD);
795 set_last_error( ERROR_INSUFFICIENT_BUFFER );
796 return FALSE;
799 *(DWORD *)buffer = request->netconn ? netconn_get_cipher_strength( request->netconn ) : 0;
800 *buflen = sizeof(DWORD);
801 return TRUE;
803 case WINHTTP_OPTION_CONNECTION_INFO:
805 WINHTTP_CONNECTION_INFO *info = buffer;
806 struct sockaddr local;
807 socklen_t len = sizeof(local);
808 const struct sockaddr *remote = (const struct sockaddr *)&request->connect->sockaddr;
810 if (!buffer || *buflen < sizeof(*info))
812 *buflen = sizeof(*info);
813 set_last_error( ERROR_INSUFFICIENT_BUFFER );
814 return FALSE;
816 if (!request->netconn)
818 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
819 return FALSE;
821 if (getsockname( request->netconn->socket, &local, &len )) return FALSE;
822 if (!convert_sockaddr( &local, &info->LocalAddress )) return FALSE;
823 if (!convert_sockaddr( remote, &info->RemoteAddress )) return FALSE;
824 info->cbSize = sizeof(*info);
825 return TRUE;
827 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
828 *(DWORD *)buffer = request->resolve_timeout;
829 *buflen = sizeof(DWORD);
830 return TRUE;
831 case WINHTTP_OPTION_CONNECT_TIMEOUT:
832 *(DWORD *)buffer = request->connect_timeout;
833 *buflen = sizeof(DWORD);
834 return TRUE;
835 case WINHTTP_OPTION_SEND_TIMEOUT:
836 *(DWORD *)buffer = request->send_timeout;
837 *buflen = sizeof(DWORD);
838 return TRUE;
839 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
840 *(DWORD *)buffer = request->recv_timeout;
841 *buflen = sizeof(DWORD);
842 return TRUE;
844 case WINHTTP_OPTION_USERNAME:
845 str_to_buffer( buffer, request->connect->username, buflen );
846 return TRUE;
848 case WINHTTP_OPTION_PASSWORD:
849 str_to_buffer( buffer, request->connect->password, buflen );
850 return TRUE;
852 case WINHTTP_OPTION_PROXY_USERNAME:
853 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
854 return TRUE;
856 case WINHTTP_OPTION_PROXY_PASSWORD:
857 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
858 return TRUE;
860 default:
861 FIXME("unimplemented option %u\n", option);
862 set_last_error( ERROR_INVALID_PARAMETER );
863 return FALSE;
867 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
869 WCHAR *ret;
870 if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
872 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
873 ret[buflen] = 0;
874 return ret;
876 set_last_error( ERROR_OUTOFMEMORY );
877 return NULL;
880 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
882 request_t *request = (request_t *)hdr;
884 switch (option)
886 case WINHTTP_OPTION_PROXY:
888 WINHTTP_PROXY_INFO *pi = buffer;
890 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
891 return TRUE;
893 case WINHTTP_OPTION_DISABLE_FEATURE:
895 DWORD disable;
897 if (buflen != sizeof(DWORD))
899 set_last_error( ERROR_INSUFFICIENT_BUFFER );
900 return FALSE;
903 disable = *(DWORD *)buffer;
904 TRACE("0x%x\n", disable);
905 hdr->disable_flags |= disable;
906 return TRUE;
908 case WINHTTP_OPTION_AUTOLOGON_POLICY:
910 DWORD policy;
912 if (buflen != sizeof(DWORD))
914 set_last_error( ERROR_INSUFFICIENT_BUFFER );
915 return FALSE;
918 policy = *(DWORD *)buffer;
919 TRACE("0x%x\n", policy);
920 hdr->logon_policy = policy;
921 return TRUE;
923 case WINHTTP_OPTION_REDIRECT_POLICY:
925 DWORD policy;
927 if (buflen != sizeof(DWORD))
929 set_last_error( ERROR_INSUFFICIENT_BUFFER );
930 return FALSE;
933 policy = *(DWORD *)buffer;
934 TRACE("0x%x\n", policy);
935 hdr->redirect_policy = policy;
936 return TRUE;
938 case WINHTTP_OPTION_SECURITY_FLAGS:
940 DWORD flags;
942 if (buflen < sizeof(DWORD))
944 set_last_error( ERROR_INSUFFICIENT_BUFFER );
945 return FALSE;
947 flags = *(DWORD *)buffer;
948 TRACE("0x%x\n", flags);
949 if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
950 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
951 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
952 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
954 set_last_error( ERROR_INVALID_PARAMETER );
955 return FALSE;
957 request->security_flags = flags;
958 return TRUE;
960 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
961 request->resolve_timeout = *(DWORD *)buffer;
962 return TRUE;
963 case WINHTTP_OPTION_CONNECT_TIMEOUT:
964 request->connect_timeout = *(DWORD *)buffer;
965 return TRUE;
966 case WINHTTP_OPTION_SEND_TIMEOUT:
967 request->send_timeout = *(DWORD *)buffer;
968 return TRUE;
969 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
970 request->recv_timeout = *(DWORD *)buffer;
971 return TRUE;
973 case WINHTTP_OPTION_USERNAME:
975 connect_t *connect = request->connect;
977 heap_free( connect->username );
978 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
979 return TRUE;
981 case WINHTTP_OPTION_PASSWORD:
983 connect_t *connect = request->connect;
985 heap_free( connect->password );
986 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
987 return TRUE;
989 case WINHTTP_OPTION_PROXY_USERNAME:
991 session_t *session = request->connect->session;
993 heap_free( session->proxy_username );
994 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
995 return TRUE;
997 case WINHTTP_OPTION_PROXY_PASSWORD:
999 session_t *session = request->connect->session;
1001 heap_free( session->proxy_password );
1002 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
1003 return TRUE;
1005 case WINHTTP_OPTION_CLIENT_CERT_CONTEXT:
1006 if (!(hdr->flags & WINHTTP_FLAG_SECURE))
1008 SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_STATE );
1009 return FALSE;
1011 FIXME("WINHTTP_OPTION_CLIENT_CERT_CONTEXT\n");
1012 return TRUE;
1013 default:
1014 FIXME("unimplemented option %u\n", option);
1015 set_last_error( ERROR_INVALID_PARAMETER );
1016 return TRUE;
1020 static const object_vtbl_t request_vtbl =
1022 request_destroy,
1023 request_query_option,
1024 request_set_option
1027 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
1029 const WCHAR **types = accept_types;
1030 DWORD i;
1032 if (!types) return TRUE;
1033 while (*types)
1035 request->num_accept_types++;
1036 types++;
1038 if (!request->num_accept_types) return TRUE;
1039 if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
1041 request->num_accept_types = 0;
1042 return FALSE;
1044 types = accept_types;
1045 for (i = 0; i < request->num_accept_types; i++)
1047 if (!(request->accept_types[i] = strdupW( *types )))
1049 for ( ; i > 0; --i) heap_free( request->accept_types[i - 1] );
1050 heap_free( request->accept_types );
1051 request->accept_types = NULL;
1052 request->num_accept_types = 0;
1053 return FALSE;
1055 types++;
1057 return TRUE;
1060 /***********************************************************************
1061 * WinHttpOpenRequest (winhttp.@)
1063 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
1064 LPCWSTR referrer, LPCWSTR *types, DWORD flags )
1066 request_t *request;
1067 connect_t *connect;
1068 HINTERNET hrequest = NULL;
1070 TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
1071 debugstr_w(version), debugstr_w(referrer), types, flags);
1073 if(types && TRACE_ON(winhttp)) {
1074 const WCHAR **iter;
1076 TRACE("accept types:\n");
1077 for(iter = types; *iter; iter++)
1078 TRACE(" %s\n", debugstr_w(*iter));
1081 if (!(connect = (connect_t *)grab_object( hconnect )))
1083 set_last_error( ERROR_INVALID_HANDLE );
1084 return NULL;
1086 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
1088 release_object( &connect->hdr );
1089 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1090 return NULL;
1092 if (!(request = heap_alloc_zero( sizeof(request_t) )))
1094 release_object( &connect->hdr );
1095 return NULL;
1097 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
1098 request->hdr.vtbl = &request_vtbl;
1099 request->hdr.refs = 1;
1100 request->hdr.flags = flags;
1101 request->hdr.callback = connect->hdr.callback;
1102 request->hdr.notify_mask = connect->hdr.notify_mask;
1103 request->hdr.context = connect->hdr.context;
1104 request->hdr.redirect_policy = connect->hdr.redirect_policy;
1105 list_init( &request->hdr.children );
1106 list_init( &request->task_queue );
1108 addref_object( &connect->hdr );
1109 request->connect = connect;
1110 list_add_head( &connect->hdr.children, &request->hdr.entry );
1112 request->resolve_timeout = connect->session->resolve_timeout;
1113 request->connect_timeout = connect->session->connect_timeout;
1114 request->send_timeout = connect->session->send_timeout;
1115 request->recv_timeout = connect->session->recv_timeout;
1117 if (!verb || !verb[0]) verb = getW;
1118 if (!(request->verb = strdupW( verb ))) goto end;
1120 if (object)
1122 WCHAR *path, *p;
1123 unsigned int len;
1125 len = strlenW( object ) + 1;
1126 if (object[0] != '/') len++;
1127 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
1129 if (object[0] != '/') *p++ = '/';
1130 strcpyW( p, object );
1131 request->path = path;
1133 else if (!(request->path = strdupW( slashW ))) goto end;
1135 if (!version || !version[0]) version = http1_1;
1136 if (!(request->version = strdupW( version ))) goto end;
1137 if (!(store_accept_types( request, types ))) goto end;
1139 if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
1140 request->hdr.handle = hrequest;
1142 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
1144 end:
1145 release_object( &request->hdr );
1146 release_object( &connect->hdr );
1147 TRACE("returning %p\n", hrequest);
1148 if (hrequest) set_last_error( ERROR_SUCCESS );
1149 return hrequest;
1152 /***********************************************************************
1153 * WinHttpCloseHandle (winhttp.@)
1155 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
1157 object_header_t *hdr;
1159 TRACE("%p\n", handle);
1161 if (!(hdr = grab_object( handle )))
1163 set_last_error( ERROR_INVALID_HANDLE );
1164 return FALSE;
1166 release_object( hdr );
1167 free_handle( handle );
1168 set_last_error( ERROR_SUCCESS );
1169 return TRUE;
1172 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1174 BOOL ret = FALSE;
1176 if (!buflen)
1178 set_last_error( ERROR_INVALID_PARAMETER );
1179 return FALSE;
1182 switch (option)
1184 case WINHTTP_OPTION_CONTEXT_VALUE:
1186 if (!buffer || *buflen < sizeof(DWORD_PTR))
1188 *buflen = sizeof(DWORD_PTR);
1189 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1190 return FALSE;
1193 *(DWORD_PTR *)buffer = hdr->context;
1194 *buflen = sizeof(DWORD_PTR);
1195 return TRUE;
1197 default:
1198 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1199 else
1201 FIXME("unimplemented option %u\n", option);
1202 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1203 return FALSE;
1205 break;
1207 return ret;
1210 /***********************************************************************
1211 * WinHttpQueryOption (winhttp.@)
1213 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1215 BOOL ret = FALSE;
1216 object_header_t *hdr;
1218 TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1220 if (!(hdr = grab_object( handle )))
1222 set_last_error( ERROR_INVALID_HANDLE );
1223 return FALSE;
1226 ret = query_option( hdr, option, buffer, buflen );
1228 release_object( hdr );
1229 if (ret) set_last_error( ERROR_SUCCESS );
1230 return ret;
1233 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1235 BOOL ret = TRUE;
1237 if (!buffer && buflen)
1239 set_last_error( ERROR_INVALID_PARAMETER );
1240 return FALSE;
1243 switch (option)
1245 case WINHTTP_OPTION_CONTEXT_VALUE:
1247 if (buflen != sizeof(DWORD_PTR))
1249 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1250 return FALSE;
1253 hdr->context = *(DWORD_PTR *)buffer;
1254 return TRUE;
1256 default:
1257 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1258 else
1260 FIXME("unimplemented option %u\n", option);
1261 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1262 return FALSE;
1264 break;
1266 return ret;
1269 /***********************************************************************
1270 * WinHttpSetOption (winhttp.@)
1272 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1274 BOOL ret = FALSE;
1275 object_header_t *hdr;
1277 TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1279 if (!(hdr = grab_object( handle )))
1281 set_last_error( ERROR_INVALID_HANDLE );
1282 return FALSE;
1285 ret = set_option( hdr, option, buffer, buflen );
1287 release_object( hdr );
1288 if (ret) set_last_error( ERROR_SUCCESS );
1289 return ret;
1292 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1294 char *ret;
1295 DWORD size = 0;
1297 GetComputerNameExA( format, NULL, &size );
1298 if (GetLastError() != ERROR_MORE_DATA) return NULL;
1299 if (!(ret = heap_alloc( size ))) return NULL;
1300 if (!GetComputerNameExA( format, ret, &size ))
1302 heap_free( ret );
1303 return NULL;
1305 return ret;
1308 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1310 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1312 if (len_suffix > len_domain) return FALSE;
1313 if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1314 return FALSE;
1317 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
1319 int ret = -1;
1320 #ifdef HAVE_GETNAMEINFO
1321 ret = getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
1322 #endif
1323 return ret;
1326 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
1328 static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1329 static const WCHAR wpadW[] = {'/','w','p','a','d','.','d','a','t',0};
1330 char name[NI_MAXHOST];
1331 WCHAR *ret, *p;
1332 int len;
1334 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
1335 if (!ai) return NULL;
1337 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
1339 len = strlenW( httpW ) + strlen( hostname ) + strlenW( wpadW );
1340 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1341 strcpyW( p, httpW );
1342 p += strlenW( httpW );
1343 while (*hostname) { *p++ = *hostname++; }
1344 strcpyW( p, wpadW );
1345 return ret;
1348 static BOOL get_system_proxy_autoconfig_url( char *buf, DWORD buflen )
1350 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1351 CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
1352 const void *ref;
1353 BOOL ret = FALSE;
1355 if (!settings) return FALSE;
1357 if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
1359 CFRelease( settings );
1360 return FALSE;
1362 if (CFStringGetCString( ref, buf, buflen, kCFStringEncodingASCII ))
1364 TRACE( "returning %s\n", debugstr_a(buf) );
1365 ret = TRUE;
1367 CFRelease( settings );
1368 return ret;
1369 #else
1370 static BOOL first = TRUE;
1371 if (first)
1373 FIXME( "no support on this platform\n" );
1374 first = FALSE;
1376 else
1377 TRACE( "no support on this platform\n" );
1378 return FALSE;
1379 #endif
1382 #define INTERNET_MAX_URL_LENGTH 2084
1384 /***********************************************************************
1385 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1387 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1389 BOOL ret = FALSE;
1390 char system_url[INTERNET_MAX_URL_LENGTH + 1];
1392 TRACE("0x%08x, %p\n", flags, url);
1394 if (!flags || !url)
1396 set_last_error( ERROR_INVALID_PARAMETER );
1397 return FALSE;
1399 if (get_system_proxy_autoconfig_url( system_url, sizeof(system_url) ))
1401 WCHAR *urlW;
1403 if (!(urlW = strdupAW( system_url ))) return FALSE;
1404 *url = urlW;
1405 set_last_error( ERROR_SUCCESS );
1406 return TRUE;
1408 if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP)
1410 static int fixme_shown;
1411 if (!fixme_shown++) FIXME("discovery via DHCP not supported\n");
1413 if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1415 #ifdef HAVE_GETADDRINFO
1416 char *fqdn, *domain, *p;
1418 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1419 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1421 heap_free( fqdn );
1422 return FALSE;
1424 p = fqdn;
1425 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1427 struct addrinfo *ai;
1428 char *name;
1429 int res;
1431 if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1433 heap_free( fqdn );
1434 heap_free( domain );
1435 return FALSE;
1437 strcpy( name, "wpad" );
1438 strcat( name, p );
1439 res = getaddrinfo( name, NULL, NULL, &ai );
1440 if (!res)
1442 *url = build_wpad_url( name, ai );
1443 freeaddrinfo( ai );
1444 if (*url)
1446 TRACE("returning %s\n", debugstr_w(*url));
1447 heap_free( name );
1448 ret = TRUE;
1449 break;
1452 heap_free( name );
1453 p++;
1455 heap_free( domain );
1456 heap_free( fqdn );
1457 #else
1458 FIXME("getaddrinfo not found at build time\n");
1459 #endif
1461 if (!ret)
1463 set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1464 *url = NULL;
1466 else set_last_error( ERROR_SUCCESS );
1467 return ret;
1470 static const WCHAR Connections[] = {
1471 'S','o','f','t','w','a','r','e','\\',
1472 'M','i','c','r','o','s','o','f','t','\\',
1473 'W','i','n','d','o','w','s','\\',
1474 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1475 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1476 'C','o','n','n','e','c','t','i','o','n','s',0 };
1477 static const WCHAR WinHttpSettings[] = {
1478 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1479 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1480 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1481 static const DWORD PROXY_TYPE_DIRECT = 1;
1482 static const DWORD PROXY_TYPE_PROXY = 2;
1483 static const DWORD PROXY_USE_PAC_SCRIPT = 4;
1484 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1486 struct connection_settings_header
1488 DWORD magic;
1489 DWORD unknown; /* always zero? */
1490 DWORD flags; /* one or more of PROXY_* */
1493 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1495 const BYTE *begin;
1497 for (begin = src; src - begin < len; src++, dst++)
1498 *dst = *src;
1499 *dst = 0;
1502 /***********************************************************************
1503 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1505 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1507 LONG l;
1508 HKEY key;
1509 BOOL got_from_reg = FALSE, direct = TRUE;
1510 char *envproxy;
1512 TRACE("%p\n", info);
1514 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1515 if (!l)
1517 DWORD type, size = 0;
1519 l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1520 if (!l && type == REG_BINARY &&
1521 size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1523 BYTE *buf = heap_alloc( size );
1525 if (buf)
1527 struct connection_settings_header *hdr =
1528 (struct connection_settings_header *)buf;
1529 DWORD *len = (DWORD *)(hdr + 1);
1531 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1532 &size );
1533 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1534 hdr->unknown == 0)
1536 if (hdr->flags & PROXY_TYPE_PROXY)
1538 BOOL sane = FALSE;
1539 LPWSTR proxy = NULL;
1540 LPWSTR proxy_bypass = NULL;
1542 /* Sanity-check length of proxy string */
1543 if ((BYTE *)len - buf + *len <= size)
1545 sane = TRUE;
1546 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1547 if (proxy)
1548 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1549 len = (DWORD *)((BYTE *)(len + 1) + *len);
1551 if (sane)
1553 /* Sanity-check length of proxy bypass string */
1554 if ((BYTE *)len - buf + *len <= size)
1556 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1557 if (proxy_bypass)
1558 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1560 else
1562 sane = FALSE;
1563 GlobalFree( proxy );
1564 proxy = NULL;
1567 info->lpszProxy = proxy;
1568 info->lpszProxyBypass = proxy_bypass;
1569 if (sane)
1571 got_from_reg = TRUE;
1572 direct = FALSE;
1573 info->dwAccessType =
1574 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1575 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1576 debugstr_w(info->lpszProxy),
1577 debugstr_w(info->lpszProxyBypass));
1581 heap_free( buf );
1584 RegCloseKey( key );
1586 if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1588 char *colon, *http_proxy;
1590 if ((colon = strchr( envproxy, ':' )))
1592 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1594 static const char http[] = "http://";
1596 /* It's a scheme, check that it's http */
1597 if (!strncmp( envproxy, http, strlen( http ) ))
1598 http_proxy = envproxy + strlen( http );
1599 else
1601 WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1602 http_proxy = NULL;
1605 else
1606 http_proxy = envproxy;
1608 else
1609 http_proxy = envproxy;
1610 if (http_proxy)
1612 WCHAR *http_proxyW;
1613 int len;
1615 len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1616 if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1618 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1619 direct = FALSE;
1620 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1621 info->lpszProxy = http_proxyW;
1622 info->lpszProxyBypass = NULL;
1623 TRACE("http proxy (from environment) = %s\n",
1624 debugstr_w(info->lpszProxy));
1628 if (direct)
1630 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1631 info->lpszProxy = NULL;
1632 info->lpszProxyBypass = NULL;
1634 set_last_error( ERROR_SUCCESS );
1635 return TRUE;
1638 /***********************************************************************
1639 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1641 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1643 static const WCHAR settingsW[] =
1644 {'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};
1645 HKEY hkey = NULL;
1646 struct connection_settings_header *hdr = NULL;
1647 DWORD type, offset, len, size = 0;
1648 BOOL ret = FALSE;
1650 TRACE("%p\n", config);
1652 if (!config)
1654 set_last_error( ERROR_INVALID_PARAMETER );
1655 return FALSE;
1657 memset( config, 0, sizeof(*config) );
1658 config->fAutoDetect = TRUE;
1660 if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1661 RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1662 type != REG_BINARY || size < sizeof(struct connection_settings_header))
1664 ret = TRUE;
1665 goto done;
1667 if (!(hdr = heap_alloc( size ))) goto done;
1668 if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1669 hdr->magic != WININET_SETTINGS_MAGIC)
1671 ret = TRUE;
1672 goto done;
1675 config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1676 offset = sizeof(*hdr);
1677 if (offset + sizeof(DWORD) > size) goto done;
1678 len = *(DWORD *)((char *)hdr + offset);
1679 offset += sizeof(DWORD);
1680 if (len && hdr->flags & PROXY_TYPE_PROXY)
1682 if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1683 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1685 offset += len;
1686 if (offset + sizeof(DWORD) > size) goto done;
1687 len = *(DWORD *)((char *)hdr + offset);
1688 offset += sizeof(DWORD);
1689 if (len && (hdr->flags & PROXY_TYPE_PROXY))
1691 if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1692 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1694 offset += len;
1695 if (offset + sizeof(DWORD) > size) goto done;
1696 len = *(DWORD *)((char *)hdr + offset);
1697 offset += sizeof(DWORD);
1698 if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1700 if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1701 copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1703 ret = TRUE;
1705 done:
1706 RegCloseKey( hkey );
1707 heap_free( hdr );
1708 if (!ret)
1710 GlobalFree( config->lpszAutoConfigUrl );
1711 config->lpszAutoConfigUrl = NULL;
1712 GlobalFree( config->lpszProxy );
1713 config->lpszProxy = NULL;
1714 GlobalFree( config->lpszProxyBypass );
1715 config->lpszProxyBypass = NULL;
1717 else set_last_error( ERROR_SUCCESS );
1718 return ret;
1721 static BOOL parse_script_result( const char *result, WINHTTP_PROXY_INFO *info )
1723 const char *p;
1724 WCHAR *q;
1725 int len;
1727 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1728 info->lpszProxy = NULL;
1729 info->lpszProxyBypass = NULL;
1731 TRACE("%s\n", debugstr_a( result ));
1733 p = result;
1734 while (*p == ' ') p++;
1735 len = strlen( p );
1736 if (len >= 5 && !strncasecmp( p, "PROXY", sizeof("PROXY") - 1 ))
1738 p += 5;
1739 while (*p == ' ') p++;
1740 if (!*p || *p == ';') return TRUE;
1741 if (!(info->lpszProxy = q = strdupAW( p ))) return FALSE;
1742 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1743 for (; *q; q++)
1745 if (*q == ' ' || *q == ';')
1747 *q = 0;
1748 break;
1752 return TRUE;
1755 static char *download_script( const WCHAR *url, DWORD *out_size )
1757 static const WCHAR typeW[] = {'*','/','*',0};
1758 static const WCHAR *acceptW[] = {typeW, NULL};
1759 HINTERNET ses, con = NULL, req = NULL;
1760 WCHAR *hostname;
1761 URL_COMPONENTSW uc;
1762 DWORD status, size = sizeof(status), offset, to_read, bytes_read, flags = 0;
1763 char *tmp, *buffer = NULL;
1765 *out_size = 0;
1767 memset( &uc, 0, sizeof(uc) );
1768 uc.dwStructSize = sizeof(uc);
1769 uc.dwHostNameLength = -1;
1770 uc.dwUrlPathLength = -1;
1771 if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1772 if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1773 memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1774 hostname[uc.dwHostNameLength] = 0;
1776 if (!(ses = WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0 ))) goto done;
1777 if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1778 if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1779 if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1780 if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1782 if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1783 if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
1784 &size, NULL ) || status != HTTP_STATUS_OK) goto done;
1786 size = 4096;
1787 if (!(buffer = heap_alloc( size ))) goto done;
1788 to_read = size;
1789 offset = 0;
1790 for (;;)
1792 if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1793 if (!bytes_read) break;
1794 to_read -= bytes_read;
1795 offset += bytes_read;
1796 *out_size += bytes_read;
1797 if (!to_read)
1799 to_read = size;
1800 size *= 2;
1801 if (!(tmp = heap_realloc( buffer, size ))) goto done;
1802 buffer = tmp;
1806 done:
1807 WinHttpCloseHandle( req );
1808 WinHttpCloseHandle( con );
1809 WinHttpCloseHandle( ses );
1810 heap_free( hostname );
1811 if (!buffer) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1812 return buffer;
1815 struct AUTO_PROXY_SCRIPT_BUFFER
1817 DWORD dwStructSize;
1818 LPSTR lpszScriptBuffer;
1819 DWORD dwScriptBufferSize;
1822 BOOL WINAPI InternetDeInitializeAutoProxyDll(LPSTR, DWORD);
1823 BOOL WINAPI InternetGetProxyInfo(LPCSTR, DWORD, LPSTR, DWORD, LPSTR *, LPDWORD);
1824 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD, LPSTR, LPSTR, void *, struct AUTO_PROXY_SCRIPT_BUFFER *);
1826 static BOOL run_script( char *script, DWORD size, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1828 BOOL ret;
1829 char *result, *urlA;
1830 DWORD len_result;
1831 struct AUTO_PROXY_SCRIPT_BUFFER buffer;
1832 URL_COMPONENTSW uc;
1834 buffer.dwStructSize = sizeof(buffer);
1835 buffer.lpszScriptBuffer = script;
1836 buffer.dwScriptBufferSize = size;
1838 if (!(urlA = strdupWA( url ))) return FALSE;
1839 if (!(ret = InternetInitializeAutoProxyDll( 0, NULL, NULL, NULL, &buffer )))
1841 heap_free( urlA );
1842 return FALSE;
1845 memset( &uc, 0, sizeof(uc) );
1846 uc.dwStructSize = sizeof(uc);
1847 uc.dwHostNameLength = -1;
1849 if (WinHttpCrackUrl( url, 0, 0, &uc ))
1851 char *hostnameA = strdupWA_sized( uc.lpszHostName, uc.dwHostNameLength );
1853 if ((ret = InternetGetProxyInfo( urlA, strlen(urlA),
1854 hostnameA, strlen(hostnameA), &result, &len_result )))
1856 ret = parse_script_result( result, info );
1857 heap_free( result );
1860 heap_free( hostnameA );
1862 heap_free( urlA );
1863 return InternetDeInitializeAutoProxyDll( NULL, 0 );
1866 /***********************************************************************
1867 * WinHttpGetProxyForUrl (winhttp.@)
1869 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1870 WINHTTP_PROXY_INFO *info )
1872 WCHAR *detected_pac_url = NULL;
1873 const WCHAR *pac_url;
1874 session_t *session;
1875 char *script;
1876 DWORD size;
1877 BOOL ret = FALSE;
1879 TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1881 if (!(session = (session_t *)grab_object( hsession )))
1883 set_last_error( ERROR_INVALID_HANDLE );
1884 return FALSE;
1886 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1888 release_object( &session->hdr );
1889 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1890 return FALSE;
1892 if (!url || !options || !info ||
1893 !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1894 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1895 ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1896 (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1898 release_object( &session->hdr );
1899 set_last_error( ERROR_INVALID_PARAMETER );
1900 return FALSE;
1902 if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1903 !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1904 goto done;
1906 if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1907 else pac_url = detected_pac_url;
1909 if ((script = download_script( pac_url, &size )))
1911 ret = run_script( script, size, url, info );
1912 heap_free( script );
1915 done:
1916 GlobalFree( detected_pac_url );
1917 release_object( &session->hdr );
1918 if (ret) set_last_error( ERROR_SUCCESS );
1919 return ret;
1922 /***********************************************************************
1923 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
1925 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1927 LONG l;
1928 HKEY key;
1929 BOOL ret = FALSE;
1930 const WCHAR *src;
1932 TRACE("%p\n", info);
1934 if (!info)
1936 set_last_error( ERROR_INVALID_PARAMETER );
1937 return FALSE;
1939 switch (info->dwAccessType)
1941 case WINHTTP_ACCESS_TYPE_NO_PROXY:
1942 break;
1943 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1944 if (!info->lpszProxy)
1946 set_last_error( ERROR_INVALID_PARAMETER );
1947 return FALSE;
1949 /* Only ASCII characters are allowed */
1950 for (src = info->lpszProxy; *src; src++)
1951 if (*src > 0x7f)
1953 set_last_error( ERROR_INVALID_PARAMETER );
1954 return FALSE;
1956 if (info->lpszProxyBypass)
1958 for (src = info->lpszProxyBypass; *src; src++)
1959 if (*src > 0x7f)
1961 set_last_error( ERROR_INVALID_PARAMETER );
1962 return FALSE;
1965 break;
1966 default:
1967 set_last_error( ERROR_INVALID_PARAMETER );
1968 return FALSE;
1971 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1972 KEY_WRITE, NULL, &key, NULL );
1973 if (!l)
1975 DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1976 BYTE *buf;
1978 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1980 size += strlenW( info->lpszProxy );
1981 if (info->lpszProxyBypass)
1982 size += strlenW( info->lpszProxyBypass );
1984 buf = heap_alloc( size );
1985 if (buf)
1987 struct connection_settings_header *hdr =
1988 (struct connection_settings_header *)buf;
1989 DWORD *len = (DWORD *)(hdr + 1);
1991 hdr->magic = WINHTTP_SETTINGS_MAGIC;
1992 hdr->unknown = 0;
1993 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1995 BYTE *dst;
1997 hdr->flags = PROXY_TYPE_PROXY;
1998 *len++ = strlenW( info->lpszProxy );
1999 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
2000 src++, dst++)
2001 *dst = *src;
2002 len = (DWORD *)dst;
2003 if (info->lpszProxyBypass)
2005 *len++ = strlenW( info->lpszProxyBypass );
2006 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
2007 src++, dst++)
2008 *dst = *src;
2010 else
2011 *len++ = 0;
2013 else
2015 hdr->flags = PROXY_TYPE_DIRECT;
2016 *len++ = 0;
2017 *len++ = 0;
2019 l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
2020 if (!l)
2021 ret = TRUE;
2022 heap_free( buf );
2024 RegCloseKey( key );
2026 if (ret) set_last_error( ERROR_SUCCESS );
2027 return ret;
2030 /***********************************************************************
2031 * WinHttpSetStatusCallback (winhttp.@)
2033 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
2034 DWORD flags, DWORD_PTR reserved )
2036 object_header_t *hdr;
2037 WINHTTP_STATUS_CALLBACK ret;
2039 TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
2041 if (!(hdr = grab_object( handle )))
2043 set_last_error( ERROR_INVALID_HANDLE );
2044 return WINHTTP_INVALID_STATUS_CALLBACK;
2046 ret = hdr->callback;
2047 hdr->callback = callback;
2048 hdr->notify_mask = flags;
2050 release_object( hdr );
2051 set_last_error( ERROR_SUCCESS );
2052 return ret;
2055 /***********************************************************************
2056 * WinHttpSetTimeouts (winhttp.@)
2058 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
2060 BOOL ret = TRUE;
2061 object_header_t *hdr;
2062 request_t *request;
2063 session_t *session;
2065 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
2067 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
2069 set_last_error( ERROR_INVALID_PARAMETER );
2070 return FALSE;
2073 if (!(hdr = grab_object( handle )))
2075 set_last_error( ERROR_INVALID_HANDLE );
2076 return FALSE;
2079 switch(hdr->type)
2081 case WINHTTP_HANDLE_TYPE_REQUEST:
2082 request = (request_t *)hdr;
2083 request->connect_timeout = connect;
2085 if (resolve < 0) resolve = 0;
2086 request->resolve_timeout = resolve;
2088 if (send < 0) send = 0;
2089 request->send_timeout = send;
2091 if (receive < 0) receive = 0;
2092 request->recv_timeout = receive;
2094 if (request->netconn)
2096 if (netconn_set_timeout( request->netconn, TRUE, send )) ret = FALSE;
2097 if (netconn_set_timeout( request->netconn, FALSE, receive )) ret = FALSE;
2099 break;
2101 case WINHTTP_HANDLE_TYPE_SESSION:
2102 session = (session_t *)hdr;
2103 session->connect_timeout = connect;
2105 if (resolve < 0) resolve = 0;
2106 session->resolve_timeout = resolve;
2108 if (send < 0) send = 0;
2109 session->send_timeout = send;
2111 if (receive < 0) receive = 0;
2112 session->recv_timeout = receive;
2113 break;
2115 default:
2116 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
2117 ret = FALSE;
2119 release_object( hdr );
2120 if (ret) set_last_error( ERROR_SUCCESS );
2121 return ret;
2124 static const WCHAR wkday[7][4] =
2125 {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2126 {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2127 static const WCHAR month[12][4] =
2128 {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2129 {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2130 {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2132 /***********************************************************************
2133 * WinHttpTimeFromSystemTime (WININET.@)
2135 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2137 static const WCHAR format[] =
2138 {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2139 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2141 TRACE("%p, %p\n", time, string);
2143 if (!time || !string)
2145 set_last_error( ERROR_INVALID_PARAMETER );
2146 return FALSE;
2149 sprintfW( string, format,
2150 wkday[time->wDayOfWeek],
2151 time->wDay,
2152 month[time->wMonth - 1],
2153 time->wYear,
2154 time->wHour,
2155 time->wMinute,
2156 time->wSecond );
2158 set_last_error( ERROR_SUCCESS );
2159 return TRUE;
2162 /***********************************************************************
2163 * WinHttpTimeToSystemTime (WININET.@)
2165 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2167 unsigned int i;
2168 const WCHAR *s = string;
2169 WCHAR *end;
2171 TRACE("%s, %p\n", debugstr_w(string), time);
2173 if (!string || !time)
2175 set_last_error( ERROR_INVALID_PARAMETER );
2176 return FALSE;
2179 /* Windows does this too */
2180 GetSystemTime( time );
2182 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2183 * a SYSTEMTIME structure.
2186 set_last_error( ERROR_SUCCESS );
2188 while (*s && !isalphaW( *s )) s++;
2189 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2190 time->wDayOfWeek = 7;
2192 for (i = 0; i < 7; i++)
2194 if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2195 toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2196 toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2198 time->wDayOfWeek = i;
2199 break;
2203 if (time->wDayOfWeek > 6) return TRUE;
2204 while (*s && !isdigitW( *s )) s++;
2205 time->wDay = strtolW( s, &end, 10 );
2206 s = end;
2208 while (*s && !isalphaW( *s )) s++;
2209 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2210 time->wMonth = 0;
2212 for (i = 0; i < 12; i++)
2214 if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2215 toupperW( month[i][1]) == toupperW( s[1] ) &&
2216 toupperW( month[i][2]) == toupperW( s[2] ) )
2218 time->wMonth = i + 1;
2219 break;
2222 if (time->wMonth == 0) return TRUE;
2224 while (*s && !isdigitW( *s )) s++;
2225 if (*s == '\0') return TRUE;
2226 time->wYear = strtolW( s, &end, 10 );
2227 s = end;
2229 while (*s && !isdigitW( *s )) s++;
2230 if (*s == '\0') return TRUE;
2231 time->wHour = strtolW( s, &end, 10 );
2232 s = end;
2234 while (*s && !isdigitW( *s )) s++;
2235 if (*s == '\0') return TRUE;
2236 time->wMinute = strtolW( s, &end, 10 );
2237 s = end;
2239 while (*s && !isdigitW( *s )) s++;
2240 if (*s == '\0') return TRUE;
2241 time->wSecond = strtolW( s, &end, 10 );
2243 time->wMilliseconds = 0;
2244 return TRUE;