diff options
Diffstat (limited to '')
-rw-r--r-- | include/iprt/cpp/restclient.h | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/include/iprt/cpp/restclient.h b/include/iprt/cpp/restclient.h new file mode 100644 index 00000000..37e394ac --- /dev/null +++ b/include/iprt/cpp/restclient.h @@ -0,0 +1,793 @@ +/** @file + * IPRT - C++ Representational State Transfer (REST) Client Classes. + */ + +/* + * Copyright (C) 2008-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef IPRT_INCLUDED_cpp_restclient_h +#define IPRT_INCLUDED_cpp_restclient_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/http.h> +#include <iprt/cpp/restbase.h> +#include <iprt/cpp/reststringmap.h> + + +/** @defgroup grp_rt_cpp_restclient C++ Representational State Transfer (REST) Client Classes. + * @ingroup grp_rt_cpp + * @{ + */ + +/** + * Specialization of RTCRestBinary for use with body parameters in a client. + * + * This enables registering data callbacks for provinding data to upload. + */ +class RT_DECL_CLASS RTCRestBinaryParameter : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryParameter() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryParameter const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note Resets callbacks and ASSUMES that @a a_cbData is the content length. */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will assert and work like assignReadOnly. */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryParameter *clone() const RT_NOEXCEPT { return (RTCRestBinaryParameter *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the content-type for an upload. + * + * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. + * @param a_pszContentType The content type to set. + * If NULL, no content type is set. + */ + int setContentType(const char *a_pszContentType) RT_NOEXCEPT; + + /** + * Gets the content type that was set. + */ + inline RTCString const &getContentType() const RT_NOEXCEPT { return m_strContentType; } + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for producing bytes to upload. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvDst Where to put the bytes. + * @param a_cbDst Max number of bytes to produce. + * @param a_offContent The byte offset corresponding to the start of @a a_pvDst. + * @param a_pcbActual Where to return the number of bytes actually produced. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previously returned @a *pcbActual values. + */ + typedef DECLCALLBACK(int) FNPRODUCER(RTCRestBinaryParameter *a_pThis, void *a_pvDst, size_t a_cbDst, + uint64_t a_offContent, size_t *a_pcbActual) /*RT_NOEXCEPT*/; + /** Pointer to a byte producer callback. */ + typedef FNPRODUCER *PFNPRODUCER; + + /** + * Sets the producer callback. + * + * @param a_pfnProducer The callback function for producing data. + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + * @param a_cbContentLength The amount of data that will be uploaded and + * to be set as the value of the content-length + * header field. Pass UINT64_MAX if not known. + * + * @note This will drop any buffer previously registered using setUploadData(). + */ + void setProducerCallback(PFNPRODUCER a_pfnProducer, void *a_pvCallbackData = NULL, uint64_t a_cbContentLength = UINT64_MAX) RT_NOEXCEPT; + + /** + * Preprares transmission via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual int xmitPrepare(RTHTTP a_hHttp) const RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from xmitPrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void xmitComplete(RTHTTP a_hHttp) const RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** The content type if set (upload only). */ + RTCString m_strContentType; + /** Pointer to user-registered producer callback function (upload only). */ + PFNPRODUCER m_pfnProducer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + + /** @copydoc FNRTHTTPUPLOADCALLBACK */ + static DECLCALLBACK(int) xmitHttpCallback(RTHTTP hHttp, void *pvBuf, size_t cbBuf, uint64_t offContent, + size_t *pcbActual, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryParameter(RTCRestBinaryParameter const &a_rThat); + RTCRestBinaryParameter &operator=(RTCRestBinaryParameter const &a_rThat); +}; + + +/** + * Specialization of RTCRestBinary for use with responses in a client. + * + * This enables registering data callbacks for consuming downloaded data. + */ +class RT_DECL_CLASS RTCRestBinaryResponse : public RTCRestBinary +{ +public: + /** Default constructor. */ + RTCRestBinaryResponse() RT_NOEXCEPT; + + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinaryResponse const &a_rThat) RT_NOEXCEPT; + /** Safe copy assignment method. */ + virtual int assignCopy(RTCRestBinary const &a_rThat) RT_NOEXCEPT RT_OVERRIDE; + /** Safe copy assignment method. + * @note This will assert and fail as it makes no sense for a download. */ + virtual int assignCopy(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + + /** + * Use the specified data buffer directly. + * @note This will assert and fail as it makes no sense for a download. + */ + virtual int assignReadOnly(void const *a_pvData, size_t a_cbData) RT_NOEXCEPT RT_OVERRIDE; + /** + * Use the specified data buffer directly. + * @note This will drop any previously registered producer callback and user data. + */ + virtual int assignWriteable(void *a_pvBuf, size_t a_cbBuf) RT_NOEXCEPT RT_OVERRIDE; + + /** Make a clone of this object. */ + inline RTCRestBinaryResponse *clone() const RT_NOEXCEPT { return (RTCRestBinaryResponse *)baseClone(); } + + /* Overridden methods: */ + virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE; + virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE; + virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE; + + /** Factory method. */ + static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT; + + /** + * Retrieves the callback data. + */ + inline void *getCallbackData() const RT_NOEXCEPT { return m_pvCallbackData; } + + /** + * Sets the max size to download to memory. + * + * This also indicates the intention to download to a memory buffer, so it + * will drop any previously registered consumer callback and its user data. + * + * @param a_cbMaxDownload Maximum number of bytes to download to memory. + * If 0, a default is selected (currently 32MiB for + * 32-bit hosts and 128MiB for 64-bit). + */ + void setMaxDownloadSize(size_t a_cbMaxDownload) RT_NOEXCEPT; + + /** + * Gets the content-length value (UINT64_MAX if not available). + */ + inline uint64_t getContentLength() const RT_NOEXCEPT { return m_cbContentLength; } + + /** + * Callback for consuming downloaded bytes. + * + * @returns IPRT status code. + * @param a_pThis The related string object. + * @param a_pvSrc Buffer containing the bytes. + * @param a_cbSrc The number of bytes in the buffer. + * @param a_uHttpStatus The HTTP status code. + * @param a_offContent The byte offset corresponding to the start of @a a_pvSrc. + * @param a_cbContent The content length field value, UINT64_MAX if not available. + * + * @remarks Use getCallbackData to get the user data. + * + * @note The @a a_offContent parameter does not imply random access or anthing + * like that, it is just a convenience provided by the caller. The value + * is the sum of the previous @a a_cbSrc values. + */ + typedef DECLCALLBACK(int) FNCONSUMER(RTCRestBinaryResponse *a_pThis, const void *a_pvSrc, size_t a_cbSrc, + uint32_t a_uHttpStatus, uint64_t a_offContent, uint64_t a_cbContent) /*RT_NOEXCEPT*/; + /** Pointer to a byte consumer callback. */ + typedef FNCONSUMER *PFNCONSUMER; + + /** + * Sets the consumer callback. + * + * @param a_pfnConsumer The callback function for consuming downloaded data. + * NULL if data should be stored in m_pbData (the default). + * @param a_pvCallbackData Data the can be retrieved from the callback + * using getCallbackData(). + */ + void setConsumerCallback(PFNCONSUMER a_pfnConsumer, void *a_pvCallbackData = NULL) RT_NOEXCEPT; + + /** + * Preprares for receiving via the @a a_hHttp client instance. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_fCallbackFlags The HTTP callback flags (status code spec). + * @internal + */ + virtual int receivePrepare(RTHTTP a_hHttp, uint32_t a_fCallbackFlags) RT_NOEXCEPT; + + /** + * For completing and/or undoing setup from receivePrepare. + * + * @param a_hHttp The HTTP client instance. + * @internal + */ + virtual void receiveComplete(RTHTTP a_hHttp) RT_NOEXCEPT; + +protected: + /** Number of bytes corresponding to content-length. + * UINT64_MAX if not known. Used both for unploads and downloads. */ + uint64_t m_cbContentLength; + /** Number of bytes downloaded thus far. */ + uint64_t m_cbDownloaded; + /** Pointer to user-registered consumer callback function (download only). */ + PFNCONSUMER m_pfnConsumer; + /** User argument for both callbacks (both). */ + void *m_pvCallbackData; + /** Maximum data to download to memory (download only). */ + size_t m_cbMaxDownload; + + /** @copydoc FNRTHTTPDOWNLOADCALLBACK */ + static DECLCALLBACK(int) receiveHttpCallback(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus, + uint64_t offContent, uint64_t cbContent, void *pvUser) RT_NOEXCEPT; + +private: + /* No copy constructor or copy assignment: */ + RTCRestBinaryResponse(RTCRestBinaryResponse const &a_rThat); + RTCRestBinaryResponse &operator=(RTCRestBinaryResponse const &a_rThat); +}; + + +/** + * Base class for REST client requests. + * + * This encapsulates parameters and helps transform them into a HTTP request. + * + * Parameters can be transfered in a number of places: + * - Path part of the URL. + * - Query part of the URL. + * - HTTP header fields. + * - FORM body. + * - JSON body. + * - XML body. + * - ... + * + * They can be require or optional. The latter may have default values. In + * swagger 3 they can also be nullable, which means the null-indicator cannot + * be used for tracking optional parameters. + */ +class RT_DECL_CLASS RTCRestClientRequestBase +{ +public: + RTCRestClientRequestBase() RT_NOEXCEPT; + virtual ~RTCRestClientRequestBase(); + RTCRestClientRequestBase(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + RTCRestClientRequestBase &operator=(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT; + + /** + * Reset all members to default values. + * @returns IPRT status code. + */ + virtual int resetToDefault() RT_NOEXCEPT = 0; + + /** + * Prepares the HTTP handle for transmitting this request. + * + * @returns IPRT status code. + * @param a_pStrPath Where to set path parameters. Will be appended to the base path. + * @param a_pStrQuery Where to set query parameters. + * @param a_hHttp Where to set header parameters and such. + * @param a_pStrBody Where to set body parameters. + */ + virtual int xmitPrepare(RTCString *a_pStrPath, RTCString *a_pStrQuery, RTHTTP a_hHttp, RTCString *a_pStrBody) const RT_NOEXCEPT = 0; + + /** + * Always called after the request has been transmitted. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + */ + virtual void xmitComplete(int a_rcStatus, RTHTTP a_hHttp) const RT_NOEXCEPT = 0; + + /** + * Checks if there are were any assignment errors. + */ + inline bool hasAssignmentErrors() const RT_NOEXCEPT { return m_fErrorSet != 0; } + +protected: + /** Set of fields that have been explicitly assigned a value. */ + uint64_t m_fIsSet; + /** Set of fields where value assigning failed. */ + uint64_t m_fErrorSet; + + /** Path parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The name string to replace (including {}). */ + size_t cchName; /**< Length of pszName. */ + uint32_t fFlags; /**< The toString flags. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } PATHPARAMDESC; + + /** Path parameter state. */ + typedef struct + { + RTCRestObjectBase const *pObj; /**< Pointer to the parameter object. */ + size_t offName; /**< Maintained by worker. */ + } PATHPARAMSTATE; + + /** + * Do path parameters. + * + * @returns IPRT status code + * @param a_pStrPath The destination path. + * @param a_pszPathTemplate The path template string. + * @param a_cchPathTemplate The length of the path template string. + * @param a_paPathParams The path parameter descriptors (static). + * @param a_paPathParamStates The path parameter objects and states. + * @param a_cPathParams Number of path parameters. + */ + int doPathParameters(RTCString *a_pStrPath, const char *a_pszPathTemplate, size_t a_cchPathTemplate, + PATHPARAMDESC const *a_paPathParams, PATHPARAMSTATE *a_paPathParamStates, size_t a_cPathParams) const RT_NOEXCEPT; + + /** Query parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + } QUERYPARAMDESC; + + /** + * Do query parameters. + * + * @returns IPRT status code + * @param a_pStrQuery The destination string. + * @param a_paQueryParams The query parameter descriptors. + * @param a_papQueryParamObjs The query parameter objects, parallel to @a a_paQueryParams. + * @param a_cQueryParams Number of query parameters. + */ + int doQueryParameters(RTCString *a_pStrQuery, QUERYPARAMDESC const *a_paQueryParams, + RTCRestObjectBase const **a_papQueryParamObjs, size_t a_cQueryParams) const RT_NOEXCEPT; + + /** Header parameter descriptor. */ + typedef struct + { + const char *pszName; /**< The parameter name. */ + uint32_t fFlags; /**< The toString flags. */ + bool fRequired; /**< Required or not. */ + uint8_t iBitNo; /**< The parameter bit number. */ + bool fMapCollection; /**< Collect headers starting with pszName into a map. */ + } HEADERPARAMDESC; + + /** + * Do header parameters. + * + * @returns IPRT status code + * @param a_hHttp Where to set header parameters. + * @param a_paHeaderParams The header parameter descriptors. + * @param a_papHeaderParamObjs The header parameter objects, parallel to @a a_paHeaderParams. + * @param a_cHeaderParams Number of header parameters. + */ + int doHeaderParameters(RTHTTP a_hHttp, HEADERPARAMDESC const *a_paHeaderParams, + RTCRestObjectBase const **a_papHeaderParamObjs, size_t a_cHeaderParams) const RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientResponseBase +{ +public: + /** Default constructor. */ + RTCRestClientResponseBase() RT_NOEXCEPT; + /** Destructor. */ + virtual ~RTCRestClientResponseBase(); + /** Copy constructor. */ + RTCRestClientResponseBase(RTCRestClientResponseBase const &a_rThat); + /** Copy assignment operator. */ + RTCRestClientResponseBase &operator=(RTCRestClientResponseBase const &a_rThat); + + /** + * Resets the object state. + */ + virtual void reset(void) RT_NOEXCEPT; + + /** + * Prepares the HTTP handle for receiving the response. + * + * This may install callbacks and such like. + * + * When overridden, the parent class must always be called. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP handle to prepare for receiving. + */ + virtual int receivePrepare(RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Called when the HTTP request has been completely received. + * + * @param a_rcStatus Negative numbers are IPRT errors, positive are HTTP status codes. + * @param a_hHttp The HTTP handle the request was performed on. + * This can be NIL_RTHTTP should something fail early, in + * which case it is possible receivePrepare() wasn't called. + * + * @note Called before consumeBody() but after consumeHeader(). + */ + virtual void receiveComplete(int a_rcStatus, RTHTTP a_hHttp) RT_NOEXCEPT; + + /** + * Callback that consumes HTTP body data from the server. + * + * @param a_pchData Body data. + * @param a_cbData Amount of body data. + * + * @note Called after consumeHeader(). + */ + virtual void consumeBody(const char *a_pchData, size_t a_cbData) RT_NOEXCEPT; + + /** + * Called after status, headers and body all have been presented. + * + * @returns IPRT status code. + */ + virtual void receiveFinal() RT_NOEXCEPT; + + /** + * Getter for m_rcStatus. + * @returns Negative numbers are IPRT errors, positive are HTTP status codes. + */ + inline int getStatus() const RT_NOEXCEPT { return m_rcStatus; } + + /** + * Getter for m_rcHttp. + * @returns HTTP status code or VERR_NOT_AVAILABLE. + */ + inline int getHttpStatus() const RT_NOEXCEPT { return m_rcHttp; } + + /** + * Getter for m_pErrInfo. + */ + inline PCRTERRINFO getErrInfo(void) const RT_NOEXCEPT { return m_pErrInfo; } + + /** + * Getter for m_strContentType. + */ + inline RTCString const &getContentType(void) const RT_NOEXCEPT { return m_strContentType; } + + +protected: + /** Negative numbers are IPRT errors, positive are HTTP status codes. */ + int m_rcStatus; + /** The HTTP status code, VERR_NOT_AVAILABLE if not set. */ + int m_rcHttp; + /** Error information. */ + PRTERRINFO m_pErrInfo; + /** The value of the Content-Type header field. */ + RTCString m_strContentType; + + PRTERRINFO getErrInfoInternal(void) RT_NOEXCEPT; + void deleteErrInfo(void) RT_NOEXCEPT; + void copyErrInfo(PCRTERRINFO pErrInfo) RT_NOEXCEPT; + + /** + * Reports an error (or warning if a_rc non-negative). + * + * @returns a_rc + * @param a_rc The status code to report and return. The first + * error status is assigned to m_rcStatus, subsequent + * ones as well as informational statuses are not + * recorded by m_rcStatus. + * @param a_pszFormat The message format string. + * @param ... Message arguments. + */ + int addError(int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pObj The object to deserialize into. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeader(RTCRestObjectBase *a_pObj, const char *a_pchValue, size_t a_cchValue, + uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Deserializes a header field value. + * + * @returns IPRT status code. + * @param a_pMap The string map object to deserialize into. + * @param a_pchField Pointer to the map field name. (Caller dropped the prefix.) + * Not necessarily valid UTF-8! + * @param a_cchField Length of field name. + * @param a_pchValue Pointer to the value (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchValue The value length. + * @param a_fFlags Flags to pass to fromString(). + * @param a_pszErrorTag The error tag (field name). + */ + int deserializeHeaderIntoMap(RTCRestStringMapBase *a_pMap, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue, uint32_t a_fFlags, const char *a_pszErrorTag) RT_NOEXCEPT; + + /** + * Helper that does the deserializing of the response body + * via deserializeBodyFromJsonCursor(). + * + * @param a_pchData The body blob. + * @param a_cbData The size of the body blob. + * @param a_pszBodyName The name of the body parameter. + */ + void deserializeBody(const char *a_pchData, size_t a_cbData, const char *a_pszBodyName) RT_NOEXCEPT; + + /** + * Called by deserializeBody to do the actual body deserialization. + * + * @param a_rCursor The JSON cursor. + */ + virtual void deserializeBodyFromJsonCursor(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT; + + /** + * Primary json cursor for parsing bodies. + */ + class PrimaryJsonCursorForBody : public RTCRestJsonPrimaryCursor + { + public: + RTCRestClientResponseBase *m_pThat; /**< Pointer to response object. */ + PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName, RTCRestClientResponseBase *a_pThat) RT_NOEXCEPT; + virtual int addError(RTCRestJsonCursor const &a_rCursor, int a_rc, const char *a_pszFormat, ...) RT_NOEXCEPT RT_OVERRIDE; + virtual int unknownField(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE; + }; + + + /** + * Consumes a header. + * + * Child classes can override this to pick up their header fields, but must + * always call the parent class. + * + * @returns IPRT status code. + * @param a_uMatchWord Match word constructed by RTHTTP_MAKE_HDR_MATCH_WORD + * @param a_pchField The field name (not zero terminated). + * Not necessarily valid UTF-8! + * @param a_cchField The length of the field. + * @param a_pchValue The field value (not zero terminated). + * @param a_cchValue The length of the value. + */ + virtual int consumeHeader(uint32_t a_uMatchWord, const char *a_pchField, size_t a_cchField, + const char *a_pchValue, size_t a_cchValue) RT_NOEXCEPT; + +private: + /** Callback for use with RTHttpSetHeaderCallback. */ + static DECLCALLBACK(int) receiveHttpHeaderCallback(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, + const char *pchValue, size_t cchValue, void *pvUser) RT_NOEXCEPT; +}; + + +/** + * Base class for REST client responses. + */ +class RT_DECL_CLASS RTCRestClientApiBase +{ +public: + RTCRestClientApiBase() RT_NOEXCEPT; + virtual ~RTCRestClientApiBase(); + + /** @name Host and Base path (URL) handling. + * @{ */ + /** + * Gets the server URL. + */ + const char *getServerUrl(void) const RT_NOEXCEPT; + + /** + * Sets the whole server URL. + * @returns IPRT status code. + * @param a_pszUrl The new server URL. NULL/empty to reset to default. + */ + int setServerUrl(const char *a_pszUrl) RT_NOEXCEPT; + + /** + * Sets the scheme part of the the server URL. + * @returns IPRT status code. + * @param a_pszScheme The new scheme. Does not accept NULL or empty string. + */ + int setServerScheme(const char *a_pszScheme) RT_NOEXCEPT; + + /** + * Sets the authority (hostname + port) part of the the server URL. + * @returns IPRT status code. + * @param a_pszAuthority The new authority. Does not accept NULL or empty string. + */ + int setServerAuthority(const char *a_pszAuthority) RT_NOEXCEPT; + + /** + * Sets the base path part of the the server URL. + * @returns IPRT status code. + * @param a_pszBasePath The new base path. Does not accept NULL or empty string. + */ + int setServerBasePath(const char *a_pszBasePath) RT_NOEXCEPT; + + /** + * Gets the default server URL as specified in the specs. + * @returns Server URL. + */ + virtual const char *getDefaultServerUrl() const RT_NOEXCEPT = 0; + + /** + * Gets the default server base path as specified in the specs. + * @returns Host string (start of URL). + */ + virtual const char *getDefaultServerBasePath() const RT_NOEXCEPT = 0; + /** @} */ + + /** Flags to doCall. */ + enum + { + kDoCall_OciReqSignExcludeBody = 1, /**< Exclude the body when doing OCI request signing. */ + kDoCall_RequireBody = 2 /**< The body is required. */ + }; + +protected: + /** Handle to the HTTP connection object. */ + RTHTTP m_hHttp; + /** The server URL to use. If empty use the default. */ + RTCString m_strServerUrl; + + /* Make non-copyable (RTCNonCopyable causes warnings): */ + RTCRestClientApiBase(RTCRestClientApiBase const &); + RTCRestClientApiBase *operator=(RTCRestClientApiBase const &); + + /** + * Re-initializes the HTTP instance. + * + * @returns IPRT status code. + */ + virtual int reinitHttpInstance() RT_NOEXCEPT; + + /** + * Hook that's called when doCall has fully assembled the request. + * + * Can be used for request signing and similar final steps. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + */ + virtual int xmitReady(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements stuff for making an API call. + * + * @returns a_pResponse->getStatus() + * @param a_rRequest Reference to the request object. + * @param a_enmHttpMethod The HTTP request method. + * @param a_pResponse Pointer to the response object. + * @param a_pszMethod The method name, for logging purposes. + * @param a_fFlags kDoCall_XXX. + */ + virtual int doCall(RTCRestClientRequestBase const &a_rRequest, RTHTTPMETHOD a_enmHttpMethod, + RTCRestClientResponseBase *a_pResponse, const char *a_pszMethod, uint32_t a_fFlags) RT_NOEXCEPT; + + /** + * Implements OCI style request signing. + * + * @returns IPRT status code. + * @param a_hHttp The HTTP client instance. + * @param a_rStrFullUrl The full URL. + * @param a_enmHttpMethod The HTTP request method. + * @param a_rStrXmitBody The body text. + * @param a_fFlags kDoCall_XXX. + * @param a_hKey The key to use for signing. + * @param a_rStrKeyId The key ID. + * + * @remarks The signing scheme is covered by a series of drafts RFC, the latest being: + * https://tools.ietf.org/html/draft-cavage-http-signatures-10 + */ + int ociSignRequest(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags, RTCRKEY a_hKey, RTCString const &a_rStrKeyId) RT_NOEXCEPT; + + /** + * Worker for the server URL modifiers. + * + * @returns IPRT status code. + * @param a_pszServerUrl The current server URL (for comparing). + * @param a_offDst The offset of the component in the current server URL. + * @param a_cchDst The current component length. + * @param a_pszSrc The new URL component value. + * @param a_cchSrc The length of the new component. + */ + int setServerUrlPart(const char *a_pszServerUrl, size_t a_offDst, size_t a_cchDst, const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT; +}; + +/** @} */ + +#endif /* !IPRT_INCLUDED_cpp_restclient_h */ + |