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