VirtualBox

Changeset 73930 in vbox


Ignore:
Timestamp:
Aug 28, 2018 6:09:54 PM (6 years ago)
Author:
vboxsync
Message:

IPRT/rest: Implemented parsing json response bodies. bugref:9167

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/cpp/restbase.h

    r73922 r73930  
    707707    int getHttpStatus() { return m_rcHttp; }
    708708
     709    /**
     710     * Getter for m_pErrInfo.
     711     */
     712    PCRTERRINFO  getErrIfno(void) const { return m_pErrInfo; }
     713
     714    /**
     715     * Getter for m_strContentType.
     716     */
     717    RTCString const &getContentType(void) const { return m_strContentType; }
     718
     719
    709720protected:
    710721    /** Negative numbers are IPRT errors, positive are HTTP status codes. */
    711     int m_rcStatus;
     722    int         m_rcStatus;
    712723    /** The HTTP status code, VERR_NOT_AVAILABLE if not set. */
    713     int m_rcHttp;
     724    int         m_rcHttp;
    714725    /** Error information. */
    715     PRTERRINFO m_pErrInfo;
     726    PRTERRINFO  m_pErrInfo;
    716727    /** The value of the Content-Type header field. */
    717     RTCString m_strContentType;
    718 
    719     PRTERRINFO  allocErrInfo(void);
     728    RTCString   m_strContentType;
     729
     730    PRTERRINFO  getErrInfo(void);
    720731    void        deleteErrInfo(void);
    721732    void        copyErrInfo(PCRTERRINFO pErrInfo);
     733
     734    /**
     735     * Reports an error (or warning if a_rc non-negative).
     736     *
     737     * @returns a_rc
     738     * @param   a_rc        The status code to report and return.  The first
     739     *                      error status is assigned to m_rcStatus, subsequent
     740     *                      ones as well as informational statuses are not
     741     *                      recorded by m_rcStatus.
     742     * @param   a_pszFormat The message format string.
     743     * @param   ...         Message arguments.
     744     */
     745    int         addError(int a_rc, const char *a_pszFormat, ...);
    722746
    723747    /**
     
    735759    int extractHeaderFromBlob(const char *a_pszField, size_t a_cchField, const char *a_pchData, size_t a_cbData,
    736760                              RTCString *a_pStrDst);
     761
     762    /**
     763     * Helper that does the deserializing of the response body.
     764     *
     765     * @param   a_pDst      The destination object for the body content.
     766     * @param   a_pchData   The body blob.
     767     * @param   a_cbData    The size of the body blob.
     768     */
     769    void deserializeBody(RTCRestObjectBase *a_pDst, const char *a_pchData, size_t a_cbData);
     770
     771    /**
     772     * Primary json cursor for parsing bodies.
     773     */
     774    class PrimaryJsonCursorForBody : public RTCRestJsonPrimaryCursor
     775    {
     776    public:
     777        RTCRestClientResponseBase *m_pThat; /**< Pointer to response object. */
     778        PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName, RTCRestClientResponseBase *a_pThat);
     779        virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_OVERRIDE;
     780        virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_OVERRIDE;
     781    };
    737782};
    738783
     
    821866    virtual void doCall(RTCRestClientRequestBase const &a_rRequest, RTHTTPMETHOD a_enmHttpMethod,
    822867                        RTCRestClientResponseBase *a_pResponse);
     868
    823869};
    824870
  • trunk/include/iprt/err.h

    r73929 r73930  
    31943194/** Internal processing error \#5.  */
    31953195#define VERR_ISOFS_IPE_5                                (-25395)
    3196 
    31973196/** @} */
    31983197
     
    32043203/** The chosen baudrate is invalid or not supported by the given serial port. */
    32053204#define VERR_SERIALPORT_INVALID_BAUDRATE                (-25501)
    3206 
     3205/** @} */
     3206
     3207
     3208/** @name RTCRest status codes
     3209 * @{ */
     3210/** Do not know how to handle the content type in the server response. */
     3211#define VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED   (-25700)
     3212/** Invalid UTF-8 encoding in the response. */
     3213#define VERR_REST_RESPONSE_INVALID_UTF8_ENCODING        (-25701)
     3214/** Server response contains embedded zero character(s). */
     3215#define VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR           (-25702)
    32073216/** @} */
    32083217
  • trunk/include/iprt/json.h

    r73874 r73930  
    8888 * @param   cbBuf           Size of the buffer.
    8989 * @param   pErrInfo        Where to store extended error info. Optional.
     90 *
     91 * @todo    r=bird: The use of uint8_t makes no sense here since the parser
     92 *          expects ASCII / UTF-8.  What's more, if this is a real buffer the
     93 *          type should be 'const void *' rather than 'const uint8_t *'.
     94 *          This function should be modified to reflect that it's really for
     95 *          handling unterminated strings.
    9096 */
    9197RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, PRTERRINFO pErrInfo);
  • trunk/src/VBox/Runtime/common/misc/json.cpp

    r73874 r73930  
    12251225    AssertPtrReturn(pszStr, VERR_INVALID_POINTER);
    12261226
     1227    /** @todo r=bird: The rtJsonTokenizerParseFromString function does
     1228     *        strlen() on the whole pszStr for each read.  For larger strings (
     1229     *        longer than sizeof(Tokenizer.achBuf)) it would be good to join
     1230     *        forces with RTJsonParseFromBuf. */
    12271231    RTJSONTOKENIZER Tokenizer;
    12281232    int rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr);
  • trunk/src/VBox/Runtime/common/rest/RTCRestClientResponseBase.cpp

    r73923 r73930  
    125125
    126126
    127 PRTERRINFO RTCRestClientResponseBase::allocErrInfo(void)
    128 {
     127PRTERRINFO RTCRestClientResponseBase::getErrInfo(void)
     128{
     129    if (m_pErrInfo)
     130        return m_pErrInfo;
    129131    size_t cbMsg = _4K;
    130132    m_pErrInfo = (PRTERRINFO)RTMemAllocZ(sizeof(*m_pErrInfo) + cbMsg);
     
    155157        m_pErrInfo->apvReserved[1] = NULL;
    156158    }
     159}
     160
     161
     162int RTCRestClientResponseBase::addError(int rc, const char *pszFormat, ...)
     163{
     164    PRTERRINFO pErrInfo = getErrInfo();
     165    if (pErrInfo)
     166    {
     167        va_list va;
     168        va_start(va, pszFormat);
     169        if (   !RTErrInfoIsSet(pErrInfo)
     170            || pErrInfo->cbMsg == 0
     171            || pErrInfo->pszMsg[pErrInfo->cbMsg - 1] == '\n')
     172            RTErrInfoAddV(pErrInfo, rc, pszFormat, va);
     173        else
     174            RTErrInfoAddF(pErrInfo, rc, "\n%N", pszFormat, &va);
     175        va_end(va);
     176    }
     177    if (RT_SUCCESS(m_rcStatus) && RT_FAILURE_NP(rc))
     178        m_rcStatus = rc;
     179    return rc;
    157180}
    158181
     
    198221            int rc = a_pStrDst->assignNoThrow(a_pchData, cchField);
    199222            if (RT_SUCCESS(rc))
    200                 RTStrPurgeEncoding(a_pStrDst->mutableRaw());
     223                RTStrPurgeEncoding(a_pStrDst->mutableRaw()); /** @todo this is probably a little wrong... */
    201224            return rc;
    202225        }
     
    210233}
    211234
     235
     236
     237RTCRestClientResponseBase::PrimaryJsonCursorForBody::PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName,
     238                                                                              RTCRestClientResponseBase *a_pThat)
     239    : RTCRestJsonPrimaryCursor(hValue, pszName, a_pThat->getErrInfo())
     240    , m_pThat(a_pThat)
     241{
     242}
     243
     244
     245int RTCRestClientResponseBase::PrimaryJsonCursorForBody::addError(RTCRestJsonCursor const &a_rCursor, int a_rc,
     246                                                                  const char *a_pszFormat, ...)
     247{
     248    va_list va;
     249    va_start(va, a_pszFormat);
     250    char szPath[256];
     251    m_pThat->addError(a_rc, "response body/%s: %N", getPath(a_rCursor, szPath, sizeof(szPath)), a_pszFormat, &va);
     252    va_end(va);
     253    return a_rc;
     254}
     255
     256
     257int RTCRestClientResponseBase::PrimaryJsonCursorForBody::unknownField(RTCRestJsonCursor const &a_rCursor)
     258{
     259    char szPath[256];
     260    m_pThat->addError(VWRN_NOT_FOUND, "response body/%s: unknown field (type %s)",
     261                      getPath(a_rCursor, szPath, sizeof(szPath)), RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
     262    return VWRN_NOT_FOUND;
     263}
     264
     265
     266void RTCRestClientResponseBase::deserializeBody(RTCRestObjectBase *a_pDst, const char *a_pchData, size_t a_cbData)
     267{
     268    if (m_strContentType.startsWith("application/json;"))
     269    {
     270        int rc = RTStrValidateEncodingEx(a_pchData, a_cbData, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
     271        if (RT_SUCCESS(rc))
     272        {
     273            RTERRINFOSTATIC ErrInfo;
     274            RTJSONVAL hValue;
     275            rc = RTJsonParseFromBuf(&hValue, (const uint8_t *)a_pchData, a_cbData, RTErrInfoInitStatic(&ErrInfo));
     276            if (RT_SUCCESS(rc))
     277            {
     278                PrimaryJsonCursorForBody PrimaryCursor(hValue, a_pDst->getType(), this); /* note: consumes hValue */
     279                a_pDst->deserializeFromJson(PrimaryCursor.m_Cursor);
     280            }
     281            else if (RTErrInfoIsSet(&ErrInfo.Core))
     282                addError(rc, "Error %Rrc parsing server response as JSON (type %s): %s",
     283                         rc, a_pDst->getType(), ErrInfo.Core.pszMsg);
     284            else
     285                addError(rc, "Error %Rrc parsing server response as JSON (type %s)", rc, a_pDst->getType());
     286        }
     287        else if (rc == VERR_INVALID_UTF8_ENCODING)
     288            addError(VERR_REST_RESPONSE_INVALID_UTF8_ENCODING, "Invalid UTF-8 body encoding (object type %s; Content-Type: %s)",
     289                     a_pDst->getType(), m_strContentType.c_str());
     290        else if (rc == VERR_BUFFER_UNDERFLOW)
     291            addError(VERR_REST_RESPONSE_EMBEDDED_ZERO_CHAR, "Embedded zero character in response (object type %s; Content-Type: %s)",
     292                     a_pDst->getType(), m_strContentType.c_str());
     293        else
     294            addError(rc, "Unexpected body validation error (object type %s; Content-Type: %s): %Rrc",
     295                     a_pDst->getType(), m_strContentType.c_str(), rc);
     296    }
     297    else
     298        addError(VERR_REST_RESPONSE_CONTENT_TYPE_NOT_SUPPORTED, "Unsupported content type for '%s': %s",
     299                 a_pDst->getType(), m_strContentType.c_str());
     300}
     301
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