VirtualBox

Changeset 74222 in vbox for trunk/src


Ignore:
Timestamp:
Sep 12, 2018 1:30:00 PM (6 years ago)
Author:
vboxsync
Message:

IPRT/http: Implemented header callbacks. bugref:9167

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/generic/http-curl.cpp

    r74202 r74222  
    218218    /** @name Upload callback
    219219     * @{ */
    220     /** Pointer to the download callback function, if anyn. */
     220    /** Pointer to the download callback function, if any. */
    221221    PFNRTHTTPUPLOADCALLBACK         pfnUploadCallback;
    222222    /** The user argument for the upload callback function. */
     
    228228    /** @} */
    229229
    230     /** @name Download callback
     230    /** @name Download callback.
    231231     * @{ */
    232     /** Pointer to the download callback function, if anyn. */
     232    /** Pointer to the download callback function, if any. */
    233233    PFNRTHTTPDOWNLOADCALLBACK       pfnDownloadCallback;
    234234    /** The user argument for the download callback function. */
     
    247247     * @{ */
    248248    /** Download size hint set by the progress callback. */
    249     uint64_t                       cbDownloadHint;
     249    uint64_t                        cbDownloadHint;
    250250    /** Callback called during download. */
    251     PFNRTHTTPDOWNLDPROGRCALLBACK   pfnDownloadProgress;
     251    PFNRTHTTPDOWNLDPROGRCALLBACK    pfnDownloadProgress;
    252252    /** User pointer parameter for pfnDownloadProgress. */
    253253    void                           *pvDownloadProgressUser;
    254254    /** @} */
     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
    255264} RTHTTPINTERNAL;
    256265/** Pointer to an internal HTTP client instance. */
     
    29202929
    29212930/**
    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 */
     2933static 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 */
     2992static size_t rtHttpWriteBodyData(char *pchBuf, size_t cbUnit, size_t cUnits, void *pvUser)
     2993{
     2994    PRTHTTPINTERNAL   pThis      = (PRTHTTPINTERNAL)pvUser;
    29282995    size_t const      cbToAppend = cbUnit * cUnits;
    29292996
    29302997    /*
    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)
    29353001    {
    29363002        if (pThis->offDownloadContent == 0)
     
    29553021
    29563022    /*
    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 */
     3032static 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))
    29693087            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);
    30073096}
    30083097
     
    31743263    {
    31753264        RT_ZERO(pThis->BodyOutput.uData.Mem);
    3176         int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteData, (void *)&pThis->BodyOutput);
     3265        int rcCurl = rtHttpSetWriteCallback(pThis, &rtHttpWriteBodyData, pThis);
    31773266        if (fNoBody)
    31783267        {
     
    34613550        {
    34623551            RT_ZERO(pThis->HeadersOutput.uData.Mem);
    3463             rcCurl = rtHttpSetHeaderCallback(pThis, rtHttpWriteData, &pThis->HeadersOutput);
     3552            rcCurl = rtHttpSetHeaderCallback(pThis, rtHttpWriteHeaderData, pThis);
    34643553        }
    34653554
     
    34683557        {
    34693558            RT_ZERO(pThis->BodyOutput.uData.Mem);
    3470             rcCurl = rtHttpSetWriteCallback(pThis, rtHttpWriteData, &pThis->BodyOutput);
     3559            rcCurl = rtHttpSetWriteCallback(pThis, rtHttpWriteBodyData, pThis);
    34713560        }
    34723561        else if (pThis->pfnDownloadCallback && CURL_SUCCESS(rcCurl))
     
    35963685
    35973686
    3598 /** @todo header field callback. */
     3687RTR3DECL(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}
    35993696
    36003697
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette