VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestClientRequestBase.cpp@ 98859

Last change on this file since 98859 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: RTCRestClientRequestBase.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestClientRequestBase implementation.
4 */
5
6/*
7 * Copyright (C) 2018-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_REST
42#include <iprt/cpp/restclient.h>
43
44#include <iprt/assert.h>
45#include <iprt/err.h>
46#include <iprt/log.h>
47#include <iprt/cpp/restarray.h>
48#include <iprt/cpp/reststringmap.h>
49
50
51/**
52 * Default constructor.
53 */
54RTCRestClientRequestBase::RTCRestClientRequestBase() RT_NOEXCEPT
55 : m_fIsSet(0)
56 , m_fErrorSet(0)
57{
58}
59
60
61/**
62 * Copy constructor.
63 */
64RTCRestClientRequestBase::RTCRestClientRequestBase(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT
65 : m_fIsSet(a_rThat.m_fIsSet)
66 , m_fErrorSet(a_rThat.m_fErrorSet)
67{
68}
69
70
71/**
72 * Destructor
73 */
74RTCRestClientRequestBase::~RTCRestClientRequestBase()
75{
76 /* nothing to do */
77}
78
79
80/**
81 * Copy assignment operator.
82 */
83RTCRestClientRequestBase &RTCRestClientRequestBase::operator=(RTCRestClientRequestBase const &a_rThat) RT_NOEXCEPT
84{
85 m_fIsSet = a_rThat.m_fIsSet;
86 m_fErrorSet = a_rThat.m_fErrorSet;
87 return *this;
88}
89
90
91int RTCRestClientRequestBase::doPathParameters(RTCString *a_pStrPath, const char *a_pszPathTemplate, size_t a_cchPathTemplate,
92 PATHPARAMDESC const *a_paPathParams, PATHPARAMSTATE *a_paPathParamStates,
93 size_t a_cPathParams) const RT_NOEXCEPT
94{
95 int rc = a_pStrPath->assignNoThrow(a_pszPathTemplate, a_cchPathTemplate);
96 AssertRCReturn(rc, rc);
97
98 /* Locate the sub-string to replace with values first: */
99 for (size_t i = 0; i < a_cPathParams; i++)
100 {
101 char const *psz = strstr(a_pszPathTemplate, a_paPathParams[i].pszName);
102 AssertReturn(psz, VERR_INTERNAL_ERROR_5);
103 a_paPathParamStates[i].offName = psz - a_pszPathTemplate;
104 }
105
106 /* Replace with actual values: */
107 for (size_t i = 0; i < a_cPathParams; i++)
108 {
109 AssertReturn( (a_paPathParams[i].fFlags & RTCRestObjectBase::kCollectionFormat_Mask)
110 != RTCRestObjectBase::kCollectionFormat_multi,
111 VERR_INTERNAL_ERROR_3);
112 AssertMsgReturn(a_paPathParamStates[i].pObj != NULL,
113 ("%s: Path parameter '%s' is not set!\n",
114 getOperationName(), a_paPathParams[i].pszName),
115 VERR_REST_PATH_PARAMETER_NOT_SET);
116 AssertMsgReturn(m_fIsSet & RT_BIT_64(a_paPathParams[i].iBitNo),
117 ("%s: Path parameter '%s' is not set!\n",
118 getOperationName(), a_paPathParams[i].pszName),
119 VERR_REST_PATH_PARAMETER_NOT_SET);
120
121 RTCString strPathParam;
122 rc = a_paPathParamStates[i].pObj->toString(&strPathParam, a_paPathParams[i].fFlags);
123 AssertRCReturn(rc, rc);
124
125 LogRel5(("> %s: /%s = %s\n",
126 getOperationName(), a_paPathParams[i].pszName, strPathParam.c_str()));
127
128 RTCString strTmpVal;
129 rc = strTmpVal.printfNoThrow("%RMpa", strPathParam.c_str()); /* urlencode */
130 AssertRCReturn(rc, rc);
131
132 /* Replace. */
133 ssize_t cchAdjust = strTmpVal.length() - a_paPathParams[i].cchName;
134 rc = a_pStrPath->replaceNoThrow(a_paPathParamStates[i].offName, a_paPathParams[i].cchName, strTmpVal);
135 AssertRCReturn(rc, rc);
136
137 /* Adjust subsequent fields. */
138 if (cchAdjust != 0)
139 for (size_t j = i + 1; j < a_cPathParams; j++)
140 if (a_paPathParamStates[j].offName > a_paPathParamStates[i].offName)
141 a_paPathParamStates[j].offName += cchAdjust;
142 }
143
144 return VINF_SUCCESS;
145}
146
147
148int RTCRestClientRequestBase::doQueryParameters(RTCString *a_pStrQuery, QUERYPARAMDESC const *a_paQueryParams,
149 RTCRestObjectBase const **a_papQueryParamObjs, size_t a_cQueryParams) const RT_NOEXCEPT
150{
151 RTCString strTmpVal;
152 char chSep = a_pStrQuery->isEmpty() ? '?' : '&';
153 for (size_t i = 0; i < a_cQueryParams; i++)
154 {
155 if ( a_paQueryParams[i].fRequired
156 || (m_fIsSet & RT_BIT_64(a_paQueryParams[i].iBitNo)) )
157 {
158 AssertMsgReturn(a_papQueryParamObjs[i] != NULL,
159 ("%s: Required query parameter '%s' is not set!\n",
160 getOperationName(), a_paQueryParams[i].pszName),
161 VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET);
162 AssertMsgReturn(m_fIsSet & RT_BIT_64(a_paQueryParams[i].iBitNo),
163 ("%s: Required query parameter '%s' is not set!\n",
164 getOperationName(), a_paQueryParams[i].pszName),
165 VERR_REST_REQUIRED_QUERY_PARAMETER_NOT_SET);
166
167 if ( (a_paQueryParams[i].fFlags & RTCRestObjectBase::kCollectionFormat_Mask)
168 != RTCRestObjectBase::kCollectionFormat_multi)
169 {
170 int rc = a_papQueryParamObjs[i]->toString(&strTmpVal, a_paQueryParams[i].fFlags);
171 AssertRCReturn(rc, rc);
172
173 rc = a_pStrQuery->appendPrintfNoThrow("%c%RMpa=%RMpa", chSep, a_paQueryParams[i].pszName, strTmpVal.c_str());
174 AssertRCReturn(rc, rc);
175
176 LogRel5(("> %s: ?%s = %s\n",
177 getOperationName(), a_paQueryParams[i].pszName, strTmpVal.c_str()));
178
179 chSep = '&';
180 }
181 else
182 {
183 /*
184 * Enumerate array and add 'name=element' for each element in it.
185 */
186 AssertReturn(a_papQueryParamObjs[i]->typeClass() == RTCRestObjectBase::kTypeClass_Array,
187 VERR_REST_INTERNAL_ERROR_2);
188 RTCRestArrayBase const *pArray = (RTCRestArrayBase const *)a_papQueryParamObjs[i];
189 for (size_t j = 0; j < pArray->size(); j++)
190 {
191 RTCRestObjectBase const *pObj = pArray->atBase(j);
192 int rc = pObj->toString(&strTmpVal, a_paQueryParams[i].fFlags & ~RTCRestObjectBase::kCollectionFormat_Mask);
193 AssertRCReturn(rc, rc);
194
195 rc = a_pStrQuery->appendPrintfNoThrow("%c%RMpa=%RMpa", chSep, a_paQueryParams[i].pszName, strTmpVal.c_str());
196 AssertRCReturn(rc, rc);
197
198 LogRel5(("> %s: ?%s[%d] = %s\n",
199 getOperationName(), a_paQueryParams[i].pszName, j, strTmpVal.c_str()));
200
201 chSep = '&';
202 }
203 }
204 }
205 }
206 return VINF_SUCCESS;
207}
208
209
210int RTCRestClientRequestBase::doHeaderParameters(RTHTTP a_hHttp, HEADERPARAMDESC const *a_paHeaderParams,
211 RTCRestObjectBase const **a_papHeaderParamObjs, size_t a_cHeaderParams) const RT_NOEXCEPT
212{
213 RTCString strTmpVal;
214 for (size_t i = 0; i < a_cHeaderParams; i++)
215 {
216 AssertReturn( (a_paHeaderParams[i].fFlags & RTCRestObjectBase::kCollectionFormat_Mask)
217 != RTCRestObjectBase::kCollectionFormat_multi,
218 VERR_INTERNAL_ERROR_3);
219
220 if ( a_paHeaderParams[i].fRequired
221 || (m_fIsSet & RT_BIT_64(a_paHeaderParams[i].iBitNo)) )
222 {
223 AssertMsgReturn(m_fIsSet & RT_BIT_64(a_paHeaderParams[i].iBitNo),
224 ("%s: Required header parameter '%s' is not set!\n",
225 getOperationName(), a_paHeaderParams[i].pszName),
226 VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET);
227 AssertMsgReturn(a_papHeaderParamObjs[i] != NULL,
228 ("%s: Required header parameter '%s' is not set!\n",
229 getOperationName(), a_paHeaderParams[i].pszName),
230 VERR_REST_REQUIRED_HEADER_PARAMETER_NOT_SET);
231
232 if (!a_paHeaderParams[i].fMapCollection)
233 {
234 int rc = a_papHeaderParamObjs[i]->toString(&strTmpVal, a_paHeaderParams[i].fFlags);
235 AssertRCReturn(rc, rc);
236
237 rc = RTHttpAddHeader(a_hHttp, a_paHeaderParams[i].pszName, strTmpVal.c_str(), strTmpVal.length(),
238 RTHTTPADDHDR_F_BACK);
239 AssertRCReturn(rc, rc);
240
241 LogRel5(("> %s: :%s = %s\n",
242 getOperationName(), a_paHeaderParams[i].pszName, strTmpVal.c_str()));
243 }
244 else if (!a_papHeaderParamObjs[i]->isNull())
245 {
246 /*
247 * Enumerate the map and produce a series of head fields on the form:
248 * (a_paHeaderParams[i].pszName + key): value.toString()
249 */
250 AssertReturn(a_papHeaderParamObjs[i]->typeClass() == RTCRestObjectBase::kTypeClass_StringMap,
251 VERR_REST_INTERNAL_ERROR_1);
252 RTCRestStringMapBase const *pMap = (RTCRestStringMapBase const *)a_papHeaderParamObjs[i];
253 const size_t cchName = strlen(a_paHeaderParams[i].pszName);
254 Assert(a_paHeaderParams[i].pszName[cchName - 1] != '*');
255 RTCString strTmpName;
256 for (RTCRestStringMapBase::ConstIterator it = pMap->begin(); it != pMap->end(); ++it)
257 {
258 int rc = strTmpName.assignNoThrow(a_paHeaderParams[i].pszName, cchName);
259 AssertRCReturn(rc, rc);
260 rc = strTmpName.appendNoThrow(it.getKey());
261 AssertRCReturn(rc, rc);
262
263 rc = it.getValue()->toString(&strTmpVal, a_paHeaderParams[i].fFlags);
264 AssertRCReturn(rc, rc);
265
266 rc = RTHttpAddHeader(a_hHttp, strTmpName.c_str(), strTmpVal.c_str(), strTmpVal.length(),
267 RTHTTPADDHDR_F_BACK);
268 AssertRCReturn(rc, rc);
269
270 LogRel5(("> %s: :%s = %s\n",
271 getOperationName(), strTmpName.c_str(), strTmpVal.c_str()));
272 }
273 }
274 else
275 Assert(!a_paHeaderParams[i].fRequired);
276 }
277 }
278 return VINF_SUCCESS;
279}
280
Note: See TracBrowser for help on using the repository browser.

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