Changeset 73967 in vbox for trunk/src/VBox
- Timestamp:
- Aug 29, 2018 7:12:41 PM (6 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp
r73918 r73967 125 125 */ 126 126 uint32_t uHttpStatus = 0; 127 rc = RTHttpPerform(hHttp, strFullUrl.c_str(), a_enmHttpMethod, 127 rc = RTHttpPerform(hHttp, strFullUrl.c_str(), a_enmHttpMethod, strXmitBody.c_str(), strXmitBody.length(), 128 128 &uHttpStatus, ppvHdrs, &cbHdrs, ppvBody, &cbBody); 129 129 if (RT_SUCCESS(rc)) -
trunk/src/VBox/Runtime/generic/http-curl.cpp
r73918 r73967 81 81 * Structures and Typedefs * 82 82 *********************************************************************************************************************************/ 83 /** Output collection data. */ 84 typedef struct RTHTTPOUTPUTDATA 85 { 86 /** Pointer to the HTTP client instance structure. */ 87 struct RTHTTPINTERNAL *pHttp; 88 /** Callback specific data. */ 89 union 90 { 91 /** For file destination. */ 92 RTFILE hFile; 93 /** For memory destination. */ 94 struct 95 { 96 /** The current size (sans terminator char). */ 97 size_t cb; 98 /** The currently allocated size. */ 99 size_t cbAllocated; 100 /** Pointer to the buffer. */ 101 uint8_t *pb; 102 } Mem; 103 } uData; 104 } RTHTTPOUTPUTDATA; 105 83 106 /** 84 107 * Internal HTTP client instance. … … 141 164 char *pszRedirLocation; 142 165 143 /** Output callback data. */144 166 union 145 167 { 146 /** For file destination. */147 RTFILE hFile;148 /** For memory destination. */149 168 struct 150 169 { 151 /** The current size (sans terminator char). */152 size_t cb;153 /** The currently allocated size. */154 size_t cb Allocated;155 /** Pointer to the buffer. */156 uint8_t *pb;170 /** Pointer to the memory block we're feeding the cURL/server. */ 171 void const *pvMem; 172 /** Size of the memory block. */ 173 size_t cbMem; 174 /** Current memory block offset. */ 175 size_t offMem; 157 176 } Mem; 158 } Output; 159 /** Output callback status. */ 177 } ReadData; 178 179 /** Body output callback data. */ 180 RTHTTPOUTPUTDATA BodyOutput; 181 /** Headers output callback data. */ 182 RTHTTPOUTPUTDATA HeadersOutput; 183 /** The output status.*/ 160 184 int rcOutput; 185 161 186 /** Download size hint set by the progress callback. */ 162 187 uint64_t cbDownloadHint; … … 260 285 static int rtHttpDarwinTryConfigProxies(PRTHTTPINTERNAL pThis, CFArrayRef hArrayProxies, CFURLRef hUrlTarget, bool fIgnorePacType); 261 286 #endif 262 static CURLcode rtHttpSetWriteCallback(PRTHTTPINTERNAL pThis, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser);263 287 264 288 … … 271 295 int rc = VERR_HTTP_INIT_FAILED; 272 296 CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL); 273 if ( !CURL_FAILURE(rcCurl))297 if (CURL_SUCCESS(rcCurl)) 274 298 { 275 299 CURL *pCurl = curl_easy_init(); … … 283 307 pThis->fUseSystemProxySettings = true; 284 308 pThis->cMaxRedirects = 0; /* no automatic redir following */ 309 pThis->BodyOutput.pHttp = pThis; 310 pThis->HeadersOutput.pHttp = pThis; 285 311 286 312 *phHttp = (RTHTTP)pThis; … … 386 412 } 387 413 414 415 RTR3DECL(int) RTHttpSetFollowRedirects(RTHTTP hHttp, uint32_t cMaxRedirects) 416 { 417 PRTHTTPINTERNAL pThis = hHttp; 418 RTHTTP_VALID_RETURN(pThis); 419 AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER); 420 421 /* 422 * Update the redirection settings. 423 */ 424 if (pThis->cMaxRedirects != cMaxRedirects) 425 { 426 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_MAXREDIRS, (long)cMaxRedirects); 427 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_MAXREDIRS=%u: %d (%#x)\n", cMaxRedirects, rcCurl, rcCurl), 428 VERR_HTTP_CURL_ERROR); 429 430 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_FOLLOWLOCATION, (long)(cMaxRedirects > 0)); 431 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_FOLLOWLOCATION=%d: %d (%#x)\n", cMaxRedirects > 0, rcCurl, rcCurl), 432 VERR_HTTP_CURL_ERROR); 433 434 pThis->cMaxRedirects = cMaxRedirects; 435 } 436 return VINF_SUCCESS; 437 } 438 439 440 /********************************************************************************************************************************* 441 * Proxy handling. * 442 *********************************************************************************************************************************/ 388 443 389 444 RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp) … … 1862 1917 1863 1918 1864 RTR3DECL(int) RTHttpSetFollowRedirects(RTHTTP hHttp, uint32_t cMaxRedirects) 1865 { 1866 PRTHTTPINTERNAL pThis = hHttp; 1867 RTHTTP_VALID_RETURN(pThis); 1868 AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER); 1869 1870 /* 1871 * Update the redirection settings. 1872 */ 1873 if (pThis->cMaxRedirects != cMaxRedirects) 1874 { 1875 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_MAXREDIRS, (long)cMaxRedirects); 1876 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_MAXREDIRS=%u: %d (%#x)\n", cMaxRedirects, rcCurl, rcCurl), 1877 VERR_HTTP_CURL_ERROR); 1878 1879 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_FOLLOWLOCATION, (long)(cMaxRedirects > 0)); 1880 AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_FOLLOWLOCATION=%d: %d (%#x)\n", cMaxRedirects > 0, rcCurl, rcCurl), 1881 VERR_HTTP_CURL_ERROR); 1882 1883 pThis->cMaxRedirects = cMaxRedirects; 1884 } 1885 return VINF_SUCCESS; 1886 } 1887 1919 1920 /********************************************************************************************************************************* 1921 * HTTP Headers * 1922 *********************************************************************************************************************************/ 1888 1923 1889 1924 /** … … 2050 2085 } 2051 2086 2087 2088 2089 /********************************************************************************************************************************* 2090 * HTTPS and root certficates * 2091 *********************************************************************************************************************************/ 2052 2092 2053 2093 /** … … 2206 2246 2207 2247 2248 /********************************************************************************************************************************* 2249 * ....... 2250 *********************************************************************************************************************************/ 2251 2252 2208 2253 /** 2209 2254 * Figures out the IPRT status code for a GET. … … 2212 2257 * @param pThis The HTTP/HTTPS client instance. 2213 2258 * @param rcCurl What curl returned. 2214 */ 2215 static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl) 2259 * @param puHttpStatus Where to optionally return the HTTP status. If specified, 2260 * the HTTP statuses are not translated to IPRT status codes. 2261 */ 2262 static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl, uint32_t *puHttpStatus) 2216 2263 { 2217 2264 int rc = VERR_HTTP_CURL_ERROR; … … 2225 2272 { 2226 2273 curl_easy_getinfo(pThis->pCurl, CURLINFO_RESPONSE_CODE, &pThis->lLastResp); 2274 if (puHttpStatus) 2275 { 2276 *puHttpStatus = pThis->lLastResp; 2277 rc = VINF_SUCCESS; 2278 } 2279 2227 2280 switch (pThis->lLastResp) 2228 2281 { … … 2244 2297 if (cb > 0 && cb < 2048) 2245 2298 pThis->pszRedirLocation = RTStrDup(pszRedirect); 2246 rc = VERR_HTTP_REDIRECTED; 2299 if (!puHttpStatus) 2300 rc = VERR_HTTP_REDIRECTED; 2247 2301 break; 2248 2302 } 2249 2303 case 400: 2250 2304 /* bad request */ 2251 rc = VERR_HTTP_BAD_REQUEST; 2305 if (!puHttpStatus) 2306 rc = VERR_HTTP_BAD_REQUEST; 2252 2307 break; 2253 2308 case 403: 2254 2309 /* forbidden, authorization will not help */ 2255 rc = VERR_HTTP_ACCESS_DENIED; 2310 if (!puHttpStatus) 2311 rc = VERR_HTTP_ACCESS_DENIED; 2256 2312 break; 2257 2313 case 404: 2258 2314 /* URL not found */ 2259 rc = VERR_HTTP_NOT_FOUND; 2315 if (!puHttpStatus) 2316 rc = VERR_HTTP_NOT_FOUND; 2260 2317 break; 2261 2318 } … … 2430 2487 2431 2488 /** 2489 * Resets state. 2490 * 2491 * @param pThis HTTP client instance. 2492 */ 2493 static void rtHttpResetState(PRTHTTPINTERNAL pThis) 2494 { 2495 pThis->fAbort = false; 2496 pThis->rcOutput = VINF_SUCCESS; 2497 pThis->cbDownloadHint = 0; 2498 Assert(pThis->BodyOutput.pHttp == pThis); 2499 Assert(pThis->HeadersOutput.pHttp == pThis); 2500 } 2501 2502 2503 2504 /** 2432 2505 * cURL callback for writing data. 2433 2506 */ 2434 2507 static size_t rtHttpWriteData(char *pcBuf, size_t cbUnit, size_t cUnits, void *pvUser) 2435 2508 { 2436 PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser; 2509 RTHTTPOUTPUTDATA *pOutput = (RTHTTPOUTPUTDATA *)pvUser; 2510 PRTHTTPINTERNAL pThis = pOutput->pHttp; 2437 2511 2438 2512 /* … … 2440 2514 */ 2441 2515 size_t const cbToAppend = cbUnit * cUnits; 2442 size_t const cbCurSize = p This->Output.Mem.cb;2516 size_t const cbCurSize = pOutput->uData.Mem.cb; 2443 2517 size_t const cbNewSize = cbCurSize + cbToAppend; 2444 2518 if ( cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2445 2519 && cbNewSize < RTHTTP_MAX_MEM_DOWNLOAD_SIZE) 2446 2520 { 2447 if (cbNewSize + 1 <= p This->Output.Mem.cbAllocated)2448 { 2449 memcpy(&p This->Output.Mem.pb[cbCurSize], pcBuf, cbToAppend);2450 p This->Output.Mem.cb = cbNewSize;2451 p This->Output.Mem.pb[cbNewSize] = '\0';2521 if (cbNewSize + 1 <= pOutput->uData.Mem.cbAllocated) 2522 { 2523 memcpy(&pOutput->uData.Mem.pb[cbCurSize], pcBuf, cbToAppend); 2524 pOutput->uData.Mem.cb = cbNewSize; 2525 pOutput->uData.Mem.pb[cbNewSize] = '\0'; 2452 2526 return cbToAppend; 2453 2527 } … … 2459 2533 size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64); 2460 2534 if ( cbAlloc <= pThis->cbDownloadHint 2461 && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE) 2535 && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2536 && pOutput == &pThis->BodyOutput) 2462 2537 cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64); 2463 2538 2464 uint8_t *pbNew = (uint8_t *)RTMemRealloc(p This->Output.Mem.pb, cbAlloc);2539 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pOutput->uData.Mem.pb, cbAlloc); 2465 2540 if (pbNew) 2466 2541 { … … 2468 2543 pbNew[cbNewSize] = '\0'; 2469 2544 2470 p This->Output.Mem.cbAllocated = cbAlloc;2471 p This->Output.Mem.pb = pbNew;2472 p This->Output.Mem.cb = cbNewSize;2545 pOutput->uData.Mem.cbAllocated = cbAlloc; 2546 pOutput->uData.Mem.pb = pbNew; 2547 pOutput->uData.Mem.cb = cbNewSize; 2473 2548 return cbToAppend; 2474 2549 } … … 2482 2557 * Failure - abort. 2483 2558 */ 2484 RTMemFree(p This->Output.Mem.pb);2485 p This->Output.Mem.pb = NULL;2486 p This->Output.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE;2487 pThis->fAbort 2559 RTMemFree(pOutput->uData.Mem.pb); 2560 pOutput->uData.Mem.pb = NULL; 2561 pOutput->uData.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE; 2562 pThis->fAbort = true; 2488 2563 return 0; 2564 } 2565 2566 2567 /** 2568 * Callback feeding cURL data from RTHTTPINTERNAL::ReadData::Mem. 2569 */ 2570 static size_t rtHttpReadData(void *pvDst, size_t cbUnit, size_t cUnits, void *pvUser) 2571 { 2572 PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser; 2573 size_t const cbReq = cbUnit * cUnits; 2574 size_t const offMem = pThis->ReadData.Mem.offMem; 2575 size_t cbToCopy = pThis->ReadData.Mem.cbMem - offMem; 2576 if (cbToCopy > cbReq) 2577 cbToCopy = cbReq; 2578 memcpy(pvDst, (uint8_t const *)pThis->ReadData.Mem.pvMem + offMem, cbToCopy); 2579 pThis->ReadData.Mem.offMem = offMem + cbToCopy; 2580 return cbToCopy; 2581 } 2582 2583 2584 /** 2585 * Helper for installing a (body) write callback function. 2586 * 2587 * @returns cURL status code. 2588 * @param pThis The HTTP client instance. 2589 * @param pfnWrite The callback. 2590 * @param pvUser The callback user argument. 2591 */ 2592 static CURLcode rtHttpSetWriteCallback(PRTHTTPINTERNAL pThis, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser) 2593 { 2594 CURLcode rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, pfnWrite); 2595 if (CURL_SUCCESS(rcCurl)) 2596 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, pvUser); 2597 return rcCurl; 2598 } 2599 2600 2601 /** 2602 * Helper for installing a header write callback function. 2603 * 2604 * @returns cURL status code. 2605 * @param pThis The HTTP client instance. 2606 * @param pfnWrite The callback. 2607 * @param pvUser The callback user argument. 2608 */ 2609 static CURLcode rtHttpSetHeaderCallback(PRTHTTPINTERNAL pThis, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser) 2610 { 2611 CURLcode rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HEADERFUNCTION, pfnWrite); 2612 if (CURL_SUCCESS(rcCurl)) 2613 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HEADERDATA, pvUser); 2614 return rcCurl; 2615 } 2616 2617 2618 /** 2619 * Helper for installing a (body) read callback function. 2620 * 2621 * @returns cURL status code. 2622 * @param pThis The HTTP client instance. 2623 * @param pfnRead The callback. 2624 * @param pvUser The callback user argument. 2625 */ 2626 static CURLcode rtHttpSetReadCallback(PRTHTTPINTERNAL pThis, PFNRTHTTPREADCALLBACK pfnRead, void *pvUser) 2627 { 2628 CURLcode rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_READFUNCTION, pfnRead); 2629 if (CURL_SUCCESS(rcCurl)) 2630 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_READDATA, pvUser); 2631 return rcCurl; 2489 2632 } 2490 2633 … … 2527 2670 * Reset the state and apply settings. 2528 2671 */ 2529 pThis->fAbort = false; 2530 pThis->rcOutput = VINF_SUCCESS; 2531 pThis->cbDownloadHint = 0; 2532 2672 rtHttpResetState(pThis); 2533 2673 int rc = rtHttpApplySettings(hHttp, pszUrl); 2534 2674 if (RT_SUCCESS(rc)) 2535 2675 { 2536 RT_ZERO(pThis-> Output.Mem);2537 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteData, (void *) pThis);2676 RT_ZERO(pThis->BodyOutput.uData.Mem); 2677 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteData, (void *)&pThis->BodyOutput); 2538 2678 if (fNoBody) 2539 2679 { 2540 if ( !CURL_FAILURE(rcCurl))2680 if (CURL_SUCCESS(rcCurl)) 2541 2681 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOBODY, 1L); 2542 if ( !CURL_FAILURE(rcCurl))2682 if (CURL_SUCCESS(rcCurl)) 2543 2683 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HEADER, 1L); 2544 2684 } 2545 if ( !CURL_FAILURE(rcCurl))2685 if (CURL_SUCCESS(rcCurl)) 2546 2686 { 2547 2687 /* … … 2549 2689 */ 2550 2690 rcCurl = curl_easy_perform(pThis->pCurl); 2551 rc = rtHttpGetCalcStatus(pThis, rcCurl );2691 rc = rtHttpGetCalcStatus(pThis, rcCurl, NULL); 2552 2692 if (RT_SUCCESS(rc)) 2553 2693 rc = pThis->rcOutput; 2554 2694 if (RT_SUCCESS(rc)) 2555 2695 { 2556 *ppvResponse = pThis->Output.Mem.pb; 2557 *pcb = pThis->Output.Mem.cb; 2558 Log(("rtHttpGetToMem: %zx bytes (allocated %zx)\n", pThis->Output.Mem.cb, pThis->Output.Mem.cbAllocated)); 2696 *ppvResponse = pThis->BodyOutput.uData.Mem.pb; 2697 *pcb = pThis->BodyOutput.uData.Mem.cb; 2698 Log(("rtHttpGetToMem: %zx bytes (allocated %zx)\n", 2699 pThis->BodyOutput.uData.Mem.cb, pThis->BodyOutput.uData.Mem.cbAllocated)); 2559 2700 } 2560 else if (pThis-> Output.Mem.pb)2561 RTMemFree(pThis-> Output.Mem.pb);2562 RT_ZERO(pThis-> Output.Mem);2701 else if (pThis->BodyOutput.uData.Mem.pb) 2702 RTMemFree(pThis->BodyOutput.uData.Mem.pb); 2703 RT_ZERO(pThis->BodyOutput.uData.Mem); 2563 2704 } 2564 2705 else … … 2641 2782 static size_t rtHttpWriteDataToFile(char *pcBuf, size_t cbUnit, size_t cUnits, void *pvUser) 2642 2783 { 2643 PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser; 2644 size_t cbWritten = 0; 2645 int rc = RTFileWrite(pThis->Output.hFile, pcBuf, cbUnit * cUnits, &cbWritten); 2784 RTHTTPOUTPUTDATA *pOutput = (RTHTTPOUTPUTDATA *)pvUser; 2785 PRTHTTPINTERNAL pThis = pOutput->pHttp; 2786 2787 size_t cbWritten = 0; 2788 int rc = RTFileWrite(pOutput->uData.hFile, pcBuf, cbUnit * cUnits, &cbWritten); 2646 2789 if (RT_SUCCESS(rc)) 2647 2790 return cbWritten; 2791 2648 2792 Log(("rtHttpWriteDataToFile: rc=%Rrc cbUnit=%zd cUnits=%zu\n", rc, cbUnit, cUnits)); 2649 2793 pThis->rcOutput = rc; … … 2667 2811 * Reset the state and apply settings. 2668 2812 */ 2669 pThis->fAbort = false; 2670 pThis->rcOutput = VINF_SUCCESS; 2671 pThis->cbDownloadHint = 0; 2672 2813 rtHttpResetState(pThis); 2673 2814 int rc = rtHttpApplySettings(hHttp, pszUrl); 2674 2815 if (RT_SUCCESS(rc)) 2675 2816 { 2676 pThis-> Output.hFile = NIL_RTFILE;2677 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteDataToFile, (void *) pThis);2678 if ( !CURL_FAILURE(rcCurl))2817 pThis->BodyOutput.uData.hFile = NIL_RTFILE; 2818 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteDataToFile, (void *)&pThis->BodyOutput); 2819 if (CURL_SUCCESS(rcCurl)) 2679 2820 { 2680 2821 /* 2681 2822 * Open the output file. 2682 2823 */ 2683 rc = RTFileOpen(&pThis->Output.hFile, pszDstFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_READWRITE); 2824 rc = RTFileOpen(&pThis->BodyOutput.uData.hFile, pszDstFile, 2825 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_READWRITE); 2684 2826 if (RT_SUCCESS(rc)) 2685 2827 { … … 2688 2830 */ 2689 2831 rcCurl = curl_easy_perform(pThis->pCurl); 2690 rc = rtHttpGetCalcStatus(pThis, rcCurl );2832 rc = rtHttpGetCalcStatus(pThis, rcCurl, NULL); 2691 2833 if (RT_SUCCESS(rc)) 2692 2834 rc = pThis->rcOutput; 2693 2835 2694 int rc2 = RTFileClose(pThis-> Output.hFile);2836 int rc2 = RTFileClose(pThis->BodyOutput.uData.hFile); 2695 2837 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 2696 2838 rc = rc2; 2697 2839 } 2698 pThis-> Output.hFile = NIL_RTFILE;2840 pThis->BodyOutput.uData.hFile = NIL_RTFILE; 2699 2841 } 2700 2842 else … … 2707 2849 2708 2850 2709 RTR3DECL(int) RTHttpPerform(RTHTTP hHttp, const char *pszUrl, RTHTTPMETHOD enmMethod, 2851 RTR3DECL(int) RTHttpPerform(RTHTTP hHttp, const char *pszUrl, RTHTTPMETHOD enmMethod, void const *pvReqBody, size_t cbReqBody, 2710 2852 uint32_t *puHttpStatus, void **ppvHeaders, size_t *pcbHeaders, void **ppvBody, size_t *pcbBody) 2711 2853 { 2712 RT_NOREF(hHttp, pszUrl, enmMethod, puHttpStatus, ppvHeaders, pcbHeaders, ppvBody, pcbBody); 2713 return VERR_NOT_IMPLEMENTED; 2714 } 2715 2854 /* 2855 * Set safe return values and validate input. 2856 */ 2857 Log(("RTHttpPerform: hHttp=%p pszUrl=%s enmMethod=%d pvReqBody=%p cbReqBody=%zu puHttpStatus=%p ppvHeaders=%p ppvBody=%p\n", 2858 hHttp, pszUrl, enmMethod, pvReqBody, cbReqBody, puHttpStatus, ppvHeaders, ppvBody)); 2859 2860 if (ppvHeaders) 2861 *ppvHeaders = NULL; 2862 if (pcbHeaders) 2863 *pcbHeaders = 0; 2864 if (ppvBody) 2865 *ppvBody = NULL; 2866 if (pcbBody) 2867 *pcbBody = 0; 2868 if (puHttpStatus) 2869 *puHttpStatus = UINT32_MAX; 2870 2871 PRTHTTPINTERNAL pThis = hHttp; 2872 RTHTTP_VALID_RETURN(pThis); 2873 AssertReturn(enmMethod > RTHTTPMETHOD_INVALID && enmMethod < RTHTTPMETHOD_END, VERR_INVALID_PARAMETER); 2874 AssertPtrReturn(pszUrl, VERR_INVALID_POINTER); 2875 2876 /* 2877 * Set the busy flag (paranoia). 2878 */ 2879 bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true); 2880 AssertReturn(!fBusy, VERR_WRONG_ORDER); 2881 2882 /* 2883 * Reset the state and apply settings. 2884 */ 2885 rtHttpResetState(pThis); 2886 int rc = rtHttpApplySettings(hHttp, pszUrl); 2887 if (RT_SUCCESS(rc)) 2888 { 2889 2890 /* HTTP method. */ 2891 int rcCurl = 1; 2892 switch (enmMethod) 2893 { 2894 case RTHTTPMETHOD_GET: 2895 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPGET, 1L); 2896 break; 2897 case RTHTTPMETHOD_PUT: 2898 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PUT, 1L); 2899 break; 2900 case RTHTTPMETHOD_POST: 2901 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_POST, 1L); 2902 break; 2903 case RTHTTPMETHOD_PATCH: 2904 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CUSTOMREQUEST, "PATCH"); 2905 break; 2906 case RTHTTPMETHOD_DELETE: 2907 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CUSTOMREQUEST, "DELETE"); 2908 break; 2909 case RTHTTPMETHOD_HEAD: 2910 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPGET, 1L); 2911 if (CURL_SUCCESS(rcCurl)) 2912 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOBODY, 1L); 2913 break; 2914 case RTHTTPMETHOD_OPTIONS: 2915 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); 2916 break; 2917 case RTHTTPMETHOD_TRACE: 2918 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CUSTOMREQUEST, "TRACE"); 2919 break; 2920 case RTHTTPMETHOD_END: 2921 case RTHTTPMETHOD_INVALID: 2922 case RTHTTPMETHOD_32BIT_HACK: 2923 AssertFailed(); 2924 } 2925 2926 /* Request body. */ 2927 if (pvReqBody && cbReqBody > 0 && CURL_SUCCESS(rcCurl)) 2928 { 2929 if (enmMethod == RTHTTPMETHOD_POST) 2930 { 2931 /** @todo ??? */ 2932 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_POSTFIELDSIZE, cbReqBody); 2933 if (CURL_SUCCESS(rcCurl)) 2934 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_POSTFIELDS, pvReqBody); 2935 } 2936 else 2937 { 2938 pThis->ReadData.Mem.pvMem = pvReqBody; 2939 pThis->ReadData.Mem.cbMem = cbReqBody; 2940 pThis->ReadData.Mem.offMem = 0; 2941 rcCurl = rtHttpSetReadCallback(pThis, &rtHttpReadData, pThis); 2942 } 2943 } 2944 2945 /* Headers. */ 2946 if (ppvHeaders && CURL_SUCCESS(rcCurl)) 2947 { 2948 RT_ZERO(pThis->HeadersOutput.uData.Mem); 2949 rcCurl = rtHttpSetHeaderCallback(pThis, &rtHttpWriteData, &pThis->HeadersOutput); 2950 } 2951 2952 /* Body */ 2953 if (ppvBody && CURL_SUCCESS(rcCurl)) 2954 { 2955 RT_ZERO(pThis->BodyOutput.uData.Mem); 2956 rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteData, &pThis->BodyOutput); 2957 } 2958 2959 if (CURL_SUCCESS(rcCurl)) 2960 { 2961 /* 2962 * Perform the HTTP operation. 2963 */ 2964 rcCurl = curl_easy_perform(pThis->pCurl); 2965 rc = rtHttpGetCalcStatus(pThis, rcCurl, puHttpStatus); 2966 if (RT_SUCCESS(rc)) 2967 rc = pThis->rcOutput; 2968 if (RT_SUCCESS(rc)) 2969 { 2970 if (ppvHeaders) 2971 { 2972 *ppvHeaders = pThis->HeadersOutput.uData.Mem.pb; 2973 *pcbHeaders = pThis->HeadersOutput.uData.Mem.cb; 2974 pThis->HeadersOutput.uData.Mem.pb = NULL; 2975 Log(("RTHttpPerform: headers: %zx bytes (allocated %zx)\n", 2976 pThis->HeadersOutput.uData.Mem.cb, pThis->HeadersOutput.uData.Mem.cbAllocated)); 2977 } 2978 if (ppvBody) 2979 { 2980 *ppvBody = pThis->BodyOutput.uData.Mem.pb; 2981 *pcbBody = pThis->BodyOutput.uData.Mem.cb; 2982 pThis->BodyOutput.uData.Mem.pb = NULL; 2983 Log(("RTHttpPerform: body: %zx bytes (allocated %zx)\n", 2984 pThis->HeadersOutput.uData.Mem.cb, pThis->HeadersOutput.uData.Mem.cbAllocated)); 2985 } 2986 } 2987 } 2988 else 2989 rc = VERR_HTTP_CURL_ERROR; 2990 2991 /* Ensure we've freed all unused output and dropped references to input memory.*/ 2992 if (pThis->HeadersOutput.uData.Mem.pb) 2993 RTMemFree(pThis->HeadersOutput.uData.Mem.pb); 2994 if (pThis->BodyOutput.uData.Mem.pb) 2995 RTMemFree(pThis->BodyOutput.uData.Mem.pb); 2996 RT_ZERO(pThis->HeadersOutput.uData.Mem); 2997 RT_ZERO(pThis->BodyOutput.uData.Mem); 2998 RT_ZERO(pThis->ReadData); 2999 } 3000 3001 ASMAtomicWriteBool(&pThis->fBusy, false); 3002 return rc; 3003 } 3004 3005 3006 /********************************************************************************************************************************* 3007 * Callback APIs. * 3008 *********************************************************************************************************************************/ 2716 3009 2717 3010 RTR3DECL(int) RTHttpSetDownloadProgressCallback(RTHTTP hHttp, PFNRTHTTPDOWNLDPROGRCALLBACK pfnDownloadProgress, void *pvUser) … … 2727 3020 2728 3021 3022 /** @todo questionable wrt calling convension */ 2729 3023 RTR3DECL(int) RTHttpSetReadCallback(RTHTTP hHttp, PFNRTHTTPREADCALLBACK pfnRead, void *pvUser) 2730 3024 { … … 2746 3040 2747 3041 2748 static CURLcode rtHttpSetWriteCallback(PRTHTTPINTERNAL pThis, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser) 2749 { 2750 CURLcode rcCurl; 2751 2752 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, pfnWrite); 2753 if (CURL_FAILURE(rcCurl)) 2754 return rcCurl; 2755 2756 rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, pvUser); 2757 if (CURL_FAILURE(rcCurl)) 2758 return rcCurl; 2759 2760 return rcCurl; 2761 } 2762 2763 3042 /** @todo questionable wrt calling convension */ 2764 3043 RTR3DECL(int) RTHttpSetWriteCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser) 2765 3044 { … … 2775 3054 2776 3055 3056 /** @todo questionable wrt calling convension */ 2777 3057 RTR3DECL(int) RTHttpSetWriteHeaderCallback(RTHTTP hHttp, PFNRTHTTPWRITECALLBACK pfnWrite, void *pvUser) 2778 3058 { … … 2794 3074 2795 3075 3076 3077 3078 /********************************************************************************************************************************* 3079 * Temporary raw cURL stuff. * 3080 *********************************************************************************************************************************/ 3081 2796 3082 RTR3DECL(int) RTHttpRawSetUrl(RTHTTP hHttp, const char *pszUrl) 2797 3083 {
Note:
See TracChangeset
for help on using the changeset viewer.