- Timestamp:
- Sep 12, 2018 1:30:00 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/http-curl.cpp
r74202 r74222 218 218 /** @name Upload callback 219 219 * @{ */ 220 /** Pointer to the download callback function, if any n. */220 /** Pointer to the download callback function, if any. */ 221 221 PFNRTHTTPUPLOADCALLBACK pfnUploadCallback; 222 222 /** The user argument for the upload callback function. */ … … 228 228 /** @} */ 229 229 230 /** @name Download callback 230 /** @name Download callback. 231 231 * @{ */ 232 /** Pointer to the download callback function, if any n. */232 /** Pointer to the download callback function, if any. */ 233 233 PFNRTHTTPDOWNLOADCALLBACK pfnDownloadCallback; 234 234 /** The user argument for the download callback function. */ … … 247 247 * @{ */ 248 248 /** Download size hint set by the progress callback. */ 249 uint64_t cbDownloadHint;249 uint64_t cbDownloadHint; 250 250 /** Callback called during download. */ 251 PFNRTHTTPDOWNLDPROGRCALLBACK pfnDownloadProgress;251 PFNRTHTTPDOWNLDPROGRCALLBACK pfnDownloadProgress; 252 252 /** User pointer parameter for pfnDownloadProgress. */ 253 253 void *pvDownloadProgressUser; 254 254 /** @} */ 255 256 /** @name Header callback. 257 * @{ */ 258 /** Pointer to the header callback function, if any. */ 259 PFNRTHTTPHEADERCALLBACK pfnHeaderCallback; 260 /** User pointer parameter for pfnHeaderCallback. */ 261 void *pvHeaderCallbackUser; 262 /** @} */ 263 255 264 } RTHTTPINTERNAL; 256 265 /** Pointer to an internal HTTP client instance. */ … … 2920 2929 2921 2930 /** 2922 * cURL callback for writing data. 2923 */ 2924 static size_t rtHttpWriteData(char *pchBuf, size_t cbUnit, size_t cUnits, void *pvUser) 2925 { 2926 RTHTTPOUTPUTDATA *pOutput = (RTHTTPOUTPUTDATA *)pvUser; 2927 PRTHTTPINTERNAL pThis = pOutput->pHttp; 2931 * Worker for rtHttpWriteHeaderData and rtHttpWriteBodyData. 2932 */ 2933 static size_t rtHttpWriteDataToMemOutput(PRTHTTPINTERNAL pThis, RTHTTPOUTPUTDATA *pOutput, char const *pchBuf, size_t cbToAppend) 2934 { 2935 /* 2936 * Do max size and overflow checks. 2937 */ 2938 size_t const cbCurSize = pOutput->uData.Mem.cb; 2939 size_t const cbNewSize = cbCurSize + cbToAppend; 2940 if ( cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2941 && cbNewSize < RTHTTP_MAX_MEM_DOWNLOAD_SIZE) 2942 { 2943 if (cbNewSize + 1 <= pOutput->uData.Mem.cbAllocated) 2944 { 2945 memcpy(&pOutput->uData.Mem.pb[cbCurSize], pchBuf, cbToAppend); 2946 pOutput->uData.Mem.cb = cbNewSize; 2947 pOutput->uData.Mem.pb[cbNewSize] = '\0'; 2948 return cbToAppend; 2949 } 2950 2951 /* 2952 * We need to reallocate the output buffer. 2953 */ 2954 /** @todo this could do with a better strategy wrt growth. */ 2955 size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64); 2956 if ( cbAlloc <= pThis->cbDownloadHint 2957 && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2958 && pOutput == &pThis->BodyOutput) 2959 cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64); 2960 2961 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pOutput->uData.Mem.pb, cbAlloc); 2962 if (pbNew) 2963 { 2964 memcpy(&pbNew[cbCurSize], pchBuf, cbToAppend); 2965 pbNew[cbNewSize] = '\0'; 2966 2967 pOutput->uData.Mem.cbAllocated = cbAlloc; 2968 pOutput->uData.Mem.pb = pbNew; 2969 pOutput->uData.Mem.cb = cbNewSize; 2970 return cbToAppend; 2971 } 2972 2973 pThis->rcOutput = VERR_NO_MEMORY; 2974 } 2975 else 2976 pThis->rcOutput = VERR_TOO_MUCH_DATA; 2977 2978 /* 2979 * Failure - abort. 2980 */ 2981 RTMemFree(pOutput->uData.Mem.pb); 2982 pOutput->uData.Mem.pb = NULL; 2983 pOutput->uData.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE; 2984 pThis->fAbort = true; 2985 return 0; 2986 } 2987 2988 2989 /** 2990 * cURL callback for writing body data. 2991 */ 2992 static size_t rtHttpWriteBodyData(char *pchBuf, size_t cbUnit, size_t cUnits, void *pvUser) 2993 { 2994 PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser; 2928 2995 size_t const cbToAppend = cbUnit * cUnits; 2929 2996 2930 2997 /* 2931 * If called on the body, check if this belongs to the body download callback. 2932 */ 2933 if ( pThis->pfnDownloadCallback 2934 && pOutput == &pThis->BodyOutput) 2998 * Check if this belongs to the body download callback. 2999 */ 3000 if (pThis->pfnDownloadCallback) 2935 3001 { 2936 3002 if (pThis->offDownloadContent == 0) … … 2955 3021 2956 3022 /* 2957 * Do max size and overflow checks. 2958 */ 2959 size_t const cbCurSize = pOutput->uData.Mem.cb; 2960 size_t const cbNewSize = cbCurSize + cbToAppend; 2961 if ( cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2962 && cbNewSize < RTHTTP_MAX_MEM_DOWNLOAD_SIZE) 2963 { 2964 if (cbNewSize + 1 <= pOutput->uData.Mem.cbAllocated) 2965 { 2966 memcpy(&pOutput->uData.Mem.pb[cbCurSize], pchBuf, cbToAppend); 2967 pOutput->uData.Mem.cb = cbNewSize; 2968 pOutput->uData.Mem.pb[cbNewSize] = '\0'; 3023 * Otherwise, copy to memory output buffer. 3024 */ 3025 return rtHttpWriteDataToMemOutput(pThis, &pThis->BodyOutput, pchBuf, cbToAppend); 3026 } 3027 3028 3029 /** 3030 * cURL callback for writing header data. 3031 */ 3032 static size_t rtHttpWriteHeaderData(char *pchBuf, size_t cbUnit, size_t cUnits, void *pvUser) 3033 { 3034 PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser; 3035 size_t const cbToAppend = cbUnit * cUnits; 3036 3037 /* 3038 * Work the header callback, if one. 3039 * ASSUMES cURL is giving us one header at a time. 3040 */ 3041 if (pThis->pfnHeaderCallback) 3042 { 3043 /* Find the end of the field name first. Since cURL gives us the 3044 "HTTP/{version} {code} {status}" line too, we slap a fictitious 3045 field name ':http-status-line' in front of it. */ 3046 uint32_t uMatchWord; 3047 size_t cchField; 3048 const char *pchField = pchBuf; 3049 size_t cchValue; 3050 const char *pchValue = (const char *)memchr(pchBuf, ':', cbToAppend); 3051 if (pchValue) 3052 { 3053 cchField = pchValue - pchField; 3054 if (RT_LIKELY(cchField >= 3)) 3055 uMatchWord = RTHTTP_MAKE_HDR_MATCH_WORD(cchField, RT_C_TO_LOWER(pchBuf[0]), 3056 RT_C_TO_LOWER(pchBuf[1]), RT_C_TO_LOWER(pchBuf[2])); 3057 else 3058 uMatchWord = RTHTTP_MAKE_HDR_MATCH_WORD(cchField, 3059 cchField >= 1 ? RT_C_TO_LOWER(pchBuf[0]) : 0, 3060 cchField >= 2 ? RT_C_TO_LOWER(pchBuf[1]) : 0, 3061 0); 3062 pchValue++; 3063 cchValue = cbToAppend - cchField - 1; 3064 } 3065 else if (pchBuf[0] == 'H' && pchBuf[1] == 'T' && pchBuf[2] == 'T' && pchBuf[1] == 'P') 3066 { 3067 pchField = ":http-status-line"; 3068 cchField = 17; 3069 uMatchWord = RTHTTP_MAKE_HDR_MATCH_WORD(17, ':', 'h', 't'); 3070 pchValue = pchBuf; 3071 cchValue = cbToAppend; 3072 } 3073 else 3074 AssertMsgFailedReturn(("pchBuf=%.*s\n", cbToAppend, pchBuf), cbToAppend); 3075 3076 /* Determin the field value, stripping one leading blank and all 3077 trailing spaces. */ 3078 if (cchValue > 0 && RT_C_IS_BLANK(*pchValue)) 3079 pchValue++, cchValue--; 3080 while (cchValue > 0 && RT_C_IS_SPACE(pchValue[cchValue - 1])) 3081 cchValue--; 3082 3083 /* Pass it to the callback. */ 3084 int rc = pThis->pfnHeaderCallback(pThis, uMatchWord, pchBuf, cchField, 3085 pchValue, cchValue, pThis->pvHeaderCallbackUser); 3086 if (RT_SUCCESS(rc)) 2969 3087 return cbToAppend; 2970 } 2971 2972 /* 2973 * We need to reallocate the output buffer. 2974 */ 2975 /** @todo this could do with a better strategy wrt growth. */ 2976 size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64); 2977 if ( cbAlloc <= pThis->cbDownloadHint 2978 && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE 2979 && pOutput == &pThis->BodyOutput) 2980 cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64); 2981 2982 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pOutput->uData.Mem.pb, cbAlloc); 2983 if (pbNew) 2984 { 2985 memcpy(&pbNew[cbCurSize], pchBuf, cbToAppend); 2986 pbNew[cbNewSize] = '\0'; 2987 2988 pOutput->uData.Mem.cbAllocated = cbAlloc; 2989 pOutput->uData.Mem.pb = pbNew; 2990 pOutput->uData.Mem.cb = cbNewSize; 2991 return cbToAppend; 2992 } 2993 2994 pThis->rcOutput = VERR_NO_MEMORY; 2995 } 2996 else 2997 pThis->rcOutput = VERR_TOO_MUCH_DATA; 2998 2999 /* 3000 * Failure - abort. 3001 */ 3002 RTMemFree(pOutput->uData.Mem.pb); 3003 pOutput->uData.Mem.pb = NULL; 3004 pOutput->uData.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE; 3005 pThis->fAbort = true; 3006 return 0; 3088 3089 if (RT_SUCCESS(pThis->rcOutput)) 3090 pThis->rcOutput = rc; 3091 pThis->fAbort = true; 3092 return 0; 3093 } 3094 3095 return rtHttpWriteDataToMemOutput(pThis, &pThis->HeadersOutput, pchBuf, cbToAppend); 3007 3096 } 3008 3097 … … 3174 3263 { 3175 3264 RT_ZERO(pThis->BodyOutput.uData.Mem); 3176 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWrite Data, (void *)&pThis->BodyOutput);3265 int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteBodyData, pThis); 3177 3266 if (fNoBody) 3178 3267 { … … 3461 3550 { 3462 3551 RT_ZERO(pThis->HeadersOutput.uData.Mem); 3463 rcCurl = rtHttpSetHeaderCallback(pThis, rtHttpWrite Data, &pThis->HeadersOutput);3552 rcCurl = rtHttpSetHeaderCallback(pThis, rtHttpWriteHeaderData, pThis); 3464 3553 } 3465 3554 … … 3468 3557 { 3469 3558 RT_ZERO(pThis->BodyOutput.uData.Mem); 3470 rcCurl = rtHttpSetWriteCallback(pThis, rtHttpWrite Data, &pThis->BodyOutput);3559 rcCurl = rtHttpSetWriteCallback(pThis, rtHttpWriteBodyData, pThis); 3471 3560 } 3472 3561 else if (pThis->pfnDownloadCallback && CURL_SUCCESS(rcCurl)) … … 3596 3685 3597 3686 3598 /** @todo header field callback. */ 3687 RTR3DECL(int) RTHttpSetHeaderCallback(RTHTTP hHttp, PFNRTHTTPHEADERCALLBACK pfnCallback, void *pvUser) 3688 { 3689 PRTHTTPINTERNAL pThis = hHttp; 3690 RTHTTP_VALID_RETURN(pThis); 3691 3692 pThis->pfnHeaderCallback = pfnCallback; 3693 pThis->pvHeaderCallbackUser = pvUser; 3694 return VINF_SUCCESS; 3695 } 3599 3696 3600 3697
Note:
See TracChangeset
for help on using the changeset viewer.