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