VirtualBox

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

Last change on this file since 86694 was 86682, checked in by vboxsync, 4 years ago

IPRT/rest: bugref:9167 - Add missing format in an assert message,
forgotten in previous.

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