Changeset 57726 in vbox for trunk/src/VBox/Runtime/common/misc/http.cpp
- Timestamp:
- Sep 12, 2015 12:01:23 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/http.cpp
r57720 r57726 42 42 #include <iprt/stream.h> 43 43 #include <iprt/string.h> 44 #include <iprt/uri.h> 44 45 45 46 #include "internal/magics.h" … … 68 69 /** Whether to delete the CA on destruction. */ 69 70 bool fDeleteCaFile; 71 72 /** @name Proxy settings. 73 * When fUseSystemProxySettings is set, the other members will be updated each 74 * time we're presented with a new URL. The members reflect the cURL 75 * configuration. 76 * 77 * @{ */ 70 78 /** Set if we should use the system proxy settings for a URL. 71 79 * This means reconfiguring cURL for each request. */ 72 80 bool fUseSystemProxySettings; 81 /** Set if we've detected no proxy necessary. */ 82 bool fNoProxy; 83 /** Proxy host name (RTStrFree). */ 84 char *pszProxyHost; 85 /** Proxy port number (UINT32_MAX if not specified). */ 86 uint32_t uProxyPort; 87 /** The proxy type (CURLPROXY_HTTP, CURLPROXY_SOCKS5, ++). */ 88 curl_proxytype enmProxyType; 89 /** Proxy username (RTStrFree). */ 90 char *pszProxyUsername; 91 /** Proxy password (RTStrFree). */ 92 char *pszProxyPassword; 93 /** @} */ 94 73 95 /** Abort the current HTTP request if true. */ 74 96 bool volatile fAbort; … … 238 260 PRTHTTPINTERNAL pThis = hHttp; 239 261 RTHTTP_VALID_RETURN(pThis); 240 241 /* 242 * Very limited right now, just enought to make it work for ourselves. 243 */ 244 char szProxy[_1K]; 245 int rc = RTEnvGetEx(RTENV_DEFAULT, "http_proxy", szProxy, sizeof(szProxy), NULL); 246 if (RT_SUCCESS(rc)) 247 { 248 int rcCurl; 249 if (!strncmp(szProxy, RT_STR_TUPLE("http://"))) 250 { 251 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); 252 if (CURL_FAILURE(rcCurl)) 253 return VERR_INVALID_PARAMETER; 254 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, 80); 255 if (CURL_FAILURE(rcCurl)) 256 return VERR_INVALID_PARAMETER; 257 } 258 else 259 { 260 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); 261 if (CURL_FAILURE(rcCurl)) 262 return VERR_INVALID_PARAMETER; 263 } 264 } 265 else if (rc == VERR_ENV_VAR_NOT_FOUND) 266 rc = VINF_SUCCESS; 267 268 return rc; 262 AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER); 263 264 /* 265 * Change the settings. 266 */ 267 pThis->fUseSystemProxySettings = true; 268 return VINF_SUCCESS; 269 } 270 271 272 /** 273 * rtHttpConfigureProxyForUrl: Update cURL proxy settings as needed. 274 * 275 * @returns IPRT status code. 276 * @param pThis The HTTP client instance. 277 * @param enmProxyType The proxy type. 278 * @param pszHost The proxy host name. If NULL, the proxying will be 279 * disabled. 280 * @param uPort The proxy port number. 281 * @param pszUsername The proxy username, or NULL if none. 282 * @param pszPassword The proxy password, or NULL if none. 283 */ 284 static int rtHttpUpdateProxyConfig(PRTHTTPINTERNAL pThis, curl_proxytype enmProxyType, const char *pszHost, 285 uint32_t uPort, const char *pszUsername, const char *pszPassword) 286 { 287 int rcCurl; 288 289 if (enmProxyType != pThis->enmProxyType) 290 { 291 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYTYPE, (long)enmProxyType); 292 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYTYPE=%d: %d (%#x)\n", enmProxyType, rcCurl, rcCurl), 293 VERR_HTTP_CURL_PROXY_CONFIG); 294 pThis->enmProxyType = CURLPROXY_HTTP; 295 } 296 297 if (uPort != pThis->uProxyPort) 298 { 299 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)uPort); 300 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYPORT=%d: %d (%#x)\n", uPort, rcCurl, rcCurl), 301 VERR_HTTP_CURL_PROXY_CONFIG); 302 pThis->uProxyPort = uPort; 303 } 304 305 if ( pszUsername != pThis->pszProxyUsername 306 || RTStrCmp(pszUsername, pThis->pszProxyUsername)) 307 { 308 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, pszUsername); 309 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYUSERNAME=%s: %d (%#x)\n", pszUsername, rcCurl, rcCurl), 310 VERR_HTTP_CURL_PROXY_CONFIG); 311 if (pThis->pszProxyUsername) 312 { 313 RTStrFree(pThis->pszProxyUsername); 314 pThis->pszProxyUsername = NULL; 315 } 316 if (pszUsername) 317 { 318 pThis->pszProxyUsername = RTStrDup(pszUsername); 319 AssertReturn(pThis->pszProxyUsername, VERR_NO_STR_MEMORY); 320 } 321 } 322 323 if ( pszPassword != pThis->pszProxyPassword 324 || RTStrCmp(pszPassword, pThis->pszProxyPassword)) 325 { 326 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, pszPassword); 327 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYPASSWORD=%s: %d (%#x)\n", pszPassword ? "xxx" : NULL, rcCurl, rcCurl), 328 VERR_HTTP_CURL_PROXY_CONFIG); 329 if (pThis->pszProxyPassword) 330 { 331 RTMemWipeThoroughly(pThis->pszProxyPassword, strlen(pThis->pszProxyPassword), 2); 332 RTStrFree(pThis->pszProxyPassword); 333 pThis->pszProxyPassword = NULL; 334 } 335 if (pszPassword) 336 { 337 pThis->pszProxyPassword = RTStrDup(pszPassword); 338 AssertReturn(pThis->pszProxyPassword, VERR_NO_STR_MEMORY); 339 } 340 } 341 342 if ( pszHost != pThis->pszProxyHost 343 || RTStrCmp(pszHost, pThis->pszProxyHost)) 344 { 345 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, pszHost); 346 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXY=%s: %d (%#x)\n", pszHost, rcCurl, rcCurl), 347 VERR_HTTP_CURL_PROXY_CONFIG); 348 if (pThis->pszProxyHost) 349 { 350 RTStrFree(pThis->pszProxyHost); 351 pThis->pszProxyHost = NULL; 352 } 353 if (pszHost) 354 { 355 pThis->pszProxyHost = RTStrDup(pszHost); 356 AssertReturn(pThis->pszProxyHost, VERR_NO_STR_MEMORY); 357 } 358 } 359 360 return VINF_SUCCESS; 361 } 362 363 364 /** 365 * rtHttpConfigureProxyForUrl: Disables proxying. 366 * 367 * @returns IPRT status code. 368 * @param pThis The HTTP client instance. 369 */ 370 static int rtHttpUpdateAutomaticProxyDisable(PRTHTTPINTERNAL pThis) 371 { 372 AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTP) == CURLE_OK, VERR_INTERNAL_ERROR_2); 373 pThis->enmProxyType = CURLPROXY_HTTP; 374 375 AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)1080) == CURLE_OK, VERR_INTERNAL_ERROR_2); 376 pThis->uProxyPort = 1080; 377 378 AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2); 379 if (pThis->pszProxyUsername) 380 { 381 RTStrFree(pThis->pszProxyUsername); 382 pThis->pszProxyUsername = NULL; 383 } 384 385 AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2); 386 if (pThis->pszProxyPassword) 387 { 388 RTStrFree(pThis->pszProxyPassword); 389 pThis->pszProxyPassword = NULL; 390 } 391 392 AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2); 393 if (pThis->pszProxyHost) 394 { 395 RTStrFree(pThis->pszProxyHost); 396 pThis->pszProxyHost = NULL; 397 } 398 return VINF_SUCCESS; 269 399 } 270 400 … … 277 407 278 408 279 static int rtHttpConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl) 280 { 281 const char *pszProxy = NULL; 282 long uPort = 0; 283 const char *pszUser = NULL; 284 const char *pszPassword = NULL; 285 bool fNoProxy = true; 286 287 409 410 /** 411 * Consults enviornment variables that cURL/lynx/wget/lynx uses for figuring out 412 * the proxy config. 413 * 414 * @returns IPRT status code. 415 * @param pThis The HTTP client instance. 416 * @param pszUrl The URL to configure a proxy for. 417 */ 418 static int rtHttpConfigureProxyForUrlFromEnv(PRTHTTPINTERNAL pThis, const char *pszUrl) 419 { 288 420 char szTmp[_1K]; 289 421 … … 305 437 } 306 438 AssertMsg(rc == VINF_SUCCESS || rc == VERR_ENV_VAR_NOT_FOUND, ("rc=%Rrc\n", rc)); 307 fNoProxy = rtHttpUrlInNoProxyList(pszUrl, pszNoProxy);308 RTMemTmpFree(pszNoProxy );439 bool fNoProxy = rtHttpUrlInNoProxyList(pszUrl, pszNoProxy); 440 RTMemTmpFree(pszNoProxyFree); 309 441 if (!fNoProxy) 310 442 { … … 332 464 apszEnvVars[cEnvVars++] = "ALL_PROXY"; 333 465 466 /* 467 * We try the env vars out and goes with the first one we can make sense out of. 468 * If we cannot make sense of any, we return the first unexpected rc we got. 469 */ 470 rc = VINF_SUCCESS; 334 471 for (uint32_t i = 0; i < cEnvVars; i++) 335 472 { 336 473 size_t cchValue; 337 rc= RTEnvGetEx(RTENV_DEFAULT, apszEnvVars[i], szTmp, sizeof(szTmp) - sizeof("http://"), &cchValue);338 if (RT_SUCCESS(rc ))474 int rc2 = RTEnvGetEx(RTENV_DEFAULT, apszEnvVars[i], szTmp, sizeof(szTmp) - sizeof("http://"), &cchValue); 475 if (RT_SUCCESS(rc2)) 339 476 { 340 if ( !strstr(szTmp, "://"))477 if (cchValue != 0) 341 478 { 342 memmove(&szTmp[sizeof("http://") - 1], szTmp, cchValue + 1); 343 memcpy(szTmp, RT_STR_TUPLE("http://")); 479 /* Add a http:// prefix so RTUriParse groks it. */ 480 if (!strstr(szTmp, "://")) 481 { 482 memmove(&szTmp[sizeof("http://") - 1], szTmp, cchValue + 1); 483 memcpy(szTmp, RT_STR_TUPLE("http://")); 484 } 485 486 RTURIPARSED Parsed; 487 rc2 = RTUriParse(szTmp, &Parsed); 488 if (RT_SUCCESS(rc)) 489 { 490 bool fDone = false; 491 char *pszHost = RTUriParsedAuthorityHost(szTmp, &Parsed); 492 if (pszHost) 493 { 494 /* 495 * We've got a host name, try get the rest. 496 */ 497 char *pszUsername = RTUriParsedAuthorityUsername(szTmp, &Parsed); 498 char *pszPassword = RTUriParsedAuthorityPassword(szTmp, &Parsed); 499 uint32_t uProxyPort = RTUriParsedAuthorityPort(szTmp, &Parsed); 500 curl_proxytype enmProxyType; 501 if (RTUriIsSchemeMatch(szTmp, "http")) 502 enmProxyType = CURLPROXY_HTTP; 503 else if ( RTUriIsSchemeMatch(szTmp, "socks4") 504 || RTUriIsSchemeMatch(szTmp, "socks")) 505 enmProxyType = CURLPROXY_SOCKS4; 506 else if (RTUriIsSchemeMatch(szTmp, "socks4a")) 507 enmProxyType = CURLPROXY_SOCKS4A; 508 else if (RTUriIsSchemeMatch(szTmp, "socks5")) 509 enmProxyType = CURLPROXY_SOCKS5; 510 else if (RTUriIsSchemeMatch(szTmp, "socks5h")) 511 enmProxyType = CURLPROXY_SOCKS5_HOSTNAME; 512 else 513 enmProxyType = CURLPROXY_HTTP; 514 515 /* Guess the port from the proxy type if not given. */ 516 if (uProxyPort == UINT32_MAX) 517 switch (enmProxyType) 518 { 519 case CURLPROXY_HTTP: uProxyPort = 80; break; 520 default: uProxyPort = 1080 /* CURL_DEFAULT_PROXY_PORT */; break; 521 } 522 523 rc2 = rtHttpUpdateProxyConfig(pThis, enmProxyType, pszHost, uProxyPort, pszUsername, pszPassword); 524 525 RTStrFree(pszUsername); 526 RTStrFree(pszPassword); 527 RTStrFree(pszHost); 528 529 /* If that succeeded we're done. */ 530 if (RT_SUCCESS(rc2)) 531 { 532 rc = rc2; 533 break; 534 } 535 536 if (RT_SUCCESS(rc)) 537 rc = rc2; 538 } 539 else 540 AssertMsgFailed(("RTUriParsedAuthorityHost('%s',) -> NULL\n", szTmp)); 541 } 542 else 543 { 544 AssertMsgFailed(("RTUriParse('%s',) -> %Rrc\n", szTmp, rc2)); 545 if (RT_SUCCESS(rc)) 546 rc = rc2; 547 } 344 548 } 345 /** @todo continue where using RTUriParse... */ 549 /* 550 * The variable is empty. Guess that means no proxying wanted. 551 */ 552 else 553 { 554 rc = rtHttpUpdateAutomaticProxyDisable(pThis); 555 break; 556 } 346 557 } 347 558 else 348 AssertMsg(rc == VERR_ENV_VAR_NOT_FOUND, ("%Rrc\n")); 349 } 350 351 #if 0 352 if (RT_SUCCESS(rc)) 353 { 354 int rcCurl; 355 if (!strncmp(szProxy, RT_STR_TUPLE("http://"))) 356 { 357 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); 358 if (CURL_FAILURE(rcCurl)) 359 return VERR_INVALID_PARAMETER; 360 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, 80); 361 if (CURL_FAILURE(rcCurl)) 362 return VERR_INVALID_PARAMETER; 363 } 364 else 365 { 366 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]); 367 if (CURL_FAILURE(rcCurl)) 368 return VERR_INVALID_PARAMETER; 369 } 370 } 371 else if (rc == VERR_ENV_VAR_NOT_FOUND) 372 rc = VINF_SUCCESS; 373 #endif 374 } 559 AssertMsgStmt(rc2 == VERR_ENV_VAR_NOT_FOUND, ("%Rrc\n", rc2), if (RT_SUCCESS(rc)) rc = rc2); 560 } 561 } 562 /* 563 * The host is the no-proxy list, it seems. 564 */ 565 else 566 rc = rtHttpUpdateAutomaticProxyDisable(pThis); 375 567 376 568 return rc; 569 } 570 571 572 static int rtHttpConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl) 573 { 574 if (pThis->fUseSystemProxySettings) 575 { 576 /** @todo system specific class here, fall back on env vars if necessary. */ 577 return rtHttpConfigureProxyForUrlFromEnv(pThis, pszUrl); 578 } 579 580 return VINF_SUCCESS; 377 581 } 378 582 … … 384 588 RTHTTP_VALID_RETURN(pThis); 385 589 AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER); 386 387 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, pcszProxy); 388 if (CURL_FAILURE(rcCurl)) 389 return VERR_INVALID_PARAMETER; 390 391 if (uPort != 0) 392 { 393 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)uPort); 394 if (CURL_FAILURE(rcCurl)) 395 return VERR_INVALID_PARAMETER; 396 } 397 398 if (pcszProxyUser && pcszProxyPwd) 399 { 400 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser); 401 if (CURL_FAILURE(rcCurl)) 402 return VERR_INVALID_PARAMETER; 403 404 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd); 405 if (CURL_FAILURE(rcCurl)) 406 return VERR_INVALID_PARAMETER; 407 } 408 409 return VINF_SUCCESS; 590 AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER); 591 592 /* 593 * Update the settings. 594 * 595 * Currently, we don't make alot of effort parsing or checking the input, we 596 * leave that to cURL. (A bit afraid of breaking user settings.) 597 */ 598 pThis->fUseSystemProxySettings = false; 599 return rtHttpUpdateProxyConfig(pThis, CURLPROXY_HTTP, pcszProxy, uPort ? uPort : 1080, pcszProxyUser, pcszProxyPwd); 410 600 } 411 601 … … 599 789 static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl) 600 790 { 601 int rc = VERR_ INTERNAL_ERROR;791 int rc = VERR_HTTP_CURL_ERROR; 602 792 603 793 if (pThis->pszRedirLocation) … … 728 918 729 919 /* 920 * Proxy config. 921 */ 922 int rc = rtHttpConfigureProxyForUrl(pThis, pszUrl); 923 if (RT_FAILURE(rc)) 924 return rc; 925 926 /* 730 927 * Setup SSL. Can be a bit of work. 731 928 */ … … 738 935 && rtHttpNeedSsl(pszUrl)) 739 936 { 740 intrc = RTHttpUseTemporaryCaFile(pThis, NULL);937 rc = RTHttpUseTemporaryCaFile(pThis, NULL); 741 938 if (RT_SUCCESS(rc)) 742 939 pszCaFile = pThis->pszCaFile; … … 748 945 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CAINFO, pszCaFile); 749 946 if (CURL_FAILURE(rcCurl)) 750 return VERR_ INTERNAL_ERROR;947 return VERR_HTTP_CURL_ERROR; 751 948 } 752 949 … … 756 953 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress); 757 954 if (CURL_FAILURE(rcCurl)) 758 return VERR_ INTERNAL_ERROR;955 return VERR_HTTP_CURL_ERROR; 759 956 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSDATA, (void *)pThis); 760 957 if (CURL_FAILURE(rcCurl)) 761 return VERR_ INTERNAL_ERROR;958 return VERR_HTTP_CURL_ERROR; 762 959 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROGRESS, (long)0); 763 960 if (CURL_FAILURE(rcCurl)) 764 return VERR_ INTERNAL_ERROR;961 return VERR_HTTP_CURL_ERROR; 765 962 766 963 return VINF_SUCCESS; … … 895 1092 } 896 1093 else 897 rc = VERR_ INTERNAL_ERROR_3;1094 rc = VERR_HTTP_CURL_ERROR; 898 1095 } 899 1096 … … 1002 1199 } 1003 1200 else 1004 rc = VERR_ INTERNAL_ERROR_3;1201 rc = VERR_HTTP_CURL_ERROR; 1005 1202 } 1006 1203
Note:
See TracChangeset
for help on using the changeset viewer.