VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/rest-binary.cpp@ 74158

Last change on this file since 74158 was 74149, checked in by vboxsync, 6 years ago

IPRT/rest: Adding RTCRestDate (untested). bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.3 KB
Line 
1/* $Id: rest-binary.cpp 74149 2018-09-07 18:51:37Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestBinary and Descendants.
4 */
5
6/*
7 * Copyright (C) 2018 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/restbase.h>
33#include <iprt/cpp/restclient.h>
34
35#include <iprt/assert.h>
36#include <iprt/err.h>
37
38
39/*********************************************************************************************************************************
40* Defined Constants And Macros *
41*********************************************************************************************************************************/
42/** The default maximum download size. */
43#if ARCH_BITS == 32
44# define RTCREST_MAX_DOWNLOAD_SIZE_DEFAULT _32M
45#else
46# define RTCREST_MAX_DOWNLOAD_SIZE_DEFAULT _128M
47#endif
48
49
50
51/*********************************************************************************************************************************
52* RTCRestBinary Implementation. *
53*********************************************************************************************************************************/
54/**
55 * Default constructor.
56 */
57RTCRestBinary::RTCRestBinary()
58 : m_pbData(NULL)
59 , m_cbData(0)
60 , m_cbAllocated(0)
61 , m_fFreeable(true)
62 , m_fReadOnly(false)
63{
64}
65
66
67/**
68 * Destructor.
69 */
70RTCRestBinary::~RTCRestBinary()
71{
72 freeData();
73}
74
75/**
76 * Safe copy assignment method.
77 */
78int RTCRestBinary::assignCopy(RTCRestBinary const &a_rThat)
79{
80 freeData();
81 if (a_rThat.m_pbData)
82 {
83 m_pbData = (uint8_t *)RTMemDup(a_rThat.m_pbData, a_rThat.m_cbAllocated);
84 AssertReturn(m_pbData, VERR_NO_MEMORY);
85 m_cbData = a_rThat.m_cbData;
86 m_cbAllocated = a_rThat.m_cbAllocated;
87 m_fFreeable = true;
88 m_fReadOnly = false;
89 m_fNullIndicator = false;
90 }
91 else
92 m_fNullIndicator = a_rThat.m_fNullIndicator;
93 return VINF_SUCCESS;
94}
95
96
97/**
98 * Safe buffer copy method.
99 */
100int RTCRestBinary::assignCopy(void const *a_pvData, size_t a_cbData)
101{
102 if ( m_pbData == NULL
103 || m_fReadOnly
104 || a_cbData > m_cbAllocated)
105 {
106 freeData();
107 m_pbData = (uint8_t *)RTMemDup(a_pvData, a_cbData);
108 AssertReturn(m_pbData, VERR_NO_MEMORY);
109 m_cbData = a_cbData;
110 m_cbAllocated = a_cbData;
111 m_fFreeable = true;
112 m_fReadOnly = false;
113 }
114 else
115 {
116 m_cbData = a_cbData;
117 memcpy(m_pbData, a_pvData, a_cbData);
118 }
119 m_fNullIndicator = false;
120 return VINF_SUCCESS;
121}
122
123
124/**
125 * Use the specified data buffer directly.
126 */
127int RTCRestBinary::assignReadOnly(void const *a_pvData, size_t a_cbData)
128{
129 freeData();
130 if (a_pvData)
131 {
132 m_pbData = (uint8_t *)a_pvData;
133 m_cbData = a_cbData;
134 m_cbAllocated = 0;
135 m_fFreeable = false;
136 m_fReadOnly = true;
137 m_fNullIndicator = false;
138 }
139 return VINF_SUCCESS;
140}
141
142
143/**
144 * Use the specified data buffer directly.
145 */
146int RTCRestBinary::assignWriteable(void *a_pvBuf, size_t a_cbBuf)
147{
148 freeData();
149 if (a_pvBuf)
150 {
151 m_pbData = (uint8_t *)a_pvBuf;
152 m_cbData = a_cbBuf;
153 m_cbAllocated = a_cbBuf;
154 m_fFreeable = false;
155 m_fReadOnly = false;
156 m_fNullIndicator = false;
157 }
158 return VINF_SUCCESS;
159}
160
161
162/**
163 * Frees the data held by the object and resets it default state.
164 */
165void RTCRestBinary::freeData()
166{
167 if (m_fFreeable)
168 RTMemFree(m_pbData);
169 m_pbData = NULL;
170 m_cbData = 0;
171 m_cbAllocated = 0;
172 m_fFreeable = true;
173 m_fReadOnly = false;
174}
175
176
177/* Overridden methods: */
178int RTCRestBinary::setNull(void)
179{
180 freeData();
181 m_fNullIndicator = true;
182 return VINF_SUCCESS;
183}
184
185
186int RTCRestBinary::resetToDefault(void)
187{
188 freeData();
189 return VINF_SUCCESS;
190}
191
192
193RTCRestOutputBase &RTCRestBinary::serializeAsJson(RTCRestOutputBase &a_rDst) const
194{
195 AssertMsgFailed(("We should never get here!\n"));
196 a_rDst.printf("null");
197 return a_rDst;
198}
199
200
201int RTCRestBinary::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
202{
203 return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NOT_SUPPORTED, "RTCRestBinary does not support deserialization!");
204}
205
206
207int RTCRestBinary::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const
208{
209 RT_NOREF(a_pDst, a_fFlags);
210 AssertFailedReturn(VERR_NOT_SUPPORTED);
211}
212
213
214int RTCRestBinary::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo/*= NULL*/,
215 uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/)
216{
217 RT_NOREF(a_rValue, a_pszName, a_fFlags);
218 AssertFailedReturn(RTErrInfoSet(a_pErrInfo, VERR_NOT_SUPPORTED, "RTCRestBinary does not support fromString()!"));
219}
220
221
222RTCRestObjectBase::kTypeClass RTCRestBinary::typeClass(void) const
223{
224 return kTypeClass_Binary;
225}
226
227
228const char *RTCRestBinary::typeName(void) const
229{
230 return "RTCRestBinary";
231}
232
233
234/** Factory method. */
235/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestBinary::createInstance(void)
236{
237 return new (std::nothrow) RTCRestBinary();
238}
239
240
241
242/*********************************************************************************************************************************
243* RTCRestBinaryParameter Implementation. *
244*********************************************************************************************************************************/
245
246/**
247 * Default constructor.
248 */
249RTCRestBinaryParameter::RTCRestBinaryParameter()
250 : RTCRestBinary()
251 , m_cbContentLength(UINT64_MAX)
252 , m_strContentType()
253 , m_pfnProducer(NULL)
254 , m_pvCallbackData(NULL)
255{
256}
257
258
259int RTCRestBinaryParameter::assignCopy(RTCRestBinaryParameter const &a_rThat)
260{
261 AssertReturn(a_rThat.m_pfnProducer, VERR_INVALID_STATE);
262 int rc = assignCopy(*(RTCRestBinary const *)&a_rThat);
263 if (RT_SUCCESS(rc))
264 rc = m_strContentType.assignNoThrow(a_rThat.m_strContentType);
265 m_cbContentLength = a_rThat.m_cbContentLength;
266 return VINF_SUCCESS;
267}
268
269
270int RTCRestBinaryParameter::assignCopy(RTCRestBinary const &a_rThat)
271{
272 m_cbContentLength = a_rThat.getSize();
273 m_strContentType.setNull();
274 m_pfnProducer = NULL;
275 m_pvCallbackData = NULL;
276 return RTCRestBinary::assignCopy(a_rThat);
277}
278
279
280int RTCRestBinaryParameter::assignCopy(void const *a_pvData, size_t a_cbData)
281{
282 m_cbContentLength = a_cbData;
283 m_pfnProducer = NULL;
284 m_pvCallbackData = NULL;
285 return RTCRestBinary::assignCopy(a_pvData, a_cbData);
286}
287
288
289int RTCRestBinaryParameter::assignReadOnly(void const *a_pvData, size_t a_cbData)
290{
291 m_cbContentLength = a_cbData;
292 m_pfnProducer = NULL;
293 m_pvCallbackData = NULL;
294 return RTCRestBinary::assignReadOnly(a_pvData, a_cbData);
295}
296
297
298int RTCRestBinaryParameter::assignWriteable(void *a_pvBuf, size_t a_cbBuf)
299{
300 AssertMsgFailed(("Please use assignReadOnly!\n"));
301 return assignReadOnly(a_pvBuf, a_cbBuf);
302}
303
304
305int RTCRestBinaryParameter::resetToDefault()
306{
307 m_cbContentLength = UINT64_MAX;
308 m_pfnProducer = NULL;
309 m_pvCallbackData = NULL;
310 return RTCRestBinary::resetToDefault();
311}
312
313
314const char *RTCRestBinaryParameter::typeName(void) const
315{
316 return "RTCRestBinaryParameter";
317}
318
319
320/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestBinaryParameter::createInstance(void)
321{
322 return new (std::nothrow) RTCRestBinaryParameter();
323}
324
325
326int RTCRestBinaryParameter::setContentType(const char *a_pszContentType)
327{
328 return m_strContentType.assignNoThrow(a_pszContentType);
329}
330
331
332void RTCRestBinaryParameter::setProducerCallback(PFNPRODUCER a_pfnProducer, void *a_pvCallbackData /*= NULL*/,
333 uint64_t a_cbContentLength /*= UINT64_MAX*/)
334{
335 freeData();
336
337 m_pfnProducer = a_pfnProducer;
338 m_pvCallbackData = a_pvCallbackData;
339 m_cbContentLength = a_cbContentLength;
340}
341
342
343int RTCRestBinaryParameter::xmitPrepare(RTHTTP a_hHttp) const
344{
345 AssertReturn(m_pbData != NULL || m_pfnProducer != NULL || m_cbContentLength == 0, VERR_INVALID_STATE);
346
347
348 /*
349 * Set the content type if given.
350 */
351 if (m_strContentType.isNotEmpty())
352 {
353 Assert(!RTHttpGetHeader(a_hHttp, RT_STR_TUPLE("Content-Type")));
354 int rc = RTHttpAddHeader(a_hHttp, "Content-Type", m_strContentType.c_str(), m_strContentType.length(),
355 RTHTTPADDHDR_F_BACK);
356 AssertRCReturn(rc, rc);
357 }
358
359 /*
360 * Set the content length if given.
361 */
362 if (m_cbContentLength != UINT64_MAX)
363 {
364 const char *pszContentLength = RTHttpGetHeader(a_hHttp, RT_STR_TUPLE("Content-Length"));
365 AssertMsgReturn(!pszContentLength || RTStrToUInt64(pszContentLength) == m_cbContentLength,
366 ("pszContentLength=%s does not match m_cbContentLength=%RU64\n", pszContentLength, m_cbContentLength),
367 VERR_MISMATCH);
368 if (!pszContentLength)
369 {
370 char szValue[64];
371 ssize_t cchValue = RTStrFormatU64(szValue, sizeof(szValue), m_cbContentLength, 10, 0, 0, 0);
372 int rc = RTHttpAddHeader(a_hHttp, "Content-Length", szValue, cchValue, RTHTTPADDHDR_F_BACK);
373 AssertRCReturn(rc, rc);
374 }
375 }
376
377 /*
378 * Register an upload callback.
379 */
380 int rc = RTHttpSetUploadCallback(a_hHttp, m_cbContentLength, xmitHttpCallback, (RTCRestBinaryParameter *)this);
381 AssertRCReturn(rc, rc);
382
383 return VINF_SUCCESS;
384
385}
386
387
388/*static*/ DECLCALLBACK(int)
389RTCRestBinaryParameter::xmitHttpCallback(RTHTTP hHttp, void *pvBuf, size_t cbBuf,
390 uint64_t offContent, size_t *pcbActual, void *pvUser)
391{
392 RTCRestBinaryParameter *pThis = (RTCRestBinaryParameter *)pvUser;
393
394 /*
395 * Call the user upload callback if we've got one.
396 */
397 if (pThis->m_pfnProducer)
398 return pThis->m_pfnProducer(pThis, pvBuf, cbBuf, offContent, pcbActual);
399
400 /*
401 * Feed from the memory buffer.
402 */
403 if (offContent < pThis->m_cbContentLength)
404 {
405 uint64_t const cbLeft = pThis->m_cbContentLength - offContent;
406 size_t const cbToCopy = cbLeft >= cbBuf ? cbBuf : (size_t)cbLeft;
407 memcpy(pvBuf, &pThis->m_pbData[(size_t)offContent], cbToCopy);
408 *pcbActual = cbToCopy;
409 }
410 else
411 *pcbActual = 0;
412
413 RT_NOREF(hHttp);
414 return VINF_SUCCESS;
415}
416
417
418void RTCRestBinaryParameter::xmitComplete(RTHTTP a_hHttp) const
419{
420 /* Unset the callback. */
421 int rc = RTHttpSetUploadCallback(a_hHttp, UINT64_MAX, NULL, NULL);
422 AssertRC(rc);
423}
424
425
426/*********************************************************************************************************************************
427* RTCRestBinaryResponse Implementation. *
428*********************************************************************************************************************************/
429
430/**
431 * Default constructor.
432 */
433RTCRestBinaryResponse::RTCRestBinaryResponse()
434 : RTCRestBinary()
435 , m_cbContentLength(UINT64_MAX)
436 , m_cbDownloaded(0)
437 , m_pfnConsumer(NULL)
438 , m_pvCallbackData(NULL)
439 , m_cbMaxDownload(RTCREST_MAX_DOWNLOAD_SIZE_DEFAULT)
440{
441}
442
443
444int RTCRestBinaryResponse::assignCopy(RTCRestBinaryResponse const &a_rThat)
445{
446 AssertReturn(a_rThat.m_pfnConsumer, VERR_INVALID_STATE);
447 int rc = assignCopy(*(RTCRestBinary const *)&a_rThat);
448 m_cbContentLength = a_rThat.m_cbContentLength;
449 m_cbDownloaded = a_rThat.m_cbDownloaded;
450 m_cbMaxDownload = a_rThat.m_cbMaxDownload;
451 return rc;
452}
453
454
455int RTCRestBinaryResponse::assignCopy(RTCRestBinary const &a_rThat)
456{
457 m_cbContentLength = UINT64_MAX;
458 m_cbDownloaded = 0;
459 m_pfnConsumer = NULL;
460 m_pvCallbackData = NULL;
461 return RTCRestBinary::assignCopy(a_rThat);
462}
463
464
465int RTCRestBinaryResponse::assignCopy(void const *a_pvData, size_t a_cbData)
466{
467 RT_NOREF(a_pvData, a_cbData);
468 AssertMsgFailedReturn(("Makes no sense for downloads.\n"), VERR_INVALID_STATE);
469}
470
471
472int RTCRestBinaryResponse::assignReadOnly(void const *a_pvData, size_t a_cbData)
473{
474 RT_NOREF(a_pvData, a_cbData);
475 AssertMsgFailedReturn(("Makes no sense for downloads.\n"), VERR_INVALID_STATE);
476}
477
478
479int RTCRestBinaryResponse::assignWriteable(void *a_pvBuf, size_t a_cbBuf)
480{
481 m_cbContentLength = UINT64_MAX;
482 m_cbDownloaded = 0;
483 m_pfnConsumer = NULL;
484 m_pvCallbackData = NULL;
485 AssertStmt(a_cbBuf <= m_cbMaxDownload, m_cbMaxDownload = a_cbBuf);
486 return RTCRestBinary::assignWriteable(a_pvBuf, a_cbBuf);
487}
488
489
490int RTCRestBinaryResponse::resetToDefault()
491{
492 m_cbContentLength = UINT64_MAX;
493 m_cbDownloaded = 0;
494 m_pfnConsumer = NULL;
495 m_pvCallbackData = NULL;
496 m_cbMaxDownload = RTCREST_MAX_DOWNLOAD_SIZE_DEFAULT;
497 return RTCRestBinary::resetToDefault();
498}
499
500
501const char *RTCRestBinaryResponse::typeName(void) const
502{
503 return "RTCRestBinaryResponse";
504}
505
506
507/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestBinaryResponse::createInstance(void)
508{
509 return new (std::nothrow) RTCRestBinaryResponse();
510}
511
512
513void RTCRestBinaryResponse::setMaxDownloadSize(size_t a_cbMaxDownload)
514{
515 if (a_cbMaxDownload == 0)
516 m_cbMaxDownload = RTCREST_MAX_DOWNLOAD_SIZE_DEFAULT;
517 else
518 m_cbMaxDownload = a_cbMaxDownload;
519}
520
521
522void RTCRestBinaryResponse::setConsumerCallback(PFNCONSUMER a_pfnConsumer, void *a_pvCallbackData /*= NULL*/)
523{
524 freeData();
525
526 m_pfnConsumer = a_pfnConsumer;
527 m_pvCallbackData = a_pvCallbackData;
528 m_cbDownloaded = 0;
529 m_cbContentLength = UINT64_MAX;
530}
531
532
533int RTCRestBinaryResponse::receivePrepare(RTHTTP a_hHttp, uint32_t a_fCallbackFlags)
534{
535 AssertReturn(!m_fReadOnly, VERR_INVALID_STATE);
536
537 /*
538 * Register the download callback.
539 */
540 int rc = RTHttpSetDownloadCallback(a_hHttp, a_fCallbackFlags, receiveHttpCallback, this);
541 AssertRC(rc);
542 return rc;
543}
544
545
546/*static*/ DECLCALLBACK(int)
547RTCRestBinaryResponse::receiveHttpCallback(RTHTTP hHttp, void const *pvBuf, size_t cbBuf, uint32_t uHttpStatus,
548 uint64_t offContent, uint64_t cbContent, void *pvUser)
549{
550 RTCRestBinaryResponse *pThis = (RTCRestBinaryResponse *)pvUser;
551 Assert(offContent == pThis->m_cbDownloaded);
552 pThis->m_cbContentLength = cbContent;
553
554 /*
555 * Call the user download callback if we've got one.
556 */
557 if (pThis->m_pfnConsumer)
558 {
559 int rc = pThis->m_pfnConsumer(pThis, pvBuf, cbBuf, uHttpStatus, offContent, cbContent);
560 if (RT_SUCCESS(rc))
561 pThis->m_cbDownloaded = offContent + cbBuf;
562 return rc;
563 }
564
565 /*
566 * Check download limit before adding more data.
567 */
568 AssertMsgReturn(offContent + cbBuf <= pThis->m_cbMaxDownload,
569 ("%RU64 + %zu = %RU64; max=%RU64", offContent, cbBuf, offContent + cbBuf, pThis->m_cbMaxDownload),
570 VERR_TOO_MUCH_DATA);
571
572 /*
573 * Make sure we've got sufficient writable buffer space before we copy in the data.
574 */
575 AssertReturn(!pThis->m_fReadOnly, VERR_INVALID_STATE);
576 if (offContent + cbBuf <= pThis->m_cbAllocated)
577 { /* likely, except for the first time. */ }
578 else
579 {
580 AssertMsgReturn(pThis->m_fFreeable,
581 ("offContent=%RU64 cbBuf=%zu m_cbAllocated=%zu", offContent, cbBuf, pThis->m_cbAllocated),
582 VERR_TOO_MUCH_DATA);
583 AssertMsgReturn(cbContent <= pThis->m_cbMaxDownload || cbContent == UINT64_MAX,
584 ("cbContent: %RU64; max=%RU64", cbContent, pThis->m_cbMaxDownload),
585 VERR_TOO_MUCH_DATA);
586
587 if (offContent == 0 && cbContent != UINT64_MAX)
588 {
589 void *pvNew = RTMemRealloc(pThis->m_pbData, (size_t)cbContent);
590 if (!pvNew)
591 return VERR_NO_MEMORY;
592 pThis->m_pbData = (uint8_t *)pvNew;
593 pThis->m_cbAllocated = (size_t)cbContent;
594 }
595 else
596 {
597 size_t cbNeeded = offContent + cbBuf;
598 size_t cbNew;
599 if (pThis->m_cbAllocated == 0)
600 cbNew = RT_MAX(_64K, RT_ALIGN_Z(cbNeeded, _64K));
601 else if (pThis->m_cbAllocated < _64M && cbNeeded <= _64M)
602 {
603 cbNew = pThis->m_cbAllocated * 2;
604 while (cbNew < cbNeeded)
605 cbNew *= 2;
606 }
607 else
608 cbNew = RT_ALIGN_Z(cbNeeded, _32M);
609
610 void *pvNew = RTMemRealloc(pThis->m_pbData, cbNew);
611 if (!pvNew)
612 return VERR_NO_MEMORY;
613 pThis->m_pbData = (uint8_t *)pvNew;
614 pThis->m_cbAllocated = cbNew;
615 }
616 }
617
618 /*
619 * Do the copying.
620 */
621 memcpy(&pThis->m_pbData[(size_t)offContent], pvBuf, cbBuf);
622 pThis->m_cbDownloaded = offContent + cbBuf;
623
624 RT_NOREF(hHttp);
625 return VINF_SUCCESS;
626}
627
628
629void RTCRestBinaryResponse::receiveComplete(RTHTTP a_hHttp)
630{
631 /* Unset the callback. */
632 int rc = RTHttpSetDownloadCallback(a_hHttp, RTHTTPDOWNLOAD_F_ANY_STATUS, NULL, NULL);
633 AssertRC(rc);
634}
635
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