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