Changeset 74250 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Sep 13, 2018 4:33:17 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 125044
- Location:
- trunk/src/VBox/Runtime/common/rest
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/rest/RTCRestClientApiBase.cpp
r74192 r74250 108 108 109 109 /* 110 * Prepare the response side. This may install output callbacks and 111 * indicate this by clearing the ppvBody/ppvHdr variables. 110 * Prepare the response side. 112 111 */ 113 size_t cbHdrs = 0; 114 void *pvHdrs = NULL; 115 void **ppvHdrs = &pvHdrs; 116 117 size_t cbBody = 0; 118 void *pvBody = NULL; 119 void **ppvBody = &pvBody; 120 121 rc = a_pResponse->receivePrepare(hHttp, &ppvBody, &ppvHdrs); 112 rc = a_pResponse->receivePrepare(hHttp); 122 113 if (RT_SUCCESS(rc)) 123 114 { … … 159 150 */ 160 151 uint32_t uHttpStatus = 0; 152 size_t cbBody = 0; 153 void *pvBody = NULL; 161 154 rc = RTHttpPerform(hHttp, strFullUrl.c_str(), a_enmHttpMethod, 162 155 strXmitBody.c_str(), strXmitBody.length(), 163 &uHttpStatus, ppvHdrs, &cbHdrs, ppvBody, &cbBody);156 &uHttpStatus, NULL /*ppvHdrs*/, NULL /*pcbHdrs*/, &pvBody, &cbBody); 164 157 if (RT_SUCCESS(rc)) 165 158 { … … 170 163 */ 171 164 a_pResponse->receiveComplete(uHttpStatus, hHttp); 172 if (pvHdrs)173 {174 a_pResponse->consumeHeaders((const char *)pvHdrs, cbHdrs);175 RTHttpFreeResponse(pvHdrs);176 }177 165 if (pvBody) 178 166 { -
trunk/src/VBox/Runtime/common/rest/RTCRestClientResponseBase.cpp
r74232 r74250 99 99 100 100 101 int RTCRestClientResponseBase::receivePrepare(RTHTTP a_hHttp, void ***a_pppvHdr, void ***a_pppvBody) 102 { 103 RT_NOREF(a_hHttp, a_pppvHdr, a_pppvBody); 101 int RTCRestClientResponseBase::receivePrepare(RTHTTP a_hHttp) 102 { 103 int rc = RTHttpSetHeaderCallback(a_hHttp, receiveHttpHeaderCallback, this); 104 AssertRCReturn(rc, rc); 105 104 106 return VINF_SUCCESS; 105 107 } … … 112 114 if (a_rcStatus >= 0) 113 115 m_rcHttp = a_rcStatus; 114 } 115 116 117 void RTCRestClientResponseBase::consumeHeaders(const char *a_pchData, size_t a_cbData) 118 { 119 /* 120 * Get the the content type. 121 */ 122 int rc = extractHeaderFromBlob(RT_STR_TUPLE("Content-Type"), a_pchData, a_cbData, &m_strContentType); 123 if (rc == VERR_NOT_FOUND) 124 rc = VINF_SUCCESS; 125 AssertRCReturnVoidStmt(rc, m_rcStatus = rc); 116 117 int rc = RTHttpSetHeaderCallback(a_hHttp, NULL, NULL); 118 AssertRC(rc); 119 } 120 121 122 int RTCRestClientResponseBase::consumeHeader(uint32_t a_uMatchWord, const char *a_pchField, size_t a_cchField, 123 const char *a_pchValue, size_t a_cchValue) 124 { 125 if ( a_uMatchWord == RTHTTP_MAKE_HDR_MATCH_WORD(sizeof("Content-Type") - 1, 'c', 'o', 'n') 126 && RTStrNICmpAscii(a_pchField, RT_STR_TUPLE("Content-Type")) == 0) 127 { 128 int rc = RTStrValidateEncodingEx(a_pchValue, a_cchValue, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH); 129 AssertRC(rc); 130 if (RT_SUCCESS(rc)) 131 return m_strContentType.assignNoThrow(a_pchValue, a_cchValue); 132 } 133 RT_NOREF(a_cchField); 134 return VINF_SUCCESS; 135 } 136 137 138 /*static*/ DECLCALLBACK(int) 139 RTCRestClientResponseBase::receiveHttpHeaderCallback(RTHTTP hHttp, uint32_t uMatchWord, const char *pchField, size_t cchField, 140 const char *pchValue, size_t cchValue, void *pvUser) 141 { 142 RTCRestClientResponseBase *pThis = (RTCRestClientResponseBase *)pvUser; 143 RT_NOREF(hHttp); 144 return pThis->consumeHeader(uMatchWord, pchField, cchField, pchValue, cchValue); 126 145 } 127 146 … … 194 213 195 214 196 void RTCRestClientResponseBase::extractHeaderFieldsFromBlob(HEADERFIELDDESC const *a_paFieldDescs,197 RTCRestObjectBase ***a_pappFieldValues,198 size_t a_cFields, const char *a_pchData, size_t a_cbData)199 200 {201 RTCString strValue; /* (Keep it out here to encourage buffer allocation reuse and default construction call.) */202 203 /*204 * Work our way through the header blob.205 */206 while (a_cbData >= 2)207 {208 /*209 * Determine length of the header name:value combo.210 * Note! Multi-line field values are not currently supported.211 */212 const char *pchEol = (const char *)memchr(a_pchData, '\n', a_cbData);213 while (pchEol && (pchEol == a_pchData || pchEol[-1] != '\r'))214 pchEol = (const char *)memchr(pchEol, '\n', a_cbData - (pchEol - a_pchData));215 216 size_t const cchField = pchEol ? pchEol - a_pchData + 1 : a_cbData;217 size_t const cchFieldNoCrLf = pchEol ? pchEol - a_pchData - 1 : a_cbData;218 219 const char *pchColon = (const char *)memchr(a_pchData, ':', cchFieldNoCrLf);220 if (pchColon)221 {222 size_t const cchName = pchColon - a_pchData;223 size_t const offValue = cchName + (RT_C_IS_BLANK(pchColon[1]) ? 2 : 1);224 size_t const cchValue = cchFieldNoCrLf - offValue;225 226 /*227 * Match headers.228 */229 bool fHaveValue = false;230 for (size_t i = 0; i < a_cFields; i++)231 {232 size_t const cchThisName = a_paFieldDescs[i].cchName;233 if ( (!(a_paFieldDescs[i].fFlags & kHdrField_MapCollection) ? cchThisName == cchName : cchThisName < cchName)234 && RTStrNICmpAscii(a_pchData, a_paFieldDescs[i].pszName, cchThisName) == 0)235 {236 /* Get and clean the value. */237 if (!fHaveValue)238 {239 int rc = strValue.assignNoThrow(&a_pchData[offValue], cchValue);240 if (RT_SUCCESS(rc))241 {242 RTStrPurgeEncoding(strValue.mutableRaw()); /** @todo this is probably a little wrong... */243 fHaveValue = true;244 }245 else246 {247 addError(rc, "Error allocating %u bytes for header field %s", a_paFieldDescs[i].pszName);248 break;249 }250 }251 252 /*253 * Create field to deserialize.254 */255 RTCRestStringMapBase *pMap = NULL;256 RTCRestObjectBase *pObj = NULL;257 if (!(a_paFieldDescs[i].fFlags & kHdrField_MapCollection))258 {259 /* Only once. */260 if (!*a_pappFieldValues[i])261 {262 pObj = a_paFieldDescs[i].pfnCreateInstance();263 if (pObj)264 *a_pappFieldValues[i] = pObj;265 else266 {267 addError(VERR_NO_MEMORY, "out of memory");268 break;269 }270 }271 else272 {273 addError(VERR_REST_RESPONSE_REPEAT_HEADER_FIELD, "Already saw header field '%s'", a_paFieldDescs[i].pszName);274 continue;275 }276 }277 else278 {279 /* Make sure we've got a map to work with. */280 if (!*a_pappFieldValues[i])281 *a_pappFieldValues[i] = pObj = a_paFieldDescs[i].pfnCreateInstance();282 else283 pObj = *a_pappFieldValues[i];284 AssertBreak(pObj->typeClass() == RTCRestObjectBase::kTypeClass_StringMap);285 pMap = (RTCRestStringMapBase *)pObj;286 287 /* Insert the header field name (sans prefix) into the map. We then use the288 new value object for the deserialization of the header field value below. */289 int rc = pMap->putNewValue(&pObj, &a_pchData[cchThisName], cchName - cchThisName);290 if (RT_SUCCESS(rc))291 { /* likely */ }292 else if (rc == VERR_ALREADY_EXISTS)293 {294 addError(VERR_REST_RESPONSE_REPEAT_HEADER_FIELD, "Already saw header field '%s'", a_paFieldDescs[i].pszName);295 continue;296 }297 else298 {299 addError(rc, "out of memory");300 break;301 }302 }303 304 /*305 * Deserialize it.306 */307 RTERRINFOSTATIC ErrInfo;308 int rc = pObj->fromString(strValue, a_paFieldDescs[i].pszName, RTErrInfoInitStatic(&ErrInfo),309 a_paFieldDescs[i].fFlags & RTCRestObjectBase::kCollectionFormat_Mask);310 if (RT_SUCCESS(rc))311 { /* likely */ }312 else if (RTErrInfoIsSet(&ErrInfo.Core))313 addError(rc, "Error %Rrc parsing header field '%s': %s",314 rc, a_paFieldDescs[i].pszName, ErrInfo.Core.pszMsg);315 else316 addError(rc, "Error %Rrc parsing header field '%s'", rc, a_paFieldDescs[i].pszName);317 }318 }319 }320 /*321 * else { verify that it's the HTTP/... line at the start }322 */323 324 /*325 * Advance to the next field.326 */327 a_cbData -= cchField;328 a_pchData += cchField;329 }330 }331 332 int RTCRestClientResponseBase::extractHeaderFromBlob(const char *a_pszField, size_t a_cchField,333 const char *a_pchData, size_t a_cbData,334 RTCString *a_pStrDst)335 {336 char const chUpper0 = RT_C_TO_UPPER(a_pszField[0]);337 char const chLower0 = RT_C_TO_LOWER(a_pszField[0]);338 Assert(!RT_C_IS_SPACE(chUpper0));339 340 while (a_cbData > a_cchField)341 {342 /* Determine length of the header name:value combo.343 Note! Multi-line field values are not currently supported. */344 const char *pchEol = (const char *)memchr(a_pchData, '\n', a_cbData);345 while (pchEol && (pchEol == a_pchData || pchEol[-1] != '\r'))346 pchEol = (const char *)memchr(pchEol, '\n', a_cbData - (pchEol - a_pchData));347 348 size_t cchField = pchEol ? pchEol - a_pchData + 1 : a_cbData;349 350 /* Try match */351 if ( a_pchData[a_cchField] == ':'352 && ( a_pchData[0] == chUpper0353 || a_pchData[0] == chLower0)354 && RTStrNICmpAscii(a_pchData, a_pszField, a_cchField) == 0)355 {356 /* Drop CRLF. */357 if (pchEol)358 cchField -= 2;359 360 /* Drop the field name and optional whitespace. */361 cchField -= a_cchField + 1;362 a_pchData += a_cchField + 1;363 if (cchField > 0 && RT_C_IS_BLANK(*a_pchData))364 {365 a_pchData++;366 cchField--;367 }368 369 /* Return the value. */370 int rc = a_pStrDst->assignNoThrow(a_pchData, cchField);371 if (RT_SUCCESS(rc))372 RTStrPurgeEncoding(a_pStrDst->mutableRaw()); /** @todo this is probably a little wrong... */373 return rc;374 }375 376 /* Advance to the next field. */377 a_pchData += cchField;378 a_cbData -= cchField;379 }380 381 return VERR_NOT_FOUND;382 }383 384 385 386 215 RTCRestClientResponseBase::PrimaryJsonCursorForBody::PrimaryJsonCursorForBody(RTJSONVAL hValue, const char *pszName, 387 216 RTCRestClientResponseBase *a_pThat) … … 410 239 getPath(a_rCursor, szPath, sizeof(szPath)), RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue))); 411 240 return VWRN_NOT_FOUND; 241 } 242 243 244 int RTCRestClientResponseBase::deserializeHeader(RTCRestObjectBase *a_pObj, const char *a_pchValue, size_t a_cchValue, 245 uint32_t a_fFlags, const char *a_pszErrorTag) 246 { 247 /* 248 * Start by checking the encoding and transfering the value to a RTCString object. 249 */ 250 int rc = RTStrValidateEncodingEx(a_pchValue, a_cchValue, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH); 251 if (RT_SUCCESS(rc)) 252 { 253 RTCString strValue; 254 rc = strValue.assignNoThrow(a_pchValue, a_cchValue); 255 if (RT_SUCCESS(rc)) 256 { 257 /* 258 * Try deserialize it. 259 */ 260 RTERRINFOSTATIC ErrInfo; 261 rc = a_pObj->fromString(strValue, a_pszErrorTag, RTErrInfoInitStatic(&ErrInfo), a_fFlags); 262 if (RT_SUCCESS(rc)) 263 { /* likely */ } 264 else if (RTErrInfoIsSet(&ErrInfo.Core)) 265 addError(rc, "Error %Rrc parsing header field '%s': %s", rc, a_pszErrorTag, ErrInfo.Core.pszMsg); 266 else 267 addError(rc, "Error %Rrc parsing header field '%s'", rc, a_pszErrorTag); 268 } 269 } 270 else 271 { 272 addError(rc, "Error %Rrc validating value necoding of header field '%s': %.*Rhxs", 273 rc, a_pszErrorTag, a_cchValue, a_pchValue); 274 rc = VINF_SUCCESS; /* ignore */ 275 } 276 return rc; 277 } 278 279 280 int RTCRestClientResponseBase::deserializeHeaderIntoMap(RTCRestStringMapBase *a_pMap, const char *a_pchField, size_t a_cchField, 281 const char *a_pchValue, size_t a_cchValue, uint32_t a_fFlags, 282 const char *a_pszErrorTag) 283 { 284 /* 285 * Start by checking the encoding of both the field and value, 286 * then transfering the value to a RTCString object. 287 */ 288 int rc = RTStrValidateEncodingEx(a_pchField, a_cchField, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH); 289 if (RT_SUCCESS(rc)) 290 { 291 rc = RTStrValidateEncodingEx(a_pchValue, a_cchValue, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH); 292 if (RT_SUCCESS(rc)) 293 { 294 RTCString strValue; 295 rc = strValue.assignNoThrow(a_pchValue, a_cchValue); 296 if (RT_SUCCESS(rc)) 297 { 298 /* 299 * Create a value object and put it into the map. 300 */ 301 RTCRestObjectBase *pValue; 302 int rc = a_pMap->putNewValue(&pValue, a_pchField, a_cchField); 303 if (RT_SUCCESS(rc)) 304 { 305 /* 306 * Try deserialize the value. 307 */ 308 RTERRINFOSTATIC ErrInfo; 309 rc = pValue->fromString(strValue, a_pszErrorTag, RTErrInfoInitStatic(&ErrInfo), a_fFlags); 310 if (RT_SUCCESS(rc)) 311 { /* likely */ } 312 else if (RTErrInfoIsSet(&ErrInfo.Core)) 313 addError(rc, "Error %Rrc parsing header field '%s' subfield '%.*s': %s", 314 rc, a_pszErrorTag, a_cchField, a_pchField, ErrInfo.Core.pszMsg); 315 else 316 addError(rc, "Error %Rrc parsing header field '%s' subfield '%.*s'", 317 rc, a_pszErrorTag, a_cchField, a_pchField); 318 } 319 } 320 } 321 else 322 { 323 addError(rc, "Error %Rrc validating value encoding of header field '%s': %.*Rhxs", 324 rc, a_pszErrorTag, a_cchValue, a_pchValue); 325 rc = VINF_SUCCESS; /* ignore */ 326 } 327 } 328 else 329 { 330 addError(rc, "Error %Rrc validating sub-field encoding of header field '%s*': %.*Rhxs", 331 rc, a_pszErrorTag, a_cchField, a_pchField); 332 rc = VINF_SUCCESS; /* ignore */ 333 } 334 return rc; 412 335 } 413 336
Note:
See TracChangeset
for help on using the changeset viewer.