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