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