/* $Id: RTCRestClientApiBase.cpp 74348 2018-09-18 17:06:05Z vboxsync $ */ /** @file * IPRT - C++ REST, RTCRestClientApiBase implementation. */ /* * Copyright (C) 2018 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 #include #include #include /** * Default constructor. */ RTCRestClientApiBase::RTCRestClientApiBase() : 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::getHost() const { return m_strHost.isEmpty() ? getDefaultHost() : m_strHost.c_str(); } int RTCRestClientApiBase::setHost(const char *a_pszHost) { return m_strHost.assignNoThrow(a_pszHost); } int RTCRestClientApiBase::setHost(RTCString const &a_strPath) { return setHost(a_strPath.c_str()); } const char *RTCRestClientApiBase::getBasePath(void) const { return m_strBasePath.isEmpty() ? getDefaultBasePath() : m_strBasePath.c_str(); } int RTCRestClientApiBase::setBasePath(const char *a_pszPath) { return m_strBasePath.assignNoThrow(a_pszPath); } int RTCRestClientApiBase::setBasePath(RTCString const &a_strPath) { return setBasePath(a_strPath.c_str()); } int RTCRestClientApiBase::reinitHttpInstance() { if (m_hHttp != NIL_RTHTTP) { #if 0 /* * XXX: disable for now as it causes the RTHTTP handle state * and curl state to get out of sync. */ return RTHttpReset(m_hHttp); #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_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) { 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(getHost()); if (RT_SUCCESS(rc)) rc = strFullUrl.appendNoThrow(getBasePath()); 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(); }