winhttp: Reverse the order of arguments passed to Invoke.
[wine] / dlls / winhttp / session.c
1 /*
2  * Copyright 2008 Hans Leidekker for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winhttp.h"
29 #include "wincrypt.h"
30 #include "winreg.h"
31 #define COBJMACROS
32 #include "ole2.h"
33 #include "activscp.h"
34
35 #include "winhttp_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
38
39 #define DEFAULT_RESOLVE_TIMEOUT     0
40 #define DEFAULT_CONNECT_TIMEOUT     20000
41 #define DEFAULT_SEND_TIMEOUT        30000
42 #define DEFAULT_RECEIVE_TIMEOUT     30000
43
44 void set_last_error( DWORD error )
45 {
46     /* FIXME */
47     SetLastError( error );
48 }
49
50 DWORD get_last_error( void )
51 {
52     /* FIXME */
53     return GetLastError();
54 }
55
56 void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
57 {
58     TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
59
60     if (hdr->callback && (hdr->notify_mask & status)) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
61 }
62
63 /***********************************************************************
64  *          WinHttpCheckPlatform (winhttp.@)
65  */
66 BOOL WINAPI WinHttpCheckPlatform( void )
67 {
68     TRACE("\n");
69     return TRUE;
70 }
71
72 /***********************************************************************
73  *          session_destroy (internal)
74  */
75 static void session_destroy( object_header_t *hdr )
76 {
77     session_t *session = (session_t *)hdr;
78     struct list *item, *next;
79     domain_t *domain;
80
81     TRACE("%p\n", session);
82
83     LIST_FOR_EACH_SAFE( item, next, &session->cookie_cache )
84     {
85         domain = LIST_ENTRY( item, domain_t, entry );
86         delete_domain( domain );
87     }
88     heap_free( session->agent );
89     heap_free( session->proxy_server );
90     heap_free( session->proxy_bypass );
91     heap_free( session->proxy_username );
92     heap_free( session->proxy_password );
93     heap_free( session );
94 }
95
96 static BOOL session_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
97 {
98     session_t *session = (session_t *)hdr;
99
100     switch (option)
101     {
102     case WINHTTP_OPTION_REDIRECT_POLICY:
103     {
104         if (!buffer || *buflen < sizeof(DWORD))
105         {
106             *buflen = sizeof(DWORD);
107             set_last_error( ERROR_INSUFFICIENT_BUFFER );
108             return FALSE;
109         }
110
111         *(DWORD *)buffer = hdr->redirect_policy;
112         *buflen = sizeof(DWORD);
113         return TRUE;
114     }
115     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
116         *(DWORD *)buffer = session->resolve_timeout;
117         *buflen = sizeof(DWORD);
118         return TRUE;
119     case WINHTTP_OPTION_CONNECT_TIMEOUT:
120         *(DWORD *)buffer = session->connect_timeout;
121         *buflen = sizeof(DWORD);
122         return TRUE;
123     case WINHTTP_OPTION_SEND_TIMEOUT:
124         *(DWORD *)buffer = session->send_timeout;
125         *buflen = sizeof(DWORD);
126         return TRUE;
127     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
128         *(DWORD *)buffer = session->recv_timeout;
129         *buflen = sizeof(DWORD);
130         return TRUE;
131     default:
132         FIXME("unimplemented option %u\n", option);
133         set_last_error( ERROR_INVALID_PARAMETER );
134         return FALSE;
135     }
136 }
137
138 static BOOL session_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
139 {
140     session_t *session = (session_t *)hdr;
141
142     switch (option)
143     {
144     case WINHTTP_OPTION_PROXY:
145     {
146         WINHTTP_PROXY_INFO *pi = buffer;
147
148         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
149         return TRUE;
150     }
151     case WINHTTP_OPTION_REDIRECT_POLICY:
152     {
153         DWORD policy;
154
155         if (buflen != sizeof(policy))
156         {
157             set_last_error( ERROR_INSUFFICIENT_BUFFER );
158             return FALSE;
159         }
160
161         policy = *(DWORD *)buffer;
162         TRACE("0x%x\n", policy);
163         hdr->redirect_policy = policy;
164         return TRUE;
165     }
166     case WINHTTP_OPTION_DISABLE_FEATURE:
167         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
168         return FALSE;
169     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
170         session->resolve_timeout = *(DWORD *)buffer;
171         return TRUE;
172     case WINHTTP_OPTION_CONNECT_TIMEOUT:
173         session->connect_timeout = *(DWORD *)buffer;
174         return TRUE;
175     case WINHTTP_OPTION_SEND_TIMEOUT:
176         session->send_timeout = *(DWORD *)buffer;
177         return TRUE;
178     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
179         session->recv_timeout = *(DWORD *)buffer;
180         return TRUE;
181     default:
182         FIXME("unimplemented option %u\n", option);
183         set_last_error( ERROR_INVALID_PARAMETER );
184         return FALSE;
185     }
186 }
187
188 static const object_vtbl_t session_vtbl =
189 {
190     session_destroy,
191     session_query_option,
192     session_set_option
193 };
194
195 /***********************************************************************
196  *          WinHttpOpen (winhttp.@)
197  */
198 HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWSTR bypass, DWORD flags )
199 {
200     session_t *session;
201     HINTERNET handle = NULL;
202
203     TRACE("%s, %u, %s, %s, 0x%08x\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags);
204
205     if (!(session = heap_alloc_zero( sizeof(session_t) ))) return NULL;
206
207     session->hdr.type = WINHTTP_HANDLE_TYPE_SESSION;
208     session->hdr.vtbl = &session_vtbl;
209     session->hdr.flags = flags;
210     session->hdr.refs = 1;
211     session->hdr.redirect_policy = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
212     list_init( &session->hdr.children );
213     session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
214     session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
215     session->send_timeout = DEFAULT_SEND_TIMEOUT;
216     session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
217     list_init( &session->cookie_cache );
218
219     if (agent && !(session->agent = strdupW( agent ))) goto end;
220     if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
221     {
222         WINHTTP_PROXY_INFO info;
223
224         WinHttpGetDefaultProxyConfiguration( &info );
225         session->access = info.dwAccessType;
226         if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
227         {
228             GlobalFree( (LPWSTR)info.lpszProxy );
229             GlobalFree( (LPWSTR)info.lpszProxyBypass );
230             goto end;
231         }
232         if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
233         {
234             GlobalFree( (LPWSTR)info.lpszProxy );
235             GlobalFree( (LPWSTR)info.lpszProxyBypass );
236             goto end;
237         }
238     }
239     else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
240     {
241         session->access = access;
242         if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
243         if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
244     }
245
246     if (!(handle = alloc_handle( &session->hdr ))) goto end;
247     session->hdr.handle = handle;
248
249 end:
250     release_object( &session->hdr );
251     TRACE("returning %p\n", handle);
252     return handle;
253 }
254
255 /***********************************************************************
256  *          connect_destroy (internal)
257  */
258 static void connect_destroy( object_header_t *hdr )
259 {
260     connect_t *connect = (connect_t *)hdr;
261
262     TRACE("%p\n", connect);
263
264     release_object( &connect->session->hdr );
265
266     heap_free( connect->hostname );
267     heap_free( connect->servername );
268     heap_free( connect->username );
269     heap_free( connect->password );
270     heap_free( connect );
271 }
272
273 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
274 {
275     connect_t *connect = (connect_t *)hdr;
276
277     switch (option)
278     {
279     case WINHTTP_OPTION_PARENT_HANDLE:
280     {
281         if (!buffer || *buflen < sizeof(HINTERNET))
282         {
283             *buflen = sizeof(HINTERNET);
284             set_last_error( ERROR_INSUFFICIENT_BUFFER );
285             return FALSE;
286         }
287
288         *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
289         *buflen = sizeof(HINTERNET);
290         return TRUE;
291     }
292     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
293         *(DWORD *)buffer = connect->session->resolve_timeout;
294         *buflen = sizeof(DWORD);
295         return TRUE;
296     case WINHTTP_OPTION_CONNECT_TIMEOUT:
297         *(DWORD *)buffer = connect->session->connect_timeout;
298         *buflen = sizeof(DWORD);
299         return TRUE;
300     case WINHTTP_OPTION_SEND_TIMEOUT:
301         *(DWORD *)buffer = connect->session->send_timeout;
302         *buflen = sizeof(DWORD);
303         return TRUE;
304     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
305         *(DWORD *)buffer = connect->session->recv_timeout;
306         *buflen = sizeof(DWORD);
307         return TRUE;
308     default:
309         FIXME("unimplemented option %u\n", option);
310         set_last_error( ERROR_INVALID_PARAMETER );
311         return FALSE;
312     }
313 }
314
315 static const object_vtbl_t connect_vtbl =
316 {
317     connect_destroy,
318     connect_query_option,
319     NULL
320 };
321
322 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
323 {
324     static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
325     BOOL ret = FALSE;
326
327     if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
328         ret = TRUE;
329     else if (*domain == '*')
330     {
331         if (domain[1] == '.')
332         {
333             LPCWSTR dot;
334
335             /* For a hostname to match a wildcard, the last domain must match
336              * the wildcard exactly.  E.g. if the wildcard is *.a.b, and the
337              * hostname is www.foo.a.b, it matches, but a.b does not.
338              */
339             dot = strchrW( server, '.' );
340             if (dot)
341             {
342                 int len = strlenW( dot + 1 );
343
344                 if (len > strlenW( domain + 2 ))
345                 {
346                     LPCWSTR ptr;
347
348                     /* The server's domain is longer than the wildcard, so it
349                      * could be a subdomain.  Compare the last portion of the
350                      * server's domain.
351                      */
352                     ptr = dot + len + 1 - strlenW( domain + 2 );
353                     if (!strcmpiW( ptr, domain + 2 ))
354                     {
355                         /* This is only a match if the preceding character is
356                          * a '.', i.e. that it is a matching domain.  E.g.
357                          * if domain is '*.b.c' and server is 'www.ab.c' they
358                          * do not match.
359                          */
360                         ret = *(ptr - 1) == '.';
361                     }
362                 }
363                 else
364                     ret = !strcmpiW( dot + 1, domain + 2 );
365             }
366         }
367     }
368     else
369         ret = !strcmpiW( server, domain );
370     return ret;
371 }
372
373 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
374 #define MAX_HOST_NAME_LENGTH 256
375
376 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
377 {
378     LPCWSTR ptr;
379     BOOL ret = FALSE;
380
381     if (!session->proxy_bypass) return FALSE;
382     ptr = session->proxy_bypass;
383     do {
384         LPCWSTR tmp = ptr;
385
386         ptr = strchrW( ptr, ';' );
387         if (!ptr)
388             ptr = strchrW( tmp, ' ' );
389         if (ptr)
390         {
391             if (ptr - tmp < MAX_HOST_NAME_LENGTH)
392             {
393                 WCHAR domain[MAX_HOST_NAME_LENGTH];
394
395                 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
396                 domain[ptr - tmp] = 0;
397                 ret = domain_matches( server, domain );
398             }
399             ptr += 1;
400         }
401         else if (*tmp)
402             ret = domain_matches( server, tmp );
403     } while (ptr && !ret);
404     return ret;
405 }
406
407 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
408 {
409     session_t *session = connect->session;
410     BOOL ret = TRUE;
411
412     if (session->proxy_server && !should_bypass_proxy(session, server))
413     {
414         LPCWSTR colon;
415
416         if ((colon = strchrW( session->proxy_server, ':' )))
417         {
418             if (!connect->servername || strncmpiW( connect->servername,
419                 session->proxy_server, colon - session->proxy_server - 1 ))
420             {
421                 heap_free( connect->servername );
422                 if (!(connect->servername = heap_alloc(
423                     (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
424                 {
425                     ret = FALSE;
426                     goto end;
427                 }
428                 memcpy( connect->servername, session->proxy_server,
429                     (colon - session->proxy_server) * sizeof(WCHAR) );
430                 connect->servername[colon - session->proxy_server] = 0;
431                 if (*(colon + 1))
432                     connect->serverport = atoiW( colon + 1 );
433                 else
434                     connect->serverport = INTERNET_DEFAULT_PORT;
435             }
436         }
437         else
438         {
439             if (!connect->servername || strcmpiW( connect->servername,
440                 session->proxy_server ))
441             {
442                 heap_free( connect->servername );
443                 if (!(connect->servername = strdupW( session->proxy_server )))
444                 {
445                     ret = FALSE;
446                     goto end;
447                 }
448                 connect->serverport = INTERNET_DEFAULT_PORT;
449             }
450         }
451     }
452     else if (server)
453     {
454         heap_free( connect->servername );
455         if (!(connect->servername = strdupW( server )))
456         {
457             ret = FALSE;
458             goto end;
459         }
460         connect->serverport = port;
461     }
462 end:
463     return ret;
464 }
465
466 /***********************************************************************
467  *          WinHttpConnect (winhttp.@)
468  */
469 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
470 {
471     connect_t *connect;
472     session_t *session;
473     HINTERNET hconnect = NULL;
474
475     TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
476
477     if (!server)
478     {
479         set_last_error( ERROR_INVALID_PARAMETER );
480         return NULL;
481     }
482     if (!(session = (session_t *)grab_object( hsession )))
483     {
484         set_last_error( ERROR_INVALID_HANDLE );
485         return NULL;
486     }
487     if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
488     {
489         release_object( &session->hdr );
490         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
491         return NULL;
492     }
493     if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
494     {
495         release_object( &session->hdr );
496         return NULL;
497     }
498     connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
499     connect->hdr.vtbl = &connect_vtbl;
500     connect->hdr.refs = 1;
501     connect->hdr.flags = session->hdr.flags;
502     connect->hdr.callback = session->hdr.callback;
503     connect->hdr.notify_mask = session->hdr.notify_mask;
504     connect->hdr.context = session->hdr.context;
505     list_init( &connect->hdr.children );
506
507     addref_object( &session->hdr );
508     connect->session = session;
509     list_add_head( &session->hdr.children, &connect->hdr.entry );
510
511     if (!(connect->hostname = strdupW( server ))) goto end;
512     connect->hostport = port;
513     if (!set_server_for_hostname( connect, server, port )) goto end;
514
515     if (!(hconnect = alloc_handle( &connect->hdr ))) goto end;
516     connect->hdr.handle = hconnect;
517
518     send_callback( &session->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hconnect, sizeof(hconnect) );
519
520 end:
521     release_object( &connect->hdr );
522     release_object( &session->hdr );
523     TRACE("returning %p\n", hconnect);
524     return hconnect;
525 }
526
527 /***********************************************************************
528  *          request_destroy (internal)
529  */
530 static void request_destroy( object_header_t *hdr )
531 {
532     request_t *request = (request_t *)hdr;
533     unsigned int i;
534
535     TRACE("%p\n", request);
536
537     release_object( &request->connect->hdr );
538
539     heap_free( request->verb );
540     heap_free( request->path );
541     heap_free( request->version );
542     heap_free( request->raw_headers );
543     heap_free( request->status_text );
544     for (i = 0; i < request->num_headers; i++)
545     {
546         heap_free( request->headers[i].field );
547         heap_free( request->headers[i].value );
548     }
549     heap_free( request->headers );
550     for (i = 0; i < request->num_accept_types; i++) heap_free( request->accept_types[i] );
551     heap_free( request->accept_types );
552     heap_free( request );
553 }
554
555 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
556 {
557     int len = 0;
558     if (str) len = strlenW( str );
559     if (buffer && *buflen > len)
560     {
561         memcpy( buffer, str, len * sizeof(WCHAR) );
562         buffer[len] = 0;
563     }
564     *buflen = len * sizeof(WCHAR);
565 }
566
567 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
568 {
569     WCHAR *ret;
570     DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
571
572     size = CertNameToStrW( encoding, blob, format, NULL, 0 );
573     if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
574         CertNameToStrW( encoding, blob, format, ret, size );
575
576     return ret;
577 }
578
579 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
580 {
581     request_t *request = (request_t *)hdr;
582
583     switch (option)
584     {
585     case WINHTTP_OPTION_SECURITY_FLAGS:
586     {
587         DWORD flags;
588         int bits;
589
590         if (!buffer || *buflen < sizeof(flags))
591         {
592             *buflen = sizeof(flags);
593             set_last_error( ERROR_INSUFFICIENT_BUFFER );
594             return FALSE;
595         }
596
597         flags = 0;
598         if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
599         flags |= request->netconn.security_flags;
600         bits = netconn_get_cipher_strength( &request->netconn );
601         if (bits >= 128)
602             flags |= SECURITY_FLAG_STRENGTH_STRONG;
603         else if (bits >= 56)
604             flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
605         else
606             flags |= SECURITY_FLAG_STRENGTH_WEAK;
607         *(DWORD *)buffer = flags;
608         *buflen = sizeof(flags);
609         return TRUE;
610     }
611     case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
612     {
613         const CERT_CONTEXT *cert;
614
615         if (!buffer || *buflen < sizeof(cert))
616         {
617             *buflen = sizeof(cert);
618             set_last_error( ERROR_INSUFFICIENT_BUFFER );
619             return FALSE;
620         }
621
622         if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
623         *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
624         *buflen = sizeof(cert);
625         return TRUE;
626     }
627     case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
628     {
629         const CERT_CONTEXT *cert;
630         const CRYPT_OID_INFO *oidInfo;
631         WINHTTP_CERTIFICATE_INFO *ci = buffer;
632
633         FIXME("partial stub\n");
634
635         if (!buffer || *buflen < sizeof(*ci))
636         {
637             *buflen = sizeof(*ci);
638             set_last_error( ERROR_INSUFFICIENT_BUFFER );
639             return FALSE;
640         }
641         if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
642
643         ci->ftExpiry = cert->pCertInfo->NotAfter;
644         ci->ftStart  = cert->pCertInfo->NotBefore;
645         ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
646         ci->lpszIssuerInfo  = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
647         ci->lpszProtocolName      = NULL;
648         oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
649                                     cert->pCertInfo->SignatureAlgorithm.pszObjId,
650                                     0 );
651         if (oidInfo)
652             ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
653         else
654             ci->lpszSignatureAlgName  = NULL;
655         ci->lpszEncryptionAlgName = NULL;
656         ci->dwKeySize = netconn_get_cipher_strength( &request->netconn );
657
658         CertFreeCertificateContext( cert );
659         *buflen = sizeof(*ci);
660         return TRUE;
661     }
662     case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
663     {
664         if (!buffer || *buflen < sizeof(DWORD))
665         {
666             *buflen = sizeof(DWORD);
667             set_last_error( ERROR_INSUFFICIENT_BUFFER );
668             return FALSE;
669         }
670
671         *(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn );
672         *buflen = sizeof(DWORD);
673         return TRUE;
674     }
675     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
676         *(DWORD *)buffer = request->resolve_timeout;
677         *buflen = sizeof(DWORD);
678         return TRUE;
679     case WINHTTP_OPTION_CONNECT_TIMEOUT:
680         *(DWORD *)buffer = request->connect_timeout;
681         *buflen = sizeof(DWORD);
682         return TRUE;
683     case WINHTTP_OPTION_SEND_TIMEOUT:
684         *(DWORD *)buffer = request->send_timeout;
685         *buflen = sizeof(DWORD);
686         return TRUE;
687     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
688         *(DWORD *)buffer = request->recv_timeout;
689         *buflen = sizeof(DWORD);
690         return TRUE;
691
692     case WINHTTP_OPTION_USERNAME:
693         str_to_buffer( buffer, request->connect->username, buflen );
694         return TRUE;
695
696     case WINHTTP_OPTION_PASSWORD:
697         str_to_buffer( buffer, request->connect->password, buflen );
698         return TRUE;
699
700     case WINHTTP_OPTION_PROXY_USERNAME:
701         str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
702         return TRUE;
703
704     case WINHTTP_OPTION_PROXY_PASSWORD:
705         str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
706         return TRUE;
707
708     default:
709         FIXME("unimplemented option %u\n", option);
710         set_last_error( ERROR_INVALID_PARAMETER );
711         return FALSE;
712     }
713 }
714
715 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
716 {
717     WCHAR *ret;
718     if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
719     {
720         memcpy( ret, buffer, buflen * sizeof(WCHAR) );
721         ret[buflen] = 0;
722         return ret;
723     }
724     set_last_error( ERROR_OUTOFMEMORY );
725     return NULL;
726 }
727
728 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
729 {
730     request_t *request = (request_t *)hdr;
731
732     switch (option)
733     {
734     case WINHTTP_OPTION_PROXY:
735     {
736         WINHTTP_PROXY_INFO *pi = buffer;
737
738         FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
739         return TRUE;
740     }
741     case WINHTTP_OPTION_DISABLE_FEATURE:
742     {
743         DWORD disable;
744
745         if (buflen != sizeof(DWORD))
746         {
747             set_last_error( ERROR_INSUFFICIENT_BUFFER );
748             return FALSE;
749         }
750
751         disable = *(DWORD *)buffer;
752         TRACE("0x%x\n", disable);
753         hdr->disable_flags |= disable;
754         return TRUE;
755     }
756     case WINHTTP_OPTION_AUTOLOGON_POLICY:
757     {
758         DWORD policy;
759
760         if (buflen != sizeof(DWORD))
761         {
762             set_last_error( ERROR_INSUFFICIENT_BUFFER );
763             return FALSE;
764         }
765
766         policy = *(DWORD *)buffer;
767         TRACE("0x%x\n", policy);
768         hdr->logon_policy = policy;
769         return TRUE;
770     }
771     case WINHTTP_OPTION_REDIRECT_POLICY:
772     {
773         DWORD policy;
774
775         if (buflen != sizeof(DWORD))
776         {
777             set_last_error( ERROR_INSUFFICIENT_BUFFER );
778             return FALSE;
779         }
780
781         policy = *(DWORD *)buffer;
782         TRACE("0x%x\n", policy);
783         hdr->redirect_policy = policy;
784         return TRUE;
785     }
786     case WINHTTP_OPTION_SECURITY_FLAGS:
787     {
788         DWORD flags;
789
790         if (buflen < sizeof(DWORD))
791         {
792             set_last_error( ERROR_INSUFFICIENT_BUFFER );
793             return FALSE;
794         }
795         flags = *(DWORD *)buffer;
796         TRACE("0x%x\n", flags);
797         if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID   |
798                        SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
799                        SECURITY_FLAG_IGNORE_UNKNOWN_CA        |
800                        SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
801         {
802             set_last_error( ERROR_INVALID_PARAMETER );
803             return FALSE;
804         }
805         request->netconn.security_flags = flags;
806         return TRUE;
807     }
808     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
809         request->resolve_timeout = *(DWORD *)buffer;
810         return TRUE;
811     case WINHTTP_OPTION_CONNECT_TIMEOUT:
812         request->connect_timeout = *(DWORD *)buffer;
813         return TRUE;
814     case WINHTTP_OPTION_SEND_TIMEOUT:
815         request->send_timeout = *(DWORD *)buffer;
816         return TRUE;
817     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
818         request->recv_timeout = *(DWORD *)buffer;
819         return TRUE;
820
821     case WINHTTP_OPTION_USERNAME:
822     {
823         connect_t *connect = request->connect;
824
825         heap_free( connect->username );
826         if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
827         return TRUE;
828     }
829     case WINHTTP_OPTION_PASSWORD:
830     {
831         connect_t *connect = request->connect;
832
833         heap_free( connect->password );
834         if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
835         return TRUE;
836     }
837     case WINHTTP_OPTION_PROXY_USERNAME:
838     {
839         session_t *session = request->connect->session;
840
841         heap_free( session->proxy_username );
842         if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
843         return TRUE;
844     }
845     case WINHTTP_OPTION_PROXY_PASSWORD:
846     {
847         session_t *session = request->connect->session;
848
849         heap_free( session->proxy_password );
850         if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
851         return TRUE;
852     }
853     default:
854         FIXME("unimplemented option %u\n", option);
855         set_last_error( ERROR_INVALID_PARAMETER );
856         return TRUE;
857     }
858 }
859
860 static const object_vtbl_t request_vtbl =
861 {
862     request_destroy,
863     request_query_option,
864     request_set_option
865 };
866
867 static BOOL store_accept_types( request_t *request, const WCHAR **accept_types )
868 {
869     const WCHAR **types = accept_types;
870     int i;
871
872     if (!types) return TRUE;
873     while (*types)
874     {
875         request->num_accept_types++;
876         types++;
877     }
878     if (!request->num_accept_types) return TRUE;
879     if (!(request->accept_types = heap_alloc( request->num_accept_types * sizeof(WCHAR *))))
880     {
881         request->num_accept_types = 0;
882         return FALSE;
883     }
884     types = accept_types;
885     for (i = 0; i < request->num_accept_types; i++)
886     {
887         if (!(request->accept_types[i] = strdupW( *types )))
888         {
889             for (; i >= 0; i--) heap_free( request->accept_types[i] );
890             heap_free( request->accept_types );
891             request->accept_types = NULL;
892             request->num_accept_types = 0;
893             return FALSE;
894         }
895         types++;
896     }
897     return TRUE;
898 }
899
900 /***********************************************************************
901  *          WinHttpOpenRequest (winhttp.@)
902  */
903 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
904                                      LPCWSTR referrer, LPCWSTR *types, DWORD flags )
905 {
906     request_t *request;
907     connect_t *connect;
908     HINTERNET hrequest = NULL;
909
910     TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
911           debugstr_w(version), debugstr_w(referrer), types, flags);
912
913     if (!(connect = (connect_t *)grab_object( hconnect )))
914     {
915         set_last_error( ERROR_INVALID_HANDLE );
916         return NULL;
917     }
918     if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
919     {
920         release_object( &connect->hdr );
921         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
922         return NULL;
923     }
924     if (!(request = heap_alloc_zero( sizeof(request_t) )))
925     {
926         release_object( &connect->hdr );
927         return NULL;
928     }
929     request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
930     request->hdr.vtbl = &request_vtbl;
931     request->hdr.refs = 1;
932     request->hdr.flags = flags;
933     request->hdr.callback = connect->hdr.callback;
934     request->hdr.notify_mask = connect->hdr.notify_mask;
935     request->hdr.context = connect->hdr.context;
936     list_init( &request->hdr.children );
937
938     addref_object( &connect->hdr );
939     request->connect = connect;
940     list_add_head( &connect->hdr.children, &request->hdr.entry );
941
942     if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
943     request->resolve_timeout = connect->session->resolve_timeout;
944     request->connect_timeout = connect->session->connect_timeout;
945     request->send_timeout = connect->session->send_timeout;
946     request->recv_timeout = connect->session->recv_timeout;
947
948     if (!verb || !verb[0]) verb = getW;
949     if (!(request->verb = strdupW( verb ))) goto end;
950
951     if (object)
952     {
953         WCHAR *path, *p;
954         unsigned int len;
955
956         len = strlenW( object ) + 1;
957         if (object[0] != '/') len++;
958         if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
959
960         if (object[0] != '/') *p++ = '/';
961         strcpyW( p, object );
962         request->path = path;
963     }
964     else if (!(request->path = strdupW( slashW ))) goto end;
965
966     if (!version || !version[0]) version = http1_1;
967     if (!(request->version = strdupW( version ))) goto end;
968     if (!(store_accept_types( request, types ))) goto end;
969
970     if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
971     request->hdr.handle = hrequest;
972
973     send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
974
975 end:
976     release_object( &request->hdr );
977     release_object( &connect->hdr );
978     TRACE("returning %p\n", hrequest);
979     return hrequest;
980 }
981
982 /***********************************************************************
983  *          WinHttpCloseHandle (winhttp.@)
984  */
985 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
986 {
987     object_header_t *hdr;
988
989     TRACE("%p\n", handle);
990
991     if (!(hdr = grab_object( handle )))
992     {
993         set_last_error( ERROR_INVALID_HANDLE );
994         return FALSE;
995     }
996     release_object( hdr );
997     free_handle( handle );
998     return TRUE;
999 }
1000
1001 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
1002 {
1003     BOOL ret = FALSE;
1004
1005     if (!buflen)
1006     {
1007         set_last_error( ERROR_INVALID_PARAMETER );
1008         return FALSE;
1009     }
1010
1011     switch (option)
1012     {
1013     case WINHTTP_OPTION_CONTEXT_VALUE:
1014     {
1015         if (!buffer || *buflen < sizeof(DWORD_PTR))
1016         {
1017             *buflen = sizeof(DWORD_PTR);
1018             set_last_error( ERROR_INSUFFICIENT_BUFFER );
1019             return FALSE;
1020         }
1021
1022         *(DWORD_PTR *)buffer = hdr->context;
1023         *buflen = sizeof(DWORD_PTR);
1024         return TRUE;
1025     }
1026     default:
1027         if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
1028         else
1029         {
1030             FIXME("unimplemented option %u\n", option);
1031             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1032             return FALSE;
1033         }
1034         break;
1035     }
1036     return ret;
1037 }
1038
1039 /***********************************************************************
1040  *          WinHttpQueryOption (winhttp.@)
1041  */
1042 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1043 {
1044     BOOL ret = FALSE;
1045     object_header_t *hdr;
1046
1047     TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1048
1049     if (!(hdr = grab_object( handle )))
1050     {
1051         set_last_error( ERROR_INVALID_HANDLE );
1052         return FALSE;
1053     }
1054
1055     ret = query_option( hdr, option, buffer, buflen );
1056
1057     release_object( hdr );
1058     return ret;
1059 }
1060
1061 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1062 {
1063     BOOL ret = TRUE;
1064
1065     if (!buffer)
1066     {
1067         set_last_error( ERROR_INVALID_PARAMETER );
1068         return FALSE;
1069     }
1070
1071     switch (option)
1072     {
1073     case WINHTTP_OPTION_CONTEXT_VALUE:
1074     {
1075         if (buflen != sizeof(DWORD_PTR))
1076         {
1077             set_last_error( ERROR_INSUFFICIENT_BUFFER );
1078             return FALSE;
1079         }
1080
1081         hdr->context = *(DWORD_PTR *)buffer;
1082         return TRUE;
1083     }
1084     default:
1085         if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1086         else
1087         {
1088             FIXME("unimplemented option %u\n", option);
1089             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1090             return FALSE;
1091         }
1092         break;
1093     }
1094     return ret;
1095 }
1096
1097 /***********************************************************************
1098  *          WinHttpSetOption (winhttp.@)
1099  */
1100 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1101 {
1102     BOOL ret = FALSE;
1103     object_header_t *hdr;
1104
1105     TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1106
1107     if (!(hdr = grab_object( handle )))
1108     {
1109         set_last_error( ERROR_INVALID_HANDLE );
1110         return FALSE;
1111     }
1112
1113     ret = set_option( hdr, option, buffer, buflen );
1114
1115     release_object( hdr );
1116     return ret;
1117 }
1118
1119 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
1120 {
1121     char *ret;
1122     DWORD size = 0;
1123
1124     GetComputerNameExA( format, NULL, &size );
1125     if (GetLastError() != ERROR_MORE_DATA) return NULL;
1126     if (!(ret = heap_alloc( size ))) return NULL;
1127     if (!GetComputerNameExA( format, ret, &size ))
1128     {
1129         heap_free( ret );
1130         return NULL;
1131     }
1132     return ret;
1133 }
1134
1135 static BOOL is_domain_suffix( const char *domain, const char *suffix )
1136 {
1137     int len_domain = strlen( domain ), len_suffix = strlen( suffix );
1138
1139     if (len_suffix > len_domain) return FALSE;
1140     if (!strcasecmp( domain + len_domain - len_suffix, suffix )) return TRUE;
1141     return FALSE;
1142 }
1143
1144 static WCHAR *build_wpad_url( const struct addrinfo *ai )
1145 {
1146     static const WCHAR fmtW[] =
1147         {'h','t','t','p',':','/','/','%','u','.','%','u','.','%','u','.','%','u',
1148          '/','w','p','a','d','.','d','a','t',0};
1149     struct sockaddr_in *addr;
1150     WCHAR *ret;
1151
1152     while (ai && ai->ai_family != AF_INET) ai = ai->ai_next;
1153     if (!ai) return NULL;
1154
1155     if (!(ret = GlobalAlloc( 0, sizeof(fmtW) + 12 * sizeof(WCHAR) ))) return NULL;
1156     addr = (struct sockaddr_in *)ai->ai_addr;
1157     sprintfW( ret, fmtW,
1158               (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 24 & 0xff),
1159               (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 16 & 0xff),
1160               (unsigned int)(ntohl( addr->sin_addr.s_addr ) >> 8 & 0xff),
1161               (unsigned int)(ntohl( addr->sin_addr.s_addr ) & 0xff) );
1162     return ret;
1163 }
1164
1165 /***********************************************************************
1166  *          WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1167  */
1168 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1169 {
1170     BOOL ret = FALSE;
1171
1172     TRACE("0x%08x, %p\n", flags, url);
1173
1174     if (!flags || !url)
1175     {
1176         set_last_error( ERROR_INVALID_PARAMETER );
1177         return FALSE;
1178     }
1179     if (flags & WINHTTP_AUTO_DETECT_TYPE_DHCP) FIXME("discovery via DHCP not supported\n");
1180     if (flags & WINHTTP_AUTO_DETECT_TYPE_DNS_A)
1181     {
1182 #ifdef HAVE_GETADDRINFO
1183         char *fqdn, *domain, *p;
1184
1185         if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return FALSE;
1186         if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
1187         {
1188             heap_free( fqdn );
1189             return FALSE;
1190         }
1191         p = fqdn;
1192         while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
1193         {
1194             struct addrinfo *ai;
1195             char *name;
1196             int res;
1197
1198             if (!(name = heap_alloc( sizeof("wpad") + strlen(p) )))
1199             {
1200                 heap_free( fqdn );
1201                 heap_free( domain );
1202                 return FALSE;
1203             }
1204             strcpy( name, "wpad" );
1205             strcat( name, p );
1206             res = getaddrinfo( name, NULL, NULL, &ai );
1207             heap_free( name );
1208             if (!res)
1209             {
1210                 *url = build_wpad_url( ai );
1211                 freeaddrinfo( ai );
1212                 if (*url)
1213                 {
1214                     TRACE("returning %s\n", debugstr_w(*url));
1215                     ret = TRUE;
1216                     break;
1217                 }
1218             }
1219             p++;
1220         }
1221         heap_free( domain );
1222         heap_free( fqdn );
1223 #else
1224     FIXME("getaddrinfo not found at build time\n");
1225 #endif
1226     }
1227     if (!ret) set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1228     return ret;
1229 }
1230
1231 static const WCHAR Connections[] = {
1232     'S','o','f','t','w','a','r','e','\\',
1233     'M','i','c','r','o','s','o','f','t','\\',
1234     'W','i','n','d','o','w','s','\\',
1235     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1236     'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1237     'C','o','n','n','e','c','t','i','o','n','s',0 };
1238 static const WCHAR WinHttpSettings[] = {
1239     'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1240 static const DWORD WINHTTP_SETTINGS_MAGIC = 0x18;
1241 static const DWORD WININET_SETTINGS_MAGIC = 0x46;
1242 static const DWORD PROXY_TYPE_DIRECT         = 1;
1243 static const DWORD PROXY_TYPE_PROXY          = 2;
1244 static const DWORD PROXY_USE_PAC_SCRIPT      = 4;
1245 static const DWORD PROXY_AUTODETECT_SETTINGS = 8;
1246
1247 struct connection_settings_header
1248 {
1249     DWORD magic;
1250     DWORD unknown; /* always zero? */
1251     DWORD flags;   /* one or more of PROXY_* */
1252 };
1253
1254 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1255 {
1256     const BYTE *begin;
1257
1258     for (begin = src; src - begin < len; src++, dst++)
1259         *dst = *src;
1260     *dst = 0;
1261 }
1262
1263 /***********************************************************************
1264  *          WinHttpGetDefaultProxyConfiguration (winhttp.@)
1265  */
1266 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1267 {
1268     LONG l;
1269     HKEY key;
1270     BOOL got_from_reg = FALSE, direct = TRUE;
1271     char *envproxy;
1272
1273     TRACE("%p\n", info);
1274
1275     l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1276     if (!l)
1277     {
1278         DWORD type, size = 0;
1279
1280         l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1281         if (!l && type == REG_BINARY &&
1282             size >= sizeof(struct connection_settings_header) + 2 * sizeof(DWORD))
1283         {
1284             BYTE *buf = heap_alloc( size );
1285
1286             if (buf)
1287             {
1288                 struct connection_settings_header *hdr =
1289                     (struct connection_settings_header *)buf;
1290                 DWORD *len = (DWORD *)(hdr + 1);
1291
1292                 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1293                     &size );
1294                 if (!l && hdr->magic == WINHTTP_SETTINGS_MAGIC &&
1295                     hdr->unknown == 0)
1296                 {
1297                     if (hdr->flags & PROXY_TYPE_PROXY)
1298                     {
1299                        BOOL sane = FALSE;
1300                        LPWSTR proxy = NULL;
1301                        LPWSTR proxy_bypass = NULL;
1302
1303                         /* Sanity-check length of proxy string */
1304                         if ((BYTE *)len - buf + *len <= size)
1305                         {
1306                             sane = TRUE;
1307                             proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1308                             if (proxy)
1309                                 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1310                             len = (DWORD *)((BYTE *)(len + 1) + *len);
1311                         }
1312                         if (sane)
1313                         {
1314                             /* Sanity-check length of proxy bypass string */
1315                             if ((BYTE *)len - buf + *len <= size)
1316                             {
1317                                 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1318                                 if (proxy_bypass)
1319                                     copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1320                             }
1321                             else
1322                             {
1323                                 sane = FALSE;
1324                                 GlobalFree( proxy );
1325                                 proxy = NULL;
1326                             }
1327                         }
1328                         info->lpszProxy = proxy;
1329                         info->lpszProxyBypass = proxy_bypass;
1330                         if (sane)
1331                         {
1332                             got_from_reg = TRUE;
1333                             direct = FALSE;
1334                             info->dwAccessType =
1335                                 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1336                             TRACE("http proxy (from registry) = %s, bypass = %s\n",
1337                                 debugstr_w(info->lpszProxy),
1338                                 debugstr_w(info->lpszProxyBypass));
1339                         }
1340                     }
1341                 }
1342                 heap_free( buf );
1343             }
1344         }
1345         RegCloseKey( key );
1346     }
1347     if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1348     {
1349         char *colon, *http_proxy;
1350
1351         if ((colon = strchr( envproxy, ':' )))
1352         {
1353             if (*(colon + 1) == '/' && *(colon + 2) == '/')
1354             {
1355                 static const char http[] = "http://";
1356
1357                 /* It's a scheme, check that it's http */
1358                 if (!strncmp( envproxy, http, strlen( http ) ))
1359                     http_proxy = envproxy + strlen( http );
1360                 else
1361                 {
1362                     WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1363                     http_proxy = NULL;
1364                 }
1365             }
1366             else
1367                 http_proxy = envproxy;
1368         }
1369         else
1370             http_proxy = envproxy;
1371         if (http_proxy)
1372         {
1373             WCHAR *http_proxyW;
1374             int len;
1375
1376             len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1377             if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1378             {
1379                 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1380                 direct = FALSE;
1381                 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1382                 info->lpszProxy = http_proxyW;
1383                 info->lpszProxyBypass = NULL;
1384                 TRACE("http proxy (from environment) = %s\n",
1385                     debugstr_w(info->lpszProxy));
1386             }
1387         }
1388     }
1389     if (direct)
1390     {
1391         info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
1392         info->lpszProxy       = NULL;
1393         info->lpszProxyBypass = NULL;
1394     }
1395     return TRUE;
1396 }
1397
1398 /***********************************************************************
1399  *          WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1400  */
1401 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1402 {
1403     static const WCHAR settingsW[] =
1404         {'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};
1405     HKEY hkey = NULL;
1406     struct connection_settings_header *hdr = NULL;
1407     DWORD type, offset, len, size = 0;
1408     BOOL ret = FALSE;
1409
1410     TRACE("%p\n", config);
1411
1412     if (!config)
1413     {
1414         set_last_error( ERROR_INVALID_PARAMETER );
1415         return FALSE;
1416     }
1417     memset( config, 0, sizeof(*config) );
1418     config->fAutoDetect = TRUE;
1419
1420     if (RegOpenKeyExW( HKEY_CURRENT_USER, Connections, 0, KEY_READ, &hkey ) ||
1421         RegQueryValueExW( hkey, settingsW, NULL, &type, NULL, &size ) ||
1422         type != REG_BINARY || size < sizeof(struct connection_settings_header))
1423     {
1424         ret = TRUE;
1425         goto done;
1426     }
1427     if (!(hdr = heap_alloc( size ))) goto done;
1428     if (RegQueryValueExW( hkey, settingsW, NULL, &type, (BYTE *)hdr, &size ) ||
1429         hdr->magic != WININET_SETTINGS_MAGIC)
1430     {
1431         ret = TRUE;
1432         goto done;
1433     }
1434
1435     config->fAutoDetect = (hdr->flags & PROXY_AUTODETECT_SETTINGS) != 0;
1436     offset = sizeof(*hdr);
1437     if (offset + sizeof(DWORD) > size) goto done;
1438     len = *(DWORD *)((char *)hdr + offset);
1439     offset += sizeof(DWORD);
1440     if (len && hdr->flags & PROXY_TYPE_PROXY)
1441     {
1442         if (!(config->lpszProxy = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1443         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxy );
1444     }
1445     offset += len;
1446     if (offset + sizeof(DWORD) > size) goto done;
1447     len = *(DWORD *)((char *)hdr + offset);
1448     offset += sizeof(DWORD);
1449     if (len && (hdr->flags & PROXY_TYPE_PROXY))
1450     {
1451         if (!(config->lpszProxyBypass = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1452         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszProxyBypass );
1453     }
1454     offset += len;
1455     if (offset + sizeof(DWORD) > size) goto done;
1456     len = *(DWORD *)((char *)hdr + offset);
1457     offset += sizeof(DWORD);
1458     if (len && (hdr->flags & PROXY_USE_PAC_SCRIPT))
1459     {
1460         if (!(config->lpszAutoConfigUrl = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) goto done;
1461         copy_char_to_wchar_sz( (const BYTE *)hdr + offset , len, config->lpszAutoConfigUrl );
1462     }
1463     ret = TRUE;
1464
1465 done:
1466     RegCloseKey( hkey );
1467     heap_free( hdr );
1468     if (!ret)
1469     {
1470         heap_free( config->lpszAutoConfigUrl );
1471         config->lpszAutoConfigUrl = NULL;
1472         heap_free( config->lpszProxy );
1473         config->lpszProxy = NULL;
1474         heap_free( config->lpszProxyBypass );
1475         config->lpszProxyBypass = NULL;
1476     }
1477     return ret;
1478 }
1479
1480 static HRESULT WINAPI site_QueryInterface(
1481     IActiveScriptSite *iface, REFIID riid, void **ppv )
1482 {
1483     *ppv = NULL;
1484
1485     if (IsEqualGUID( &IID_IUnknown, riid ))
1486         *ppv = iface;
1487     else if (IsEqualGUID( &IID_IActiveScriptSite, riid ))
1488         *ppv = iface;
1489     else
1490         return E_NOINTERFACE;
1491
1492     IUnknown_AddRef( (IUnknown *)*ppv );
1493     return S_OK;
1494 }
1495
1496 static ULONG WINAPI site_AddRef(
1497     IActiveScriptSite *iface )
1498 {
1499     return 2;
1500 }
1501
1502 static ULONG WINAPI site_Release(
1503     IActiveScriptSite *iface )
1504 {
1505     return 1;
1506 }
1507
1508 static HRESULT WINAPI site_GetLCID(
1509     IActiveScriptSite *iface, LCID *lcid )
1510 {
1511     return E_NOTIMPL;
1512 }
1513
1514 static HRESULT WINAPI site_GetItemInfo(
1515     IActiveScriptSite *iface, LPCOLESTR name, DWORD mask,
1516     IUnknown **item, ITypeInfo **type_info )
1517 {
1518     return E_NOTIMPL;
1519 }
1520
1521 static HRESULT WINAPI site_GetDocVersionString(
1522     IActiveScriptSite *iface, BSTR *version )
1523 {
1524     return E_NOTIMPL;
1525 }
1526
1527 static HRESULT WINAPI site_OnScriptTerminate(
1528     IActiveScriptSite *iface, const VARIANT *result, const EXCEPINFO *info )
1529 {
1530     return E_NOTIMPL;
1531 }
1532
1533 static HRESULT WINAPI site_OnStateChange(
1534     IActiveScriptSite *iface, SCRIPTSTATE state )
1535 {
1536     return E_NOTIMPL;
1537 }
1538
1539 static HRESULT WINAPI site_OnScriptError(
1540     IActiveScriptSite *iface, IActiveScriptError *error )
1541 {
1542     return E_NOTIMPL;
1543 }
1544
1545 static HRESULT WINAPI site_OnEnterScript(
1546     IActiveScriptSite *iface )
1547 {
1548     return E_NOTIMPL;
1549 }
1550
1551 static HRESULT WINAPI site_OnLeaveScript(
1552     IActiveScriptSite *iface )
1553 {
1554     return E_NOTIMPL;
1555 }
1556
1557 static const IActiveScriptSiteVtbl site_vtbl =
1558 {
1559     site_QueryInterface,
1560     site_AddRef,
1561     site_Release,
1562     site_GetLCID,
1563     site_GetItemInfo,
1564     site_GetDocVersionString,
1565     site_OnScriptTerminate,
1566     site_OnStateChange,
1567     site_OnScriptError,
1568     site_OnEnterScript,
1569     site_OnLeaveScript
1570 };
1571
1572 static IActiveScriptSite script_site = { &site_vtbl };
1573
1574 static BOOL parse_script_result( VARIANT result, WINHTTP_PROXY_INFO *info )
1575 {
1576     static const WCHAR proxyW[] = {'P','R','O','X','Y'};
1577     const WCHAR *p;
1578     WCHAR *q;
1579     int len;
1580
1581     info->dwAccessType    = WINHTTP_ACCESS_TYPE_NO_PROXY;
1582     info->lpszProxy       = NULL;
1583     info->lpszProxyBypass = NULL;
1584
1585     if (V_VT( &result ) != VT_BSTR) return TRUE;
1586     TRACE("%s\n", debugstr_w( V_BSTR( &result ) ));
1587
1588     p = V_BSTR( &result );
1589     while (*p == ' ') p++;
1590     len = strlenW( p );
1591     if (len >= 5 && !memicmpW( p, proxyW, sizeof(proxyW)/sizeof(WCHAR) ))
1592     {
1593         p += 5;
1594         while (*p == ' ') p++;
1595         if (!*p || *p == ';') return TRUE;
1596         if (!(info->lpszProxy = q = strdupW( p ))) return FALSE;
1597         info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1598         for (; *q; q++)
1599         {
1600             if (*q == ' ' || *q == ';')
1601             {
1602                 *q = 0;
1603                 break;
1604             }
1605         }
1606     }
1607     return TRUE;
1608 }
1609
1610 static BOOL run_script( const BSTR script, const WCHAR *url, WINHTTP_PROXY_INFO *info )
1611 {
1612     static const WCHAR jscriptW[] = {'J','S','c','r','i','p','t',0};
1613     static const WCHAR findproxyW[] = {'F','i','n','d','P','r','o','x','y','F','o','r','U','R','L',0};
1614     IActiveScriptParse *parser = NULL;
1615     IActiveScript *engine = NULL;
1616     IDispatch *dispatch = NULL;
1617     BOOL ret = FALSE;
1618     CLSID clsid;
1619     DISPID dispid;
1620     BSTR func = NULL, hostname = NULL;
1621     URL_COMPONENTSW uc;
1622     VARIANT args[2], result;
1623     DISPPARAMS params;
1624     HRESULT hr, init;
1625
1626     memset( &uc, 0, sizeof(uc) );
1627     uc.dwStructSize = sizeof(uc);
1628     if (!WinHttpCrackUrl( url, 0, 0, &uc )) return FALSE;
1629     if (!(hostname = SysAllocStringLen( NULL, uc.dwHostNameLength + 1 ))) return FALSE;
1630     memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1631     hostname[uc.dwHostNameLength] = 0;
1632
1633     init = CoInitialize( NULL );
1634     CLSIDFromProgID( jscriptW, &clsid );
1635     hr = CoCreateInstance( &clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1636                            &IID_IActiveScript, (void **)&engine );
1637     if (hr != S_OK) goto done;
1638
1639     hr = IActiveScript_QueryInterface( engine, &IID_IActiveScriptParse, (void **)&parser );
1640     if (hr != S_OK) goto done;
1641
1642     hr = IActiveScriptParse64_InitNew( parser );
1643     if (hr != S_OK) goto done;
1644
1645     hr = IActiveScript_SetScriptSite( engine, &script_site );
1646     if (hr != S_OK) goto done;
1647
1648     /* FIXME: make standard functions available to script */
1649
1650     hr = IActiveScriptParse64_ParseScriptText( parser, script, NULL, NULL, NULL, 0, 0, 0, NULL, NULL );
1651     if (hr != S_OK) goto done;
1652
1653     hr = IActiveScript_SetScriptState( engine, SCRIPTSTATE_STARTED );
1654     if (hr != S_OK) goto done;
1655
1656     hr = IActiveScript_GetScriptDispatch( engine, NULL, &dispatch );
1657     if (hr != S_OK) goto done;
1658
1659     if (!(func = SysAllocString( findproxyW ))) goto done;
1660     hr = IDispatch_GetIDsOfNames( dispatch, &IID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispid );
1661     if (hr != S_OK) goto done;
1662
1663     V_VT( &args[0] ) = VT_BSTR;
1664     V_BSTR( &args[0] ) = hostname;
1665     V_VT( &args[1] ) = VT_BSTR;
1666     V_BSTR( &args[1] ) = SysAllocString( url );
1667
1668     params.rgvarg = args;
1669     params.rgdispidNamedArgs = NULL;
1670     params.cArgs = 2;
1671     params.cNamedArgs = 0;
1672     hr = IDispatch_Invoke( dispatch, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
1673                            &params, &result, NULL, NULL );
1674     VariantClear( &args[0] );
1675     VariantClear( &args[1] );
1676     if (hr != S_OK) goto done;
1677
1678     ret = parse_script_result( result, info );
1679
1680 done:
1681     SysFreeString( func );
1682     if (dispatch) IDispatch_Release( dispatch );
1683     if (parser) IUnknown_Release( parser );
1684     if (engine) IActiveScript_Release( engine );
1685     if (SUCCEEDED( init )) CoUninitialize();
1686     if (!ret) set_last_error( ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT );
1687     return ret;
1688 }
1689
1690 static BSTR download_script( HINTERNET ses, const WCHAR *url )
1691 {
1692     static const WCHAR typeW[] = {'*','/','*',0};
1693     static const WCHAR *acceptW[] = {typeW, NULL};
1694     HINTERNET con, req = NULL;
1695     WCHAR *hostname;
1696     URL_COMPONENTSW uc;
1697     DWORD size = 4096, offset, to_read, bytes_read, flags = 0;
1698     char *tmp, *buffer = NULL;
1699     BSTR script = NULL;
1700     int len;
1701
1702     memset( &uc, 0, sizeof(uc) );
1703     uc.dwStructSize = sizeof(uc);
1704     if (!WinHttpCrackUrl( url, 0, 0, &uc )) return NULL;
1705     if (!(hostname = heap_alloc( (uc.dwHostNameLength + 1) * sizeof(WCHAR) ))) return NULL;
1706     memcpy( hostname, uc.lpszHostName, uc.dwHostNameLength * sizeof(WCHAR) );
1707     hostname[uc.dwHostNameLength] = 0;
1708
1709     if (!(con = WinHttpConnect( ses, hostname, uc.nPort, 0 ))) goto done;
1710     if (uc.nScheme == INTERNET_SCHEME_HTTPS) flags |= WINHTTP_FLAG_SECURE;
1711     if (!(req = WinHttpOpenRequest( con, NULL, uc.lpszUrlPath, NULL, NULL, acceptW, flags ))) goto done;
1712     if (!WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 )) goto done;
1713     if (!(WinHttpReceiveResponse( req, 0 ))) goto done;
1714
1715     if (!(buffer = heap_alloc( size ))) goto done;
1716     to_read = size;
1717     offset = 0;
1718     for (;;)
1719     {
1720         if (!WinHttpReadData( req, buffer + offset, to_read, &bytes_read )) goto done;
1721         if (!bytes_read) break;
1722         to_read -= bytes_read;
1723         offset += bytes_read;
1724         if (!to_read)
1725         {
1726             to_read = size;
1727             size *= 2;
1728             if (!(tmp = heap_realloc( buffer, size ))) goto done;
1729             buffer = tmp;
1730         }
1731     }
1732     len = MultiByteToWideChar( CP_ACP, 0, buffer, offset, NULL, 0 );
1733     if (!(script = SysAllocStringLen( NULL, len ))) goto done;
1734     MultiByteToWideChar( CP_ACP, 0, buffer, offset, script, len );
1735     script[len] = 0;
1736
1737 done:
1738     WinHttpCloseHandle( req );
1739     WinHttpCloseHandle( con );
1740     heap_free( buffer );
1741     heap_free( hostname );
1742     if (!script) set_last_error( ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT );
1743     return script;
1744 }
1745
1746 /***********************************************************************
1747  *          WinHttpGetProxyForUrl (winhttp.@)
1748  */
1749 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1750                                    WINHTTP_PROXY_INFO *info )
1751 {
1752     WCHAR *detected_pac_url = NULL;
1753     const WCHAR *pac_url;
1754     session_t *session;
1755     BSTR script;
1756     BOOL ret = FALSE;
1757
1758     TRACE("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1759
1760     if (!(session = (session_t *)grab_object( hsession )))
1761     {
1762         set_last_error( ERROR_INVALID_HANDLE );
1763         return FALSE;
1764     }
1765     if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
1766     {
1767         release_object( &session->hdr );
1768         set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1769         return FALSE;
1770     }
1771     if (!url || !options || !info ||
1772         !(options->dwFlags & (WINHTTP_AUTOPROXY_AUTO_DETECT|WINHTTP_AUTOPROXY_CONFIG_URL)) ||
1773         ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) && !options->dwAutoDetectFlags) ||
1774         ((options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT) &&
1775          (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL)))
1776     {
1777         release_object( &session->hdr );
1778         set_last_error( ERROR_INVALID_PARAMETER );
1779         return FALSE;
1780     }
1781     if (options->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT &&
1782         !WinHttpDetectAutoProxyConfigUrl( options->dwAutoDetectFlags, &detected_pac_url ))
1783     {
1784         set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
1785         goto done;
1786     }
1787     if (options->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) pac_url = options->lpszAutoConfigUrl;
1788     else pac_url = detected_pac_url;
1789
1790     if (!(script = download_script( hsession, pac_url ))) goto done;
1791     ret = run_script( script, url, info );
1792     SysFreeString( script );
1793
1794 done:
1795     GlobalFree( detected_pac_url );
1796     release_object( &session->hdr );
1797     return ret;
1798 }
1799
1800 /***********************************************************************
1801  *          WinHttpSetDefaultProxyConfiguration (winhttp.@)
1802  */
1803 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1804 {
1805     LONG l;
1806     HKEY key;
1807     BOOL ret = FALSE;
1808     const WCHAR *src;
1809
1810     TRACE("%p\n", info);
1811
1812     if (!info)
1813     {
1814         set_last_error( ERROR_INVALID_PARAMETER );
1815         return FALSE;
1816     }
1817     switch (info->dwAccessType)
1818     {
1819     case WINHTTP_ACCESS_TYPE_NO_PROXY:
1820         break;
1821     case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1822         if (!info->lpszProxy)
1823         {
1824             set_last_error( ERROR_INVALID_PARAMETER );
1825             return FALSE;
1826         }
1827         /* Only ASCII characters are allowed */
1828         for (src = info->lpszProxy; *src; src++)
1829             if (*src > 0x7f)
1830             {
1831                 set_last_error( ERROR_INVALID_PARAMETER );
1832                 return FALSE;
1833             }
1834         if (info->lpszProxyBypass)
1835         {
1836             for (src = info->lpszProxyBypass; *src; src++)
1837                 if (*src > 0x7f)
1838                 {
1839                     set_last_error( ERROR_INVALID_PARAMETER );
1840                     return FALSE;
1841                 }
1842         }
1843         break;
1844     default:
1845         set_last_error( ERROR_INVALID_PARAMETER );
1846         return FALSE;
1847     }
1848
1849     l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1850         KEY_WRITE, NULL, &key, NULL );
1851     if (!l)
1852     {
1853         DWORD size = sizeof(struct connection_settings_header) + 2 * sizeof(DWORD);
1854         BYTE *buf;
1855
1856         if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1857         {
1858             size += strlenW( info->lpszProxy );
1859             if (info->lpszProxyBypass)
1860                 size += strlenW( info->lpszProxyBypass );
1861         }
1862         buf = heap_alloc( size );
1863         if (buf)
1864         {
1865             struct connection_settings_header *hdr =
1866                 (struct connection_settings_header *)buf;
1867             DWORD *len = (DWORD *)(hdr + 1);
1868
1869             hdr->magic = WINHTTP_SETTINGS_MAGIC;
1870             hdr->unknown = 0;
1871             if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1872             {
1873                 BYTE *dst;
1874
1875                 hdr->flags = PROXY_TYPE_PROXY;
1876                 *len++ = strlenW( info->lpszProxy );
1877                 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
1878                     src++, dst++)
1879                     *dst = *src;
1880                 len = (DWORD *)dst;
1881                 if (info->lpszProxyBypass)
1882                 {
1883                     *len++ = strlenW( info->lpszProxyBypass );
1884                     for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
1885                         src++, dst++)
1886                         *dst = *src;
1887                 }
1888                 else
1889                     *len++ = 0;
1890             }
1891             else
1892             {
1893                 hdr->flags = PROXY_TYPE_DIRECT;
1894                 *len++ = 0;
1895                 *len++ = 0;
1896             }
1897             l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
1898             if (!l)
1899                 ret = TRUE;
1900             heap_free( buf );
1901         }
1902         RegCloseKey( key );
1903     }
1904     return ret;
1905 }
1906
1907 /***********************************************************************
1908  *          WinHttpSetStatusCallback (winhttp.@)
1909  */
1910 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
1911                                                          DWORD flags, DWORD_PTR reserved )
1912 {
1913     object_header_t *hdr;
1914     WINHTTP_STATUS_CALLBACK ret;
1915
1916     TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
1917
1918     if (!(hdr = grab_object( handle )))
1919     {
1920         set_last_error( ERROR_INVALID_HANDLE );
1921         return WINHTTP_INVALID_STATUS_CALLBACK;
1922     }
1923     ret = hdr->callback;
1924     hdr->callback = callback;
1925     hdr->notify_mask = flags;
1926
1927     release_object( hdr );
1928     return ret;
1929 }
1930
1931 /***********************************************************************
1932  *          WinHttpSetTimeouts (winhttp.@)
1933  */
1934 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
1935 {
1936     BOOL ret = TRUE;
1937     object_header_t *hdr;
1938     request_t *request;
1939     session_t *session;
1940
1941     TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
1942
1943     if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
1944     {
1945         set_last_error( ERROR_INVALID_PARAMETER );
1946         return FALSE;
1947     }
1948
1949     if (!(hdr = grab_object( handle )))
1950     {
1951         set_last_error( ERROR_INVALID_HANDLE );
1952         return FALSE;
1953     }
1954
1955     switch(hdr->type)
1956     {
1957         case WINHTTP_HANDLE_TYPE_REQUEST:
1958             request = (request_t *)hdr;
1959             request->connect_timeout = connect;
1960
1961             if (resolve < 0) resolve = 0;
1962             request->resolve_timeout = resolve;
1963
1964             if (send < 0) send = 0;
1965             request->send_timeout = send;
1966
1967             if (receive < 0) receive = 0;
1968             request->recv_timeout = receive;
1969
1970             if (netconn_connected( &request->netconn ))
1971             {
1972                 if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE;
1973                 if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE;
1974             }
1975
1976             release_object( &request->hdr );
1977             break;
1978
1979         case WINHTTP_HANDLE_TYPE_SESSION:
1980             session = (session_t *)hdr;
1981             session->connect_timeout = connect;
1982
1983             if (resolve < 0) resolve = 0;
1984             session->resolve_timeout = resolve;
1985
1986             if (send < 0) send = 0;
1987             session->send_timeout = send;
1988
1989             if (receive < 0) receive = 0;
1990             session->recv_timeout = receive;
1991             break;
1992
1993         default:
1994             release_object( hdr );
1995             set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1996             return FALSE;
1997     }
1998     return ret;
1999 }
2000
2001 static const WCHAR wkday[7][4] =
2002     {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
2003      {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
2004 static const WCHAR month[12][4] =
2005     {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
2006      {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
2007      {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
2008
2009 /***********************************************************************
2010  *           WinHttpTimeFromSystemTime (WININET.@)
2011  */
2012 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
2013 {
2014     static const WCHAR format[] =
2015         {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2016          '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
2017
2018     TRACE("%p, %p\n", time, string);
2019
2020     if (!time || !string) return FALSE;
2021
2022     sprintfW( string, format,
2023               wkday[time->wDayOfWeek],
2024               time->wDay,
2025               month[time->wMonth - 1],
2026               time->wYear,
2027               time->wHour,
2028               time->wMinute,
2029               time->wSecond );
2030
2031     return TRUE;
2032 }
2033
2034 /***********************************************************************
2035  *           WinHttpTimeToSystemTime (WININET.@)
2036  */
2037 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
2038 {
2039     unsigned int i;
2040     const WCHAR *s = string;
2041     WCHAR *end;
2042
2043     TRACE("%s, %p\n", debugstr_w(string), time);
2044
2045     if (!string || !time) return FALSE;
2046
2047     /* Windows does this too */
2048     GetSystemTime( time );
2049
2050     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2051      *  a SYSTEMTIME structure.
2052      */
2053
2054     while (*s && !isalphaW( *s )) s++;
2055     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2056     time->wDayOfWeek = 7;
2057
2058     for (i = 0; i < 7; i++)
2059     {
2060         if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
2061             toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
2062             toupperW( wkday[i][2] ) == toupperW( s[2] ) )
2063         {
2064             time->wDayOfWeek = i;
2065             break;
2066         }
2067     }
2068
2069     if (time->wDayOfWeek > 6) return TRUE;
2070     while (*s && !isdigitW( *s )) s++;
2071     time->wDay = strtolW( s, &end, 10 );
2072     s = end;
2073
2074     while (*s && !isalphaW( *s )) s++;
2075     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2076     time->wMonth = 0;
2077
2078     for (i = 0; i < 12; i++)
2079     {
2080         if (toupperW( month[i][0]) == toupperW( s[0] ) &&
2081             toupperW( month[i][1]) == toupperW( s[1] ) &&
2082             toupperW( month[i][2]) == toupperW( s[2] ) )
2083         {
2084             time->wMonth = i + 1;
2085             break;
2086         }
2087     }
2088     if (time->wMonth == 0) return TRUE;
2089
2090     while (*s && !isdigitW( *s )) s++;
2091     if (*s == '\0') return TRUE;
2092     time->wYear = strtolW( s, &end, 10 );
2093     s = end;
2094
2095     while (*s && !isdigitW( *s )) s++;
2096     if (*s == '\0') return TRUE;
2097     time->wHour = strtolW( s, &end, 10 );
2098     s = end;
2099
2100     while (*s && !isdigitW( *s )) s++;
2101     if (*s == '\0') return TRUE;
2102     time->wMinute = strtolW( s, &end, 10 );
2103     s = end;
2104
2105     while (*s && !isdigitW( *s )) s++;
2106     if (*s == '\0') return TRUE;
2107     time->wSecond = strtolW( s, &end, 10 );
2108
2109     time->wMilliseconds = 0;
2110     return TRUE;
2111 }