Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qhttpmultipart.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qhttpmultipart.h"
5#include "qhttpmultipart_p.h"
6#include "QtCore/qdatetime.h" // for initializing the random number generator with QTime
7#include "QtCore/qmutex.h"
8#include "QtCore/qrandom.h"
9
11
65
72
77{
78 d = nullptr;
79}
80
85{
86 d = other.d;
87 return *this;
88}
89
105{
106 return d == other.d || *d == *other.d;
107}
108
127
142{
143 d->setRawHeader(headerName, headerValue);
144}
145
155{
156 d->setBody(body);
157}
158
178
179
180
235{
236 Q_D(QHttpMultiPart);
237 d->contentType = MixedType;
238}
239
247{
248 Q_D(QHttpMultiPart);
249 d->contentType = contentType;
250}
251
258
263{
264 d_func()->parts.append(httpPart);
265}
266
280{
281 d_func()->contentType = contentType;
282}
283
290{
291 return d_func()->boundary;
292}
293
305{
306 d_func()->boundary = boundary;
307}
308
309
310
311// ------------------------------------------------------------------
312// ----------- implementations of private classes: ------------------
313// ------------------------------------------------------------------
314
315
316
318{
319 checkHeaderCreated();
320 qint64 bytesAvailable = header.size();
321 if (bodyDevice) {
322 bytesAvailable += bodyDevice->bytesAvailable() - readPointer;
323 } else {
324 bytesAvailable += body.size() - readPointer;
325 }
326 // the device might have closed etc., so make sure we do not return a negative value
327 return qMax(bytesAvailable, (qint64) 0);
328}
329
331{
332 checkHeaderCreated();
333 qint64 bytesRead = 0;
334 qint64 headerDataCount = header.size();
335
336 // read header if it has not been read yet
337 if (readPointer < headerDataCount) {
338 bytesRead = qMin(headerDataCount - readPointer, maxSize);
339 const char *headerData = header.constData();
340 memcpy(data, headerData + readPointer, bytesRead);
341 readPointer += bytesRead;
342 }
343 // read content if there is still space
344 if (bytesRead < maxSize) {
345 if (bodyDevice) {
346 qint64 dataBytesRead = bodyDevice->read(data + bytesRead, maxSize - bytesRead);
347 if (dataBytesRead == -1)
348 return -1;
349 bytesRead += dataBytesRead;
350 readPointer += dataBytesRead;
351 } else {
352 qint64 contentBytesRead = qMin(body.size() - readPointer + headerDataCount, maxSize - bytesRead);
353 const char *contentData = body.constData();
354 // if this method is called several times, we need to find the
355 // right offset in the content ourselves:
356 memcpy(data + bytesRead, contentData + readPointer - headerDataCount, contentBytesRead);
357 bytesRead += contentBytesRead;
358 readPointer += contentBytesRead;
359 }
360 }
361 return bytesRead;
362}
363
365{
366 checkHeaderCreated();
367 qint64 size = header.size();
368 if (bodyDevice) {
369 size += bodyDevice->size();
370 } else {
371 size += body.size();
372 }
373 return size;
374}
375
377{
378 bool ret = true;
379 if (bodyDevice)
380 if (!bodyDevice->reset())
381 ret = false;
382 readPointer = 0;
383 return ret;
384}
385void QHttpPartPrivate::checkHeaderCreated() const
386{
387 if (!headerCreated) {
388 // copied from QHttpNetworkRequestPrivate::header() and adapted
389 const auto h = headers();
390 for (qsizetype i = 0; i < h.size(); ++i) {
391 const auto name = h.nameAt(i);
392 header += QByteArrayView(name.data(), name.size()) + ": " + h.valueAt(i) + "\r\n";
393 }
394
395 header += "\r\n";
396 headerCreated = true;
397 }
398}
399
401{
402 // 24 random bytes, becomes 32 characters when encoded to Base64
403 quint32 random[6];
404 QRandomGenerator::global()->fillRange(random);
405 boundary = "boundary_.oOo._"
406 + QByteArray::fromRawData(reinterpret_cast<char *>(random), sizeof(random)).toBase64();
407
408 // boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
409 Q_ASSERT(boundary.size() <= 70);
410}
411
413{
414 // if not done yet, we calculate the size and the offsets of each part,
415 // including boundary (needed later in readData)
416 if (deviceSize == -1) {
417 qint64 currentSize = 0;
418 qint64 boundaryCount = multiPart->boundary.size();
419 for (int a = 0; a < multiPart->parts.size(); a++) {
420 partOffsets.append(currentSize);
421 // 4 additional bytes for the "--" before and the "\r\n" after the boundary,
422 // and 2 bytes for the "\r\n" after the content
423 currentSize += boundaryCount + 4 + multiPart->parts.at(a).d->size() + 2;
424 }
425 currentSize += boundaryCount + 6; // size for ending boundary, 2 beginning and ending dashes and "\r\n"
426 deviceSize = currentSize;
427 }
428 return deviceSize;
429}
430
432{
433 for (int a = 0; a < multiPart->parts.size(); a++) {
435 // we are sequential if any of the bodyDevices of our parts are sequential;
436 // when reading from a byte array, we are not sequential
437 if (device && device->isSequential())
438 return true;
439 }
440 return false;
441}
442
444{
445 // Reset QIODevice's data
447 for (int a = 0; a < multiPart->parts.size(); a++)
448 if (!multiPart->parts[a].d->reset())
449 return false;
450 readPointer = 0;
451 return true;
452}
454{
455 qint64 bytesRead = 0, index = 0;
456
457 // skip the parts we have already read
458 while (index < multiPart->parts.size() &&
460 + multiPart->boundary.size() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
461 index++;
462
463 // read the data
464 while (bytesRead < maxSize && index < multiPart->parts.size()) {
465
466 // check whether we need to read the boundary of the current part
467 QByteArray boundaryData = "--" + multiPart->boundary + "\r\n";
468 qint64 boundaryCount = boundaryData.size();
469 qint64 partIndex = readPointer - partOffsets.at(index);
470 if (partIndex < boundaryCount) {
471 qint64 boundaryBytesRead = qMin(boundaryCount - partIndex, maxSize - bytesRead);
472 memcpy(data + bytesRead, boundaryData.constData() + partIndex, boundaryBytesRead);
473 bytesRead += boundaryBytesRead;
474 readPointer += boundaryBytesRead;
475 partIndex += boundaryBytesRead;
476 }
477
478 // check whether we need to read the data of the current part
479 if (bytesRead < maxSize && partIndex >= boundaryCount && partIndex < boundaryCount + multiPart->parts.at(index).d->size()) {
480 qint64 dataBytesRead = multiPart->parts[index].d->readData(data + bytesRead, maxSize - bytesRead);
481 if (dataBytesRead == -1)
482 return -1;
483 bytesRead += dataBytesRead;
484 readPointer += dataBytesRead;
485 partIndex += dataBytesRead;
486 }
487
488 // check whether we need to read the ending CRLF of the current part
489 if (bytesRead < maxSize && partIndex >= boundaryCount + multiPart->parts.at(index).d->size()) {
490 if (bytesRead == maxSize - 1)
491 return bytesRead;
492 memcpy(data + bytesRead, "\r\n", 2);
493 bytesRead += 2;
494 readPointer += 2;
495 index++;
496 }
497 }
498 // check whether we need to return the final boundary
499 if (bytesRead < maxSize && index == multiPart->parts.size()) {
500 QByteArray finalBoundary = "--" + multiPart->boundary + "--\r\n";
501 qint64 boundaryIndex = readPointer + finalBoundary.size() - size();
502 qint64 lastBoundaryBytesRead = qMin(finalBoundary.size() - boundaryIndex, maxSize - bytesRead);
503 memcpy(data + bytesRead, finalBoundary.constData() + boundaryIndex, lastBoundaryBytesRead);
504 bytesRead += lastBoundaryBytesRead;
505 readPointer += lastBoundaryBytesRead;
506 }
507 return bytesRead;
508}
509
511{
512 Q_UNUSED(data);
513 Q_UNUSED(maxSize);
514 return -1;
515}
516
517#ifndef QT_NO_DEBUG_STREAM
518
530{
531 const QDebugStateSaver saver(debug);
532 debug.resetFormat().nospace().noquote();
533
534 debug << "QHttpPart(headers = ["
535 << part.d->cookedHeaders
536 << "], http headers = ["
537 << part.d->httpHeaders
538 << "],";
539
540 if (part.d->bodyDevice) {
541 debug << " bodydevice = ["
542 << part.d->bodyDevice
543 << ", is open: "
544 << part.d->bodyDevice->isOpen()
545 << "]";
546 } else {
547 debug << " size of body = "
548 << part.d->body.size()
549 << " bytes";
550 }
551
552 debug << ")";
553
554 return debug;
555}
556
557#endif // QT_NO_DEBUG_STREAM
558
559
561
562#include "moc_qhttpmultipart.cpp"
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
\inmodule QtCore
\inmodule QtCore
virtual bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
virtual qint64 size() const override
For open random-access devices, this function returns the size of the device.
virtual bool reset() override
Seeks to the start of input for random-access devices.
QList< qint64 > partOffsets
virtual qint64 readData(char *data, qint64 maxSize) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
virtual qint64 writeData(const char *data, qint64 maxSize) override
Writes up to maxSize bytes from data to the device.
QHttpMultiPartPrivate * multiPart
QList< QHttpPart > parts
The QHttpMultiPart class resembles a MIME multipart message to be sent over HTTP.
~QHttpMultiPart()
Destroys the multipart.
ContentType
List of known content types for a multipart subtype as described in RFC 2046 and others.
void append(const QHttpPart &httpPart)
Appends httpPart to this multipart.
QByteArray boundary() const
returns the boundary.
void setContentType(ContentType contentType)
Sets the content type to contentType.
void setBoundary(const QByteArray &boundary)
Sets the boundary to boundary.
QHttpMultiPart(QObject *parent=nullptr)
Constructs a QHttpMultiPart with content type MixedType and sets parent as the parent object.
void setBody(const QByteArray &newBody)
QIODevice * bodyDevice
qint64 readData(char *data, qint64 maxSize)
qint64 bytesAvailable() const
void setBodyDevice(QIODevice *device)
qint64 size() const
The QHttpPart class holds a body part to be used inside a HTTP multipart MIME message.
bool operator==(const QHttpPart &other) const
Returns true if this object is the same as other (i.e., if they have the same headers and body).
QHttpPart & operator=(QHttpPart &&other) noexcept
void setBodyDevice(QIODevice *device)
Sets the device to read the content from to device.
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
Sets the value of the known header header to be value, overriding any previously set headers.
QHttpPart()
Constructs an empty QHttpPart object.
void setBody(const QByteArray &body)
Sets the body of this MIME part to body.
~QHttpPart()
Destroys this QHttpPart.
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
Sets the header headerName to be of value headerValue.
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
bool isOpen() const
Returns true if the device is open; otherwise returns false.
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
virtual bool reset()
Seeks to the start of input for random-access devices.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
QHttpHeaders headers() const
void setRawHeader(const QByteArray &key, const QByteArray &value)
CookedHeadersMap cookedHeaders
KnownHeaders
List of known header types that QNetworkRequest parses.
\inmodule QtCore
Definition qobject.h:103
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
\inmodule QtCore
Definition qvariant.h:65
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QDebug operator<<(QDebug debug, const QHttpPart &part)
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLfloat GLfloat GLfloat GLfloat h
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
QSharedPointer< T > other(t)
[5]