diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp')
-rw-r--r-- | src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp b/src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp new file mode 100644 index 00000000..9bda2a12 --- /dev/null +++ b/src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp @@ -0,0 +1,307 @@ +/* $Id: RTCRestClientApiBase.cpp $ */ +/** @file + * IPRT - C++ REST, RTCRestClientApiBase implementation. + */ + +/* + * Copyright (C) 2018-2019 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP RTLOGGROUP_REST +#include <iprt/cpp/restclient.h> + +#include <iprt/assert.h> +#include <iprt/ctype.h> +#include <iprt/errcore.h> +#include <iprt/http.h> +#include <iprt/log.h> +#include <iprt/uri.h> + + +/** + * Default constructor. + */ +RTCRestClientApiBase::RTCRestClientApiBase() RT_NOEXCEPT + : m_hHttp(NIL_RTHTTP) +{ +} + + +/** + * The destructor. + */ +RTCRestClientApiBase::~RTCRestClientApiBase() +{ + if (m_hHttp != NIL_RTHTTP) + { + int rc = RTHttpDestroy(m_hHttp); + AssertRC(rc); + m_hHttp = NIL_RTHTTP; + } +} + + +const char *RTCRestClientApiBase::getServerUrl(void) const RT_NOEXCEPT +{ + if (m_strServerUrl.isEmpty()) + return getDefaultServerUrl(); + return m_strServerUrl.c_str(); +} + + +int RTCRestClientApiBase::setServerUrl(const char *a_pszUrl) RT_NOEXCEPT +{ +#ifdef RT_STRICT + if (a_pszUrl) + { + RTURIPARSED Parsed; + int rc = RTUriParse(a_pszUrl, &Parsed); + AssertRC(rc); + } +#endif + + return m_strServerUrl.assignNoThrow(a_pszUrl); +} + + +int RTCRestClientApiBase::setServerUrlPart(const char *a_pszServerUrl, size_t a_offDst, size_t a_cchDst, + const char *a_pszSrc, size_t a_cchSrc) RT_NOEXCEPT +{ + if ( a_cchDst == a_cchSrc + && memcmp(&a_pszServerUrl[0], a_pszSrc, a_cchSrc) == 0) + return VINF_SUCCESS; + + if (m_strServerUrl.isEmpty()) + { + int rc = m_strServerUrl.assignNoThrow(a_pszServerUrl); + AssertRCReturn(rc, rc); + } + return m_strServerUrl.replaceNoThrow(a_offDst, a_cchDst, a_pszSrc, a_cchSrc); +} + + +int RTCRestClientApiBase::setServerScheme(const char *a_pszScheme) RT_NOEXCEPT +{ + /* + * Validate. + */ + AssertReturn(a_pszScheme, VERR_INVALID_POINTER); + size_t const cchScheme = strlen(a_pszScheme); + AssertReturn(cchScheme > 0, VERR_INVALID_PARAMETER); + Assert(cchScheme < 16); +#ifdef RT_STRICT + for (size_t i = 0; i < cchScheme; i++) + Assert(RT_C_IS_ALNUM(a_pszScheme[i])); +#endif + + /* + * Parse, compare & replace. + */ + RTURIPARSED Parsed; + const char *pszUrl = getServerUrl(); + int rc = RTUriParse(pszUrl, &Parsed); + AssertRCReturn(rc, rc); + return setServerUrlPart(pszUrl, 0, Parsed.cchScheme, a_pszScheme, cchScheme); +} + + +int RTCRestClientApiBase::setServerAuthority(const char *a_pszAuthority) RT_NOEXCEPT +{ + /* + * Validate. + */ + AssertReturn(a_pszAuthority, VERR_INVALID_POINTER); + size_t const cchAuthority = strlen(a_pszAuthority); + AssertReturn(cchAuthority > 0, VERR_INVALID_PARAMETER); + Assert(memchr(a_pszAuthority, '/', cchAuthority) == NULL); + Assert(memchr(a_pszAuthority, '\\', cchAuthority) == NULL); + Assert(memchr(a_pszAuthority, '#', cchAuthority) == NULL); + Assert(memchr(a_pszAuthority, '?', cchAuthority) == NULL); + + /* + * Parse, compare & replace. + */ + RTURIPARSED Parsed; + const char *pszUrl = getServerUrl(); + int rc = RTUriParse(pszUrl, &Parsed); + AssertRCReturn(rc, rc); + return setServerUrlPart(pszUrl, Parsed.offAuthority, Parsed.cchAuthority, a_pszAuthority, cchAuthority); +} + + +int RTCRestClientApiBase::setServerBasePath(const char *a_pszBasePath) RT_NOEXCEPT +{ + /* + * Validate. + */ + AssertReturn(a_pszBasePath, VERR_INVALID_POINTER); + size_t const cchBasePath = strlen(a_pszBasePath); + AssertReturn(cchBasePath > 0, VERR_INVALID_PARAMETER); + Assert(memchr(a_pszBasePath, '?', cchBasePath) == NULL); + Assert(memchr(a_pszBasePath, '#', cchBasePath) == NULL); + + /* + * Parse, compare & replace. + */ + RTURIPARSED Parsed; + const char *pszUrl = getServerUrl(); + int rc = RTUriParse(pszUrl, &Parsed); + AssertRCReturn(rc, rc); + return setServerUrlPart(pszUrl, Parsed.offPath, Parsed.cchPath, a_pszBasePath, cchBasePath); +} + + +int RTCRestClientApiBase::reinitHttpInstance() RT_NOEXCEPT +{ + if (m_hHttp != NIL_RTHTTP) + { +#if 0 /** @todo XXX: disable for now as it causes the RTHTTP handle state and curl state to get out of sync. */ + return RTHttpReset(m_hHttp, 0 /*fFlags*/); +#else + RTHttpDestroy(m_hHttp); + m_hHttp = NIL_RTHTTP; +#endif + } + + int rc = RTHttpCreate(&m_hHttp); + if (RT_FAILURE(rc)) + m_hHttp = NIL_RTHTTP; + return rc; +} + + +int RTCRestClientApiBase::xmitReady(RTHTTP a_hHttp, RTCString const &a_rStrFullUrl, RTHTTPMETHOD a_enmHttpMethod, + RTCString const &a_rStrXmitBody, uint32_t a_fFlags) RT_NOEXCEPT +{ + RT_NOREF(a_hHttp, a_rStrFullUrl, a_enmHttpMethod, a_rStrXmitBody, a_fFlags); + return VINF_SUCCESS; +} + + +int RTCRestClientApiBase::doCall(RTCRestClientRequestBase const &a_rRequest, RTHTTPMETHOD a_enmHttpMethod, + RTCRestClientResponseBase *a_pResponse, const char *a_pszMethod, uint32_t a_fFlags) RT_NOEXCEPT +{ + LogFlow(("doCall: %s %s\n", a_pszMethod, RTHttpMethodName(a_enmHttpMethod))); + + + /* + * Reset the response object (allowing reuse of such) and check the request + * object for assignment errors. + */ + int rc; + RTHTTP hHttp = NIL_RTHTTP; + + a_pResponse->reset(); + if (!a_rRequest.hasAssignmentErrors()) + { + /* + * Initialize the HTTP instance. + */ + rc = reinitHttpInstance(); + if (RT_SUCCESS(rc)) + { + hHttp = m_hHttp; + Assert(hHttp != NIL_RTHTTP); + + /* + * Prepare the response side. + */ + rc = a_pResponse->receivePrepare(hHttp); + if (RT_SUCCESS(rc)) + { + /* + * Prepare the request for the transmission. + */ + RTCString strExtraPath; + RTCString strQuery; + RTCString strXmitBody; + rc = a_rRequest.xmitPrepare(&strExtraPath, &strQuery, hHttp, &strXmitBody); + if (RT_SUCCESS(rc)) + { + /* + * Construct the full URL. + */ + RTCString strFullUrl; + rc = strFullUrl.assignNoThrow(getServerUrl()); + if (strExtraPath.isNotEmpty()) + { + if (!strExtraPath.startsWith("/") && !strFullUrl.endsWith("/") && RT_SUCCESS(rc)) + rc = strFullUrl.appendNoThrow('/'); + if (RT_SUCCESS(rc)) + rc = strFullUrl.appendNoThrow(strExtraPath); + strExtraPath.setNull(); + } + if (strQuery.isNotEmpty()) + { + Assert(strQuery.startsWith("?")); + rc = strFullUrl.appendNoThrow(strQuery); + strQuery.setNull(); + } + if (RT_SUCCESS(rc)) + { + rc = xmitReady(hHttp, strFullUrl, a_enmHttpMethod, strXmitBody, a_fFlags); + if (RT_SUCCESS(rc)) + { + /* + * Perform HTTP request. + */ + uint32_t uHttpStatus = 0; + size_t cbBody = 0; + void *pvBody = NULL; + rc = RTHttpPerform(hHttp, strFullUrl.c_str(), a_enmHttpMethod, + strXmitBody.c_str(), strXmitBody.length(), + &uHttpStatus, NULL /*ppvHdrs*/, NULL /*pcbHdrs*/, &pvBody, &cbBody); + if (RT_SUCCESS(rc)) + { + a_rRequest.xmitComplete(uHttpStatus, hHttp); + + /* + * Do response processing. + */ + a_pResponse->receiveComplete(uHttpStatus, hHttp); + if (pvBody) + { + a_pResponse->consumeBody((const char *)pvBody, cbBody); + RTHttpFreeResponse(pvBody); + } + a_pResponse->receiveFinal(); + + return a_pResponse->getStatus(); + } + } + } + } + a_rRequest.xmitComplete(rc, hHttp); + } + } + } + else + rc = VERR_NO_MEMORY; + + a_pResponse->receiveComplete(rc, hHttp); + RT_NOREF_PV(a_pszMethod); + + return a_pResponse->getStatus(); +} + |