[CLT2012]
[reactos.git] / dll / win32 / 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
32 #include "winhttp_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
35
36 #define DEFAULT_RESOLVE_TIMEOUT 0
37 #define DEFAULT_CONNECT_TIMEOUT 20000
38 #define DEFAULT_SEND_TIMEOUT 30000
39 #define DEFAULT_RECEIVE_TIMEOUT 30000
40
41 /* FIXME */
42 #define CP_UNIXCP CP_ACP
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 session->resolve_timeout = DEFAULT_RESOLVE_TIMEOUT;
213 session->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
214 session->send_timeout = DEFAULT_SEND_TIMEOUT;
215 session->recv_timeout = DEFAULT_RECEIVE_TIMEOUT;
216 list_init( &session->cookie_cache );
217
218 if (agent && !(session->agent = strdupW( agent ))) goto end;
219 if (access == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
220 {
221 WINHTTP_PROXY_INFO info;
222
223 WinHttpGetDefaultProxyConfiguration( &info );
224 session->access = info.dwAccessType;
225 if (info.lpszProxy && !(session->proxy_server = strdupW( info.lpszProxy )))
226 {
227 GlobalFree( (LPWSTR)info.lpszProxy );
228 GlobalFree( (LPWSTR)info.lpszProxyBypass );
229 goto end;
230 }
231 if (info.lpszProxyBypass && !(session->proxy_bypass = strdupW( info.lpszProxyBypass )))
232 {
233 GlobalFree( (LPWSTR)info.lpszProxy );
234 GlobalFree( (LPWSTR)info.lpszProxyBypass );
235 goto end;
236 }
237 }
238 else if (access == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
239 {
240 session->access = access;
241 if (proxy && !(session->proxy_server = strdupW( proxy ))) goto end;
242 if (bypass && !(session->proxy_bypass = strdupW( bypass ))) goto end;
243 }
244
245 if (!(handle = alloc_handle( &session->hdr ))) goto end;
246 session->hdr.handle = handle;
247
248 end:
249 release_object( &session->hdr );
250 TRACE("returning %p\n", handle);
251 return handle;
252 }
253
254 /***********************************************************************
255 * connect_destroy (internal)
256 */
257 static void connect_destroy( object_header_t *hdr )
258 {
259 connect_t *connect = (connect_t *)hdr;
260
261 TRACE("%p\n", connect);
262
263 release_object( &connect->session->hdr );
264
265 heap_free( connect->hostname );
266 heap_free( connect->servername );
267 heap_free( connect->username );
268 heap_free( connect->password );
269 heap_free( connect );
270 }
271
272 static BOOL connect_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
273 {
274 connect_t *connect = (connect_t *)hdr;
275
276 switch (option)
277 {
278 case WINHTTP_OPTION_PARENT_HANDLE:
279 {
280 if (!buffer || *buflen < sizeof(HINTERNET))
281 {
282 *buflen = sizeof(HINTERNET);
283 set_last_error( ERROR_INSUFFICIENT_BUFFER );
284 return FALSE;
285 }
286
287 *(HINTERNET *)buffer = ((object_header_t *)connect->session)->handle;
288 *buflen = sizeof(HINTERNET);
289 return TRUE;
290 }
291 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
292 *(DWORD *)buffer = connect->session->resolve_timeout;
293 *buflen = sizeof(DWORD);
294 return TRUE;
295 case WINHTTP_OPTION_CONNECT_TIMEOUT:
296 *(DWORD *)buffer = connect->session->connect_timeout;
297 *buflen = sizeof(DWORD);
298 return TRUE;
299 case WINHTTP_OPTION_SEND_TIMEOUT:
300 *(DWORD *)buffer = connect->session->send_timeout;
301 *buflen = sizeof(DWORD);
302 return TRUE;
303 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
304 *(DWORD *)buffer = connect->session->recv_timeout;
305 *buflen = sizeof(DWORD);
306 return TRUE;
307 default:
308 FIXME("unimplemented option %u\n", option);
309 set_last_error( ERROR_INVALID_PARAMETER );
310 return FALSE;
311 }
312 }
313
314 static const object_vtbl_t connect_vtbl =
315 {
316 connect_destroy,
317 connect_query_option,
318 NULL
319 };
320
321 static BOOL domain_matches(LPCWSTR server, LPCWSTR domain)
322 {
323 static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 };
324 BOOL ret = FALSE;
325
326 if (!strcmpiW( domain, localW ) && !strchrW( server, '.' ))
327 ret = TRUE;
328 else if (*domain == '*')
329 {
330 if (domain[1] == '.')
331 {
332 LPCWSTR dot;
333
334 /* For a hostname to match a wildcard, the last domain must match
335 * the wildcard exactly. E.g. if the wildcard is *.a.b, and the
336 * hostname is www.foo.a.b, it matches, but a.b does not.
337 */
338 dot = strchrW( server, '.' );
339 if (dot)
340 {
341 int len = strlenW( dot + 1 );
342
343 if (len > strlenW( domain + 2 ))
344 {
345 LPCWSTR ptr;
346
347 /* The server's domain is longer than the wildcard, so it
348 * could be a subdomain. Compare the last portion of the
349 * server's domain.
350 */
351 ptr = dot + len + 1 - strlenW( domain + 2 );
352 if (!strcmpiW( ptr, domain + 2 ))
353 {
354 /* This is only a match if the preceding character is
355 * a '.', i.e. that it is a matching domain. E.g.
356 * if domain is '*.b.c' and server is 'www.ab.c' they
357 * do not match.
358 */
359 ret = *(ptr - 1) == '.';
360 }
361 }
362 else
363 ret = !strcmpiW( dot + 1, domain + 2 );
364 }
365 }
366 }
367 else
368 ret = !strcmpiW( server, domain );
369 return ret;
370 }
371
372 /* Matches INTERNET_MAX_HOST_NAME_LENGTH in wininet.h, also RFC 1035 */
373 #define MAX_HOST_NAME_LENGTH 256
374
375 static BOOL should_bypass_proxy(session_t *session, LPCWSTR server)
376 {
377 LPCWSTR ptr;
378 BOOL ret = FALSE;
379
380 if (!session->proxy_bypass) return FALSE;
381 ptr = session->proxy_bypass;
382 do {
383 LPCWSTR tmp = ptr;
384
385 ptr = strchrW( ptr, ';' );
386 if (!ptr)
387 ptr = strchrW( tmp, ' ' );
388 if (ptr)
389 {
390 if (ptr - tmp < MAX_HOST_NAME_LENGTH)
391 {
392 WCHAR domain[MAX_HOST_NAME_LENGTH];
393
394 memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) );
395 domain[ptr - tmp] = 0;
396 ret = domain_matches( server, domain );
397 }
398 ptr += 1;
399 }
400 else if (*tmp)
401 ret = domain_matches( server, tmp );
402 } while (ptr && !ret);
403 return ret;
404 }
405
406 BOOL set_server_for_hostname( connect_t *connect, LPCWSTR server, INTERNET_PORT port )
407 {
408 session_t *session = connect->session;
409 BOOL ret = TRUE;
410
411 if (session->proxy_server && !should_bypass_proxy(session, server))
412 {
413 LPCWSTR colon;
414
415 if ((colon = strchrW( session->proxy_server, ':' )))
416 {
417 if (!connect->servername || strncmpiW( connect->servername,
418 session->proxy_server, colon - session->proxy_server - 1 ))
419 {
420 heap_free( connect->servername );
421 if (!(connect->servername = heap_alloc(
422 (colon - session->proxy_server + 1) * sizeof(WCHAR) )))
423 {
424 ret = FALSE;
425 goto end;
426 }
427 memcpy( connect->servername, session->proxy_server,
428 (colon - session->proxy_server) * sizeof(WCHAR) );
429 connect->servername[colon - session->proxy_server] = 0;
430 if (*(colon + 1))
431 connect->serverport = atoiW( colon + 1 );
432 else
433 connect->serverport = INTERNET_DEFAULT_PORT;
434 }
435 }
436 else
437 {
438 if (!connect->servername || strcmpiW( connect->servername,
439 session->proxy_server ))
440 {
441 heap_free( connect->servername );
442 if (!(connect->servername = strdupW( session->proxy_server )))
443 {
444 ret = FALSE;
445 goto end;
446 }
447 connect->serverport = INTERNET_DEFAULT_PORT;
448 }
449 }
450 }
451 else if (server)
452 {
453 heap_free( connect->servername );
454 if (!(connect->servername = strdupW( server )))
455 {
456 ret = FALSE;
457 goto end;
458 }
459 connect->serverport = port;
460 }
461 end:
462 return ret;
463 }
464
465 /***********************************************************************
466 * WinHttpConnect (winhttp.@)
467 */
468 HINTERNET WINAPI WinHttpConnect( HINTERNET hsession, LPCWSTR server, INTERNET_PORT port, DWORD reserved )
469 {
470 connect_t *connect;
471 session_t *session;
472 HINTERNET hconnect = NULL;
473
474 TRACE("%p, %s, %u, %x\n", hsession, debugstr_w(server), port, reserved);
475
476 if (!server)
477 {
478 set_last_error( ERROR_INVALID_PARAMETER );
479 return NULL;
480 }
481 if (!(session = (session_t *)grab_object( hsession )))
482 {
483 set_last_error( ERROR_INVALID_HANDLE );
484 return NULL;
485 }
486 if (session->hdr.type != WINHTTP_HANDLE_TYPE_SESSION)
487 {
488 release_object( &session->hdr );
489 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
490 return NULL;
491 }
492 if (!(connect = heap_alloc_zero( sizeof(connect_t) )))
493 {
494 release_object( &session->hdr );
495 return NULL;
496 }
497 connect->hdr.type = WINHTTP_HANDLE_TYPE_CONNECT;
498 connect->hdr.vtbl = &connect_vtbl;
499 connect->hdr.refs = 1;
500 connect->hdr.flags = session->hdr.flags;
501 connect->hdr.callback = session->hdr.callback;
502 connect->hdr.notify_mask = session->hdr.notify_mask;
503 connect->hdr.context = session->hdr.context;
504
505 addref_object( &session->hdr );
506 connect->session = session;
507 list_add_head( &session->hdr.children, &connect->hdr.entry );
508
509 if (!(connect->hostname = strdupW( server ))) goto end;
510 connect->hostport = port;
511
512 if (!set_server_for_hostname( connect, server, port ))
513 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
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 DWORD 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 heap_free( request );
551 }
552
553 static void str_to_buffer( WCHAR *buffer, const WCHAR *str, LPDWORD buflen )
554 {
555 int len = 0;
556 if (str) len = strlenW( str );
557 if (buffer && *buflen > len)
558 {
559 memcpy( buffer, str, len * sizeof(WCHAR) );
560 buffer[len] = 0;
561 }
562 *buflen = len * sizeof(WCHAR);
563 }
564
565 static WCHAR *blob_to_str( DWORD encoding, CERT_NAME_BLOB *blob )
566 {
567 WCHAR *ret;
568 DWORD size, format = CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG;
569
570 size = CertNameToStrW( encoding, blob, format, NULL, 0 );
571 if ((ret = LocalAlloc( 0, size * sizeof(WCHAR) )))
572 CertNameToStrW( encoding, blob, format, ret, size );
573
574 return ret;
575 }
576
577 static BOOL request_query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
578 {
579 request_t *request = (request_t *)hdr;
580
581 switch (option)
582 {
583 case WINHTTP_OPTION_SECURITY_FLAGS:
584 {
585 DWORD flags;
586 int bits;
587
588 if (!buffer || *buflen < sizeof(flags))
589 {
590 *buflen = sizeof(flags);
591 set_last_error( ERROR_INSUFFICIENT_BUFFER );
592 return FALSE;
593 }
594
595 flags = 0;
596 if (hdr->flags & WINHTTP_FLAG_SECURE) flags |= SECURITY_FLAG_SECURE;
597 flags |= request->netconn.security_flags;
598 bits = netconn_get_cipher_strength( &request->netconn );
599 if (bits >= 128)
600 flags |= SECURITY_FLAG_STRENGTH_STRONG;
601 else if (bits >= 56)
602 flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
603 else
604 flags |= SECURITY_FLAG_STRENGTH_WEAK;
605 *(DWORD *)buffer = flags;
606 *buflen = sizeof(flags);
607 return TRUE;
608 }
609 case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
610 {
611 const CERT_CONTEXT *cert;
612
613 if (!buffer || *buflen < sizeof(cert))
614 {
615 *buflen = sizeof(cert);
616 set_last_error( ERROR_INSUFFICIENT_BUFFER );
617 return FALSE;
618 }
619
620 if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
621 *(CERT_CONTEXT **)buffer = (CERT_CONTEXT *)cert;
622 *buflen = sizeof(cert);
623 return TRUE;
624 }
625 case WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT:
626 {
627 const CERT_CONTEXT *cert;
628 const CRYPT_OID_INFO *oidInfo;
629 WINHTTP_CERTIFICATE_INFO *ci = buffer;
630
631 FIXME("partial stub\n");
632
633 if (!buffer || *buflen < sizeof(*ci))
634 {
635 *buflen = sizeof(*ci);
636 set_last_error( ERROR_INSUFFICIENT_BUFFER );
637 return FALSE;
638 }
639 if (!(cert = netconn_get_certificate( &request->netconn ))) return FALSE;
640
641 ci->ftExpiry = cert->pCertInfo->NotAfter;
642 ci->ftStart = cert->pCertInfo->NotBefore;
643 ci->lpszSubjectInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Subject );
644 ci->lpszIssuerInfo = blob_to_str( cert->dwCertEncodingType, &cert->pCertInfo->Issuer );
645 ci->lpszProtocolName = NULL;
646 oidInfo = CryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY,
647 cert->pCertInfo->SignatureAlgorithm.pszObjId,
648 0 );
649 if (oidInfo)
650 ci->lpszSignatureAlgName = (LPWSTR)oidInfo->pwszName;
651 else
652 ci->lpszSignatureAlgName = NULL;
653 ci->lpszEncryptionAlgName = NULL;
654 ci->dwKeySize = netconn_get_cipher_strength( &request->netconn );
655
656 CertFreeCertificateContext( cert );
657 *buflen = sizeof(*ci);
658 return TRUE;
659 }
660 case WINHTTP_OPTION_SECURITY_KEY_BITNESS:
661 {
662 if (!buffer || *buflen < sizeof(DWORD))
663 {
664 *buflen = sizeof(DWORD);
665 set_last_error( ERROR_INSUFFICIENT_BUFFER );
666 return FALSE;
667 }
668
669 *(DWORD *)buffer = netconn_get_cipher_strength( &request->netconn );
670 *buflen = sizeof(DWORD);
671 return TRUE;
672 }
673 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
674 *(DWORD *)buffer = request->resolve_timeout;
675 *buflen = sizeof(DWORD);
676 return TRUE;
677 case WINHTTP_OPTION_CONNECT_TIMEOUT:
678 *(DWORD *)buffer = request->connect_timeout;
679 *buflen = sizeof(DWORD);
680 return TRUE;
681 case WINHTTP_OPTION_SEND_TIMEOUT:
682 *(DWORD *)buffer = request->send_timeout;
683 *buflen = sizeof(DWORD);
684 return TRUE;
685 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
686 *(DWORD *)buffer = request->recv_timeout;
687 *buflen = sizeof(DWORD);
688 return TRUE;
689
690 case WINHTTP_OPTION_USERNAME:
691 str_to_buffer( buffer, request->connect->username, buflen );
692 return TRUE;
693
694 case WINHTTP_OPTION_PASSWORD:
695 str_to_buffer( buffer, request->connect->password, buflen );
696 return TRUE;
697
698 case WINHTTP_OPTION_PROXY_USERNAME:
699 str_to_buffer( buffer, request->connect->session->proxy_username, buflen );
700 return TRUE;
701
702 case WINHTTP_OPTION_PROXY_PASSWORD:
703 str_to_buffer( buffer, request->connect->session->proxy_password, buflen );
704 return TRUE;
705
706 default:
707 FIXME("unimplemented option %u\n", option);
708 set_last_error( ERROR_INVALID_PARAMETER );
709 return FALSE;
710 }
711 }
712
713 static WCHAR *buffer_to_str( WCHAR *buffer, DWORD buflen )
714 {
715 WCHAR *ret;
716 if ((ret = heap_alloc( (buflen + 1) * sizeof(WCHAR))))
717 {
718 memcpy( ret, buffer, buflen * sizeof(WCHAR) );
719 ret[buflen] = 0;
720 return ret;
721 }
722 set_last_error( ERROR_OUTOFMEMORY );
723 return NULL;
724 }
725
726 static BOOL request_set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
727 {
728 request_t *request = (request_t *)hdr;
729
730 switch (option)
731 {
732 case WINHTTP_OPTION_PROXY:
733 {
734 WINHTTP_PROXY_INFO *pi = buffer;
735
736 FIXME("%u %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass));
737 return TRUE;
738 }
739 case WINHTTP_OPTION_DISABLE_FEATURE:
740 {
741 DWORD disable;
742
743 if (buflen != sizeof(DWORD))
744 {
745 set_last_error( ERROR_INSUFFICIENT_BUFFER );
746 return FALSE;
747 }
748
749 disable = *(DWORD *)buffer;
750 TRACE("0x%x\n", disable);
751 hdr->disable_flags |= disable;
752 return TRUE;
753 }
754 case WINHTTP_OPTION_AUTOLOGON_POLICY:
755 {
756 DWORD policy;
757
758 if (buflen != sizeof(DWORD))
759 {
760 set_last_error( ERROR_INSUFFICIENT_BUFFER );
761 return FALSE;
762 }
763
764 policy = *(DWORD *)buffer;
765 TRACE("0x%x\n", policy);
766 hdr->logon_policy = policy;
767 return TRUE;
768 }
769 case WINHTTP_OPTION_REDIRECT_POLICY:
770 {
771 DWORD policy;
772
773 if (buflen != sizeof(DWORD))
774 {
775 set_last_error( ERROR_INSUFFICIENT_BUFFER );
776 return FALSE;
777 }
778
779 policy = *(DWORD *)buffer;
780 TRACE("0x%x\n", policy);
781 hdr->redirect_policy = policy;
782 return TRUE;
783 }
784 case WINHTTP_OPTION_SECURITY_FLAGS:
785 {
786 DWORD flags;
787
788 if (buflen < sizeof(DWORD))
789 {
790 set_last_error( ERROR_INSUFFICIENT_BUFFER );
791 return FALSE;
792 }
793 flags = *(DWORD *)buffer;
794 TRACE("0x%x\n", flags);
795 if (!(flags & (SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
796 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
797 SECURITY_FLAG_IGNORE_UNKNOWN_CA |
798 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE)))
799 {
800 set_last_error( ERROR_INVALID_PARAMETER );
801 return FALSE;
802 }
803 request->netconn.security_flags = flags;
804 return TRUE;
805 }
806 case WINHTTP_OPTION_RESOLVE_TIMEOUT:
807 request->resolve_timeout = *(DWORD *)buffer;
808 return TRUE;
809 case WINHTTP_OPTION_CONNECT_TIMEOUT:
810 request->connect_timeout = *(DWORD *)buffer;
811 return TRUE;
812 case WINHTTP_OPTION_SEND_TIMEOUT:
813 request->send_timeout = *(DWORD *)buffer;
814 return TRUE;
815 case WINHTTP_OPTION_RECEIVE_TIMEOUT:
816 request->recv_timeout = *(DWORD *)buffer;
817 return TRUE;
818
819 case WINHTTP_OPTION_USERNAME:
820 {
821 connect_t *connect = request->connect;
822
823 heap_free( connect->username );
824 if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
825 return TRUE;
826 }
827 case WINHTTP_OPTION_PASSWORD:
828 {
829 connect_t *connect = request->connect;
830
831 heap_free( connect->password );
832 if (!(connect->password = buffer_to_str( buffer, buflen ))) return FALSE;
833 return TRUE;
834 }
835 case WINHTTP_OPTION_PROXY_USERNAME:
836 {
837 session_t *session = request->connect->session;
838
839 heap_free( session->proxy_username );
840 if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
841 return TRUE;
842 }
843 case WINHTTP_OPTION_PROXY_PASSWORD:
844 {
845 session_t *session = request->connect->session;
846
847 heap_free( session->proxy_password );
848 if (!(session->proxy_password = buffer_to_str( buffer, buflen ))) return FALSE;
849 return TRUE;
850 }
851 default:
852 FIXME("unimplemented option %u\n", option);
853 set_last_error( ERROR_INVALID_PARAMETER );
854 return TRUE;
855 }
856 }
857
858 static const object_vtbl_t request_vtbl =
859 {
860 request_destroy,
861 request_query_option,
862 request_set_option
863 };
864
865 /***********************************************************************
866 * WinHttpOpenRequest (winhttp.@)
867 */
868 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR object, LPCWSTR version,
869 LPCWSTR referrer, LPCWSTR *types, DWORD flags )
870 {
871 request_t *request;
872 connect_t *connect;
873 HINTERNET hrequest = NULL;
874
875 TRACE("%p, %s, %s, %s, %s, %p, 0x%08x\n", hconnect, debugstr_w(verb), debugstr_w(object),
876 debugstr_w(version), debugstr_w(referrer), types, flags);
877
878 if (!(connect = (connect_t *)grab_object( hconnect )))
879 {
880 set_last_error( ERROR_INVALID_HANDLE );
881 return NULL;
882 }
883 if (connect->hdr.type != WINHTTP_HANDLE_TYPE_CONNECT)
884 {
885 release_object( &connect->hdr );
886 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
887 return NULL;
888 }
889 if (!(request = heap_alloc_zero( sizeof(request_t) )))
890 {
891 release_object( &connect->hdr );
892 return NULL;
893 }
894 request->hdr.type = WINHTTP_HANDLE_TYPE_REQUEST;
895 request->hdr.vtbl = &request_vtbl;
896 request->hdr.refs = 1;
897 request->hdr.flags = flags;
898 request->hdr.callback = connect->hdr.callback;
899 request->hdr.notify_mask = connect->hdr.notify_mask;
900 request->hdr.context = connect->hdr.context;
901
902 addref_object( &connect->hdr );
903 request->connect = connect;
904 list_add_head( &connect->hdr.children, &request->hdr.entry );
905
906 if (!netconn_init( &request->netconn, request->hdr.flags & WINHTTP_FLAG_SECURE )) goto end;
907 request->resolve_timeout = connect->session->resolve_timeout;
908 request->connect_timeout = connect->session->connect_timeout;
909 request->send_timeout = connect->session->send_timeout;
910 request->recv_timeout = connect->session->recv_timeout;
911
912 if (!verb || !verb[0]) verb = getW;
913 if (!(request->verb = strdupW( verb ))) goto end;
914
915 if (object)
916 {
917 WCHAR *path, *p;
918 unsigned int len;
919
920 len = strlenW( object ) + 1;
921 if (object[0] != '/') len++;
922 if (!(p = path = heap_alloc( len * sizeof(WCHAR) ))) goto end;
923
924 if (object[0] != '/') *p++ = '/';
925 strcpyW( p, object );
926 request->path = path;
927 }
928 else if (!(request->path = strdupW( slashW ))) goto end;
929
930 if (!version || !version[0]) version = http1_1;
931 if (!(request->version = strdupW( version ))) goto end;
932
933 if (!(hrequest = alloc_handle( &request->hdr ))) goto end;
934 request->hdr.handle = hrequest;
935
936 send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hrequest, sizeof(hrequest) );
937
938 end:
939 release_object( &request->hdr );
940
941 TRACE("returning %p\n", hrequest);
942 return hrequest;
943 }
944
945 /***********************************************************************
946 * WinHttpCloseHandle (winhttp.@)
947 */
948 BOOL WINAPI WinHttpCloseHandle( HINTERNET handle )
949 {
950 object_header_t *hdr;
951
952 TRACE("%p\n", handle);
953
954 if (!(hdr = grab_object( handle )))
955 {
956 set_last_error( ERROR_INVALID_HANDLE );
957 return FALSE;
958 }
959 release_object( hdr );
960 free_handle( handle );
961 return TRUE;
962 }
963
964 static BOOL query_option( object_header_t *hdr, DWORD option, LPVOID buffer, LPDWORD buflen )
965 {
966 BOOL ret = FALSE;
967
968 if (!buflen)
969 {
970 set_last_error( ERROR_INVALID_PARAMETER );
971 return FALSE;
972 }
973
974 switch (option)
975 {
976 case WINHTTP_OPTION_CONTEXT_VALUE:
977 {
978 if (!buffer || *buflen < sizeof(DWORD_PTR))
979 {
980 *buflen = sizeof(DWORD_PTR);
981 set_last_error( ERROR_INSUFFICIENT_BUFFER );
982 return FALSE;
983 }
984
985 *(DWORD_PTR *)buffer = hdr->context;
986 *buflen = sizeof(DWORD_PTR);
987 return TRUE;
988 }
989 default:
990 if (hdr->vtbl->query_option) ret = hdr->vtbl->query_option( hdr, option, buffer, buflen );
991 else
992 {
993 FIXME("unimplemented option %u\n", option);
994 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
995 return FALSE;
996 }
997 break;
998 }
999 return ret;
1000 }
1001
1002 /***********************************************************************
1003 * WinHttpQueryOption (winhttp.@)
1004 */
1005 BOOL WINAPI WinHttpQueryOption( HINTERNET handle, DWORD option, LPVOID buffer, LPDWORD buflen )
1006 {
1007 BOOL ret = FALSE;
1008 object_header_t *hdr;
1009
1010 TRACE("%p, %u, %p, %p\n", handle, option, buffer, buflen);
1011
1012 if (!(hdr = grab_object( handle )))
1013 {
1014 set_last_error( ERROR_INVALID_HANDLE );
1015 return FALSE;
1016 }
1017
1018 ret = query_option( hdr, option, buffer, buflen );
1019
1020 release_object( hdr );
1021 return ret;
1022 }
1023
1024 static BOOL set_option( object_header_t *hdr, DWORD option, LPVOID buffer, DWORD buflen )
1025 {
1026 BOOL ret = TRUE;
1027
1028 if (!buffer)
1029 {
1030 set_last_error( ERROR_INVALID_PARAMETER );
1031 return FALSE;
1032 }
1033
1034 switch (option)
1035 {
1036 case WINHTTP_OPTION_CONTEXT_VALUE:
1037 {
1038 if (buflen != sizeof(DWORD_PTR))
1039 {
1040 set_last_error( ERROR_INSUFFICIENT_BUFFER );
1041 return FALSE;
1042 }
1043
1044 hdr->context = *(DWORD_PTR *)buffer;
1045 return TRUE;
1046 }
1047 default:
1048 if (hdr->vtbl->set_option) ret = hdr->vtbl->set_option( hdr, option, buffer, buflen );
1049 else
1050 {
1051 FIXME("unimplemented option %u\n", option);
1052 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1053 return FALSE;
1054 }
1055 break;
1056 }
1057 return ret;
1058 }
1059
1060 /***********************************************************************
1061 * WinHttpSetOption (winhttp.@)
1062 */
1063 BOOL WINAPI WinHttpSetOption( HINTERNET handle, DWORD option, LPVOID buffer, DWORD buflen )
1064 {
1065 BOOL ret = FALSE;
1066 object_header_t *hdr;
1067
1068 TRACE("%p, %u, %p, %u\n", handle, option, buffer, buflen);
1069
1070 if (!(hdr = grab_object( handle )))
1071 {
1072 set_last_error( ERROR_INVALID_HANDLE );
1073 return FALSE;
1074 }
1075
1076 ret = set_option( hdr, option, buffer, buflen );
1077
1078 release_object( hdr );
1079 return ret;
1080 }
1081
1082 /***********************************************************************
1083 * WinHttpDetectAutoProxyConfigUrl (winhttp.@)
1084 */
1085 BOOL WINAPI WinHttpDetectAutoProxyConfigUrl( DWORD flags, LPWSTR *url )
1086 {
1087 FIXME("0x%08x, %p\n", flags, url);
1088
1089 set_last_error( ERROR_WINHTTP_AUTODETECTION_FAILED );
1090 return FALSE;
1091 }
1092
1093 static const WCHAR Connections[] = {
1094 'S','o','f','t','w','a','r','e','\\',
1095 'M','i','c','r','o','s','o','f','t','\\',
1096 'W','i','n','d','o','w','s','\\',
1097 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1098 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s','\\',
1099 'C','o','n','n','e','c','t','i','o','n','s',0 };
1100 static const WCHAR WinHttpSettings[] = {
1101 'W','i','n','H','t','t','p','S','e','t','t','i','n','g','s',0 };
1102 static const DWORD WINHTTPSETTINGS_MAGIC = 0x18;
1103 static const DWORD WINHTTP_PROXY_TYPE_DIRECT = 1;
1104 static const DWORD WINHTTP_PROXY_TYPE_PROXY = 2;
1105
1106 struct winhttp_settings_header
1107 {
1108 DWORD magic;
1109 DWORD unknown; /* always zero? */
1110 DWORD flags; /* one of WINHTTP_PROXY_TYPE_* */
1111 };
1112
1113 static inline void copy_char_to_wchar_sz(const BYTE *src, DWORD len, WCHAR *dst)
1114 {
1115 const BYTE *begin;
1116
1117 for (begin = src; src - begin < len; src++, dst++)
1118 *dst = *src;
1119 *dst = 0;
1120 }
1121
1122 /***********************************************************************
1123 * WinHttpGetDefaultProxyConfiguration (winhttp.@)
1124 */
1125 BOOL WINAPI WinHttpGetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1126 {
1127 LONG l;
1128 HKEY key;
1129 BOOL got_from_reg = FALSE, direct = TRUE;
1130 char *envproxy;
1131
1132 TRACE("%p\n", info);
1133
1134 l = RegOpenKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, KEY_READ, &key );
1135 if (!l)
1136 {
1137 DWORD type, size = 0;
1138
1139 l = RegQueryValueExW( key, WinHttpSettings, NULL, &type, NULL, &size );
1140 if (!l && type == REG_BINARY &&
1141 size >= sizeof(struct winhttp_settings_header) + 2 * sizeof(DWORD))
1142 {
1143 BYTE *buf = heap_alloc( size );
1144
1145 if (buf)
1146 {
1147 struct winhttp_settings_header *hdr =
1148 (struct winhttp_settings_header *)buf;
1149 DWORD *len = (DWORD *)(hdr + 1);
1150
1151 l = RegQueryValueExW( key, WinHttpSettings, NULL, NULL, buf,
1152 &size );
1153 if (!l && hdr->magic == WINHTTPSETTINGS_MAGIC &&
1154 hdr->unknown == 0)
1155 {
1156 if (hdr->flags & WINHTTP_PROXY_TYPE_PROXY)
1157 {
1158 BOOL sane = FALSE;
1159 LPWSTR proxy = NULL;
1160 LPWSTR proxy_bypass = NULL;
1161
1162 /* Sanity-check length of proxy string */
1163 if ((BYTE *)len - buf + *len <= size)
1164 {
1165 sane = TRUE;
1166 proxy = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1167 if (proxy)
1168 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy );
1169 len = (DWORD *)((BYTE *)(len + 1) + *len);
1170 }
1171 if (sane)
1172 {
1173 /* Sanity-check length of proxy bypass string */
1174 if ((BYTE *)len - buf + *len <= size)
1175 {
1176 proxy_bypass = GlobalAlloc( 0, (*len + 1) * sizeof(WCHAR) );
1177 if (proxy_bypass)
1178 copy_char_to_wchar_sz( (BYTE *)(len + 1), *len, proxy_bypass );
1179 }
1180 else
1181 {
1182 sane = FALSE;
1183 GlobalFree( proxy );
1184 proxy = NULL;
1185 }
1186 }
1187 info->lpszProxy = proxy;
1188 info->lpszProxyBypass = proxy_bypass;
1189 if (sane)
1190 {
1191 got_from_reg = TRUE;
1192 direct = FALSE;
1193 info->dwAccessType =
1194 WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1195 TRACE("http proxy (from registry) = %s, bypass = %s\n",
1196 debugstr_w(info->lpszProxy),
1197 debugstr_w(info->lpszProxyBypass));
1198 }
1199 }
1200 }
1201 heap_free( buf );
1202 }
1203 }
1204 RegCloseKey( key );
1205 }
1206 if (!got_from_reg && (envproxy = getenv( "http_proxy" )))
1207 {
1208 char *colon, *http_proxy;
1209
1210 if ((colon = strchr( envproxy, ':' )))
1211 {
1212 if (*(colon + 1) == '/' && *(colon + 2) == '/')
1213 {
1214 static const char http[] = "http://";
1215
1216 /* It's a scheme, check that it's http */
1217 if (!strncmp( envproxy, http, strlen( http ) ))
1218 http_proxy = envproxy + strlen( http );
1219 else
1220 {
1221 WARN("unsupported scheme in $http_proxy: %s\n", envproxy);
1222 http_proxy = NULL;
1223 }
1224 }
1225 else
1226 http_proxy = envproxy;
1227 }
1228 else
1229 http_proxy = envproxy;
1230 if (http_proxy)
1231 {
1232 WCHAR *http_proxyW;
1233 int len;
1234
1235 len = MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, NULL, 0 );
1236 if ((http_proxyW = GlobalAlloc( 0, len * sizeof(WCHAR))))
1237 {
1238 MultiByteToWideChar( CP_UNIXCP, 0, http_proxy, -1, http_proxyW, len );
1239 direct = FALSE;
1240 info->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
1241 info->lpszProxy = http_proxyW;
1242 info->lpszProxyBypass = NULL;
1243 TRACE("http proxy (from environment) = %s\n",
1244 debugstr_w(info->lpszProxy));
1245 }
1246 }
1247 }
1248 if (direct)
1249 {
1250 info->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
1251 info->lpszProxy = NULL;
1252 info->lpszProxyBypass = NULL;
1253 }
1254 return TRUE;
1255 }
1256
1257 /***********************************************************************
1258 * WinHttpGetIEProxyConfigForCurrentUser (winhttp.@)
1259 */
1260 BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *config )
1261 {
1262 TRACE("%p\n", config);
1263
1264 if (!config)
1265 {
1266 set_last_error( ERROR_INVALID_PARAMETER );
1267 return FALSE;
1268 }
1269
1270 /* FIXME: read from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings */
1271
1272 FIXME("returning no proxy used\n");
1273 config->fAutoDetect = FALSE;
1274 config->lpszAutoConfigUrl = NULL;
1275 config->lpszProxy = NULL;
1276 config->lpszProxyBypass = NULL;
1277
1278 return TRUE;
1279 }
1280
1281 /***********************************************************************
1282 * WinHttpGetProxyForUrl (winhttp.@)
1283 */
1284 BOOL WINAPI WinHttpGetProxyForUrl( HINTERNET hsession, LPCWSTR url, WINHTTP_AUTOPROXY_OPTIONS *options,
1285 WINHTTP_PROXY_INFO *info )
1286 {
1287 FIXME("%p, %s, %p, %p\n", hsession, debugstr_w(url), options, info);
1288
1289 set_last_error( ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR );
1290 return FALSE;
1291 }
1292
1293 /***********************************************************************
1294 * WinHttpSetDefaultProxyConfiguration (winhttp.@)
1295 */
1296 BOOL WINAPI WinHttpSetDefaultProxyConfiguration( WINHTTP_PROXY_INFO *info )
1297 {
1298 LONG l;
1299 HKEY key;
1300 BOOL ret = FALSE;
1301 const WCHAR *src;
1302
1303 TRACE("%p\n", info);
1304
1305 if (!info)
1306 {
1307 set_last_error( ERROR_INVALID_PARAMETER );
1308 return FALSE;
1309 }
1310 switch (info->dwAccessType)
1311 {
1312 case WINHTTP_ACCESS_TYPE_NO_PROXY:
1313 break;
1314 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
1315 if (!info->lpszProxy)
1316 {
1317 set_last_error( ERROR_INVALID_PARAMETER );
1318 return FALSE;
1319 }
1320 /* Only ASCII characters are allowed */
1321 for (src = info->lpszProxy; *src; src++)
1322 if (*src > 0x7f)
1323 {
1324 set_last_error( ERROR_INVALID_PARAMETER );
1325 return FALSE;
1326 }
1327 if (info->lpszProxyBypass)
1328 {
1329 for (src = info->lpszProxyBypass; *src; src++)
1330 if (*src > 0x7f)
1331 {
1332 set_last_error( ERROR_INVALID_PARAMETER );
1333 return FALSE;
1334 }
1335 }
1336 break;
1337 default:
1338 set_last_error( ERROR_INVALID_PARAMETER );
1339 return FALSE;
1340 }
1341
1342 l = RegCreateKeyExW( HKEY_LOCAL_MACHINE, Connections, 0, NULL, 0,
1343 KEY_WRITE, NULL, &key, NULL );
1344 if (!l)
1345 {
1346 DWORD size = sizeof(struct winhttp_settings_header) + 2 * sizeof(DWORD);
1347 BYTE *buf;
1348
1349 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1350 {
1351 size += strlenW( info->lpszProxy );
1352 if (info->lpszProxyBypass)
1353 size += strlenW( info->lpszProxyBypass );
1354 }
1355 buf = heap_alloc( size );
1356 if (buf)
1357 {
1358 struct winhttp_settings_header *hdr =
1359 (struct winhttp_settings_header *)buf;
1360 DWORD *len = (DWORD *)(hdr + 1);
1361
1362 hdr->magic = WINHTTPSETTINGS_MAGIC;
1363 hdr->unknown = 0;
1364 if (info->dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY)
1365 {
1366 BYTE *dst;
1367
1368 hdr->flags = WINHTTP_PROXY_TYPE_PROXY;
1369 *len++ = strlenW( info->lpszProxy );
1370 for (dst = (BYTE *)len, src = info->lpszProxy; *src;
1371 src++, dst++)
1372 *dst = *src;
1373 len = (DWORD *)dst;
1374 if (info->lpszProxyBypass)
1375 {
1376 *len++ = strlenW( info->lpszProxyBypass );
1377 for (dst = (BYTE *)len, src = info->lpszProxyBypass; *src;
1378 src++, dst++)
1379 *dst = *src;
1380 }
1381 else
1382 *len++ = 0;
1383 }
1384 else
1385 {
1386 hdr->flags = WINHTTP_PROXY_TYPE_DIRECT;
1387 *len++ = 0;
1388 *len++ = 0;
1389 }
1390 l = RegSetValueExW( key, WinHttpSettings, 0, REG_BINARY, buf, size );
1391 if (!l)
1392 ret = TRUE;
1393 heap_free( buf );
1394 }
1395 RegCloseKey( key );
1396 }
1397 return ret;
1398 }
1399
1400 /***********************************************************************
1401 * WinHttpSetStatusCallback (winhttp.@)
1402 */
1403 WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback( HINTERNET handle, WINHTTP_STATUS_CALLBACK callback,
1404 DWORD flags, DWORD_PTR reserved )
1405 {
1406 object_header_t *hdr;
1407 WINHTTP_STATUS_CALLBACK ret;
1408
1409 TRACE("%p, %p, 0x%08x, 0x%lx\n", handle, callback, flags, reserved);
1410
1411 if (!(hdr = grab_object( handle )))
1412 {
1413 set_last_error( ERROR_INVALID_HANDLE );
1414 return WINHTTP_INVALID_STATUS_CALLBACK;
1415 }
1416 ret = hdr->callback;
1417 hdr->callback = callback;
1418 hdr->notify_mask = flags;
1419
1420 release_object( hdr );
1421 return ret;
1422 }
1423
1424 /***********************************************************************
1425 * WinHttpSetTimeouts (winhttp.@)
1426 */
1427 BOOL WINAPI WinHttpSetTimeouts( HINTERNET handle, int resolve, int connect, int send, int receive )
1428 {
1429 BOOL ret = TRUE;
1430 object_header_t *hdr;
1431 request_t *request;
1432 session_t *session;
1433
1434 TRACE("%p, %d, %d, %d, %d\n", handle, resolve, connect, send, receive);
1435
1436 if (resolve < -1 || connect < -1 || send < -1 || receive < -1)
1437 {
1438 set_last_error( ERROR_INVALID_PARAMETER );
1439 return FALSE;
1440 }
1441
1442 if (!(hdr = grab_object( handle )))
1443 {
1444 set_last_error( ERROR_INVALID_HANDLE );
1445 return FALSE;
1446 }
1447
1448 switch(hdr->type)
1449 {
1450 case WINHTTP_HANDLE_TYPE_REQUEST:
1451 request = (request_t *)hdr;
1452 request->connect_timeout = connect;
1453
1454 if (resolve < 0) resolve = 0;
1455 request->resolve_timeout = resolve;
1456
1457 if (send < 0) send = 0;
1458 request->send_timeout = send;
1459
1460 if (receive < 0) receive = 0;
1461 request->recv_timeout = receive;
1462
1463 if (netconn_connected( &request->netconn ))
1464 {
1465 if (netconn_set_timeout( &request->netconn, TRUE, send )) ret = FALSE;
1466 if (netconn_set_timeout( &request->netconn, FALSE, receive )) ret = FALSE;
1467 }
1468
1469 release_object( &request->hdr );
1470 break;
1471
1472 case WINHTTP_HANDLE_TYPE_SESSION:
1473 session = (session_t *)hdr;
1474 session->connect_timeout = connect;
1475
1476 if (resolve < 0) resolve = 0;
1477 session->resolve_timeout = resolve;
1478
1479 if (send < 0) send = 0;
1480 session->send_timeout = send;
1481
1482 if (receive < 0) receive = 0;
1483 session->recv_timeout = receive;
1484 break;
1485
1486 default:
1487 release_object( hdr );
1488 set_last_error( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
1489 return FALSE;
1490 }
1491 return ret;
1492 }
1493
1494 static const WCHAR wkday[7][4] =
1495 {{'S','u','n', 0}, {'M','o','n', 0}, {'T','u','e', 0}, {'W','e','d', 0},
1496 {'T','h','u', 0}, {'F','r','i', 0}, {'S','a','t', 0}};
1497 static const WCHAR month[12][4] =
1498 {{'J','a','n', 0}, {'F','e','b', 0}, {'M','a','r', 0}, {'A','p','r', 0},
1499 {'M','a','y', 0}, {'J','u','n', 0}, {'J','u','l', 0}, {'A','u','g', 0},
1500 {'S','e','p', 0}, {'O','c','t', 0}, {'N','o','v', 0}, {'D','e','c', 0}};
1501
1502 /***********************************************************************
1503 * WinHttpTimeFromSystemTime (WININET.@)
1504 */
1505 BOOL WINAPI WinHttpTimeFromSystemTime( const SYSTEMTIME *time, LPWSTR string )
1506 {
1507 static const WCHAR format[] =
1508 {'%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
1509 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0};
1510
1511 TRACE("%p, %p\n", time, string);
1512
1513 if (!time || !string) return FALSE;
1514
1515 sprintfW( string, format,
1516 wkday[time->wDayOfWeek],
1517 time->wDay,
1518 month[time->wMonth - 1],
1519 time->wYear,
1520 time->wHour,
1521 time->wMinute,
1522 time->wSecond );
1523
1524 return TRUE;
1525 }
1526
1527 /***********************************************************************
1528 * WinHttpTimeToSystemTime (WININET.@)
1529 */
1530 BOOL WINAPI WinHttpTimeToSystemTime( LPCWSTR string, SYSTEMTIME *time )
1531 {
1532 unsigned int i;
1533 const WCHAR *s = string;
1534 WCHAR *end;
1535
1536 TRACE("%s, %p\n", debugstr_w(string), time);
1537
1538 if (!string || !time) return FALSE;
1539
1540 /* Windows does this too */
1541 GetSystemTime( time );
1542
1543 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
1544 * a SYSTEMTIME structure.
1545 */
1546
1547 while (*s && !isalphaW( *s )) s++;
1548 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
1549 time->wDayOfWeek = 7;
1550
1551 for (i = 0; i < 7; i++)
1552 {
1553 if (toupperW( wkday[i][0] ) == toupperW( s[0] ) &&
1554 toupperW( wkday[i][1] ) == toupperW( s[1] ) &&
1555 toupperW( wkday[i][2] ) == toupperW( s[2] ) )
1556 {
1557 time->wDayOfWeek = i;
1558 break;
1559 }
1560 }
1561
1562 if (time->wDayOfWeek > 6) return TRUE;
1563 while (*s && !isdigitW( *s )) s++;
1564 time->wDay = strtolW( s, &end, 10 );
1565 s = end;
1566
1567 while (*s && !isalphaW( *s )) s++;
1568 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
1569 time->wMonth = 0;
1570
1571 for (i = 0; i < 12; i++)
1572 {
1573 if (toupperW( month[i][0]) == toupperW( s[0] ) &&
1574 toupperW( month[i][1]) == toupperW( s[1] ) &&
1575 toupperW( month[i][2]) == toupperW( s[2] ) )
1576 {
1577 time->wMonth = i + 1;
1578 break;
1579 }
1580 }
1581 if (time->wMonth == 0) return TRUE;
1582
1583 while (*s && !isdigitW( *s )) s++;
1584 if (*s == '\0') return TRUE;
1585 time->wYear = strtolW( s, &end, 10 );
1586 s = end;
1587
1588 while (*s && !isdigitW( *s )) s++;
1589 if (*s == '\0') return TRUE;
1590 time->wHour = strtolW( s, &end, 10 );
1591 s = end;
1592
1593 while (*s && !isdigitW( *s )) s++;
1594 if (*s == '\0') return TRUE;
1595 time->wMinute = strtolW( s, &end, 10 );
1596 s = end;
1597
1598 while (*s && !isdigitW( *s )) s++;
1599 if (*s == '\0') return TRUE;
1600 time->wSecond = strtolW( s, &end, 10 );
1601 s = end;
1602
1603 time->wMilliseconds = 0;
1604 return TRUE;
1605 }