Qt 6.x
The Qt SDK
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
63{
64}
65
70{
71}
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
124{
126}
127
142{
144}
145
155{
156 d->setBody(body);
157}
158
175{
177}
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
256{
257}
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
390 QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
391 for (; it != fields.constEnd(); ++it)
392 header += it->first + ": " + it->second + "\r\n";
393 header += "\r\n";
394 headerCreated = true;
395 }
396}
397
399{
400 // 24 random bytes, becomes 32 characters when encoded to Base64
401 quint32 random[6];
403 boundary = "boundary_.oOo._"
404 + QByteArray::fromRawData(reinterpret_cast<char *>(random), sizeof(random)).toBase64();
405
406 // boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
407 Q_ASSERT(boundary.size() <= 70);
408}
409
411{
412 // if not done yet, we calculate the size and the offsets of each part,
413 // including boundary (needed later in readData)
414 if (deviceSize == -1) {
415 qint64 currentSize = 0;
416 qint64 boundaryCount = multiPart->boundary.size();
417 for (int a = 0; a < multiPart->parts.size(); a++) {
418 partOffsets.append(currentSize);
419 // 4 additional bytes for the "--" before and the "\r\n" after the boundary,
420 // and 2 bytes for the "\r\n" after the content
421 currentSize += boundaryCount + 4 + multiPart->parts.at(a).d->size() + 2;
422 }
423 currentSize += boundaryCount + 6; // size for ending boundary, 2 beginning and ending dashes and "\r\n"
424 deviceSize = currentSize;
425 }
426 return deviceSize;
427}
428
430{
431 for (int a = 0; a < multiPart->parts.size(); a++) {
433 // we are sequential if any of the bodyDevices of our parts are sequential;
434 // when reading from a byte array, we are not sequential
435 if (device && device->isSequential())
436 return true;
437 }
438 return false;
439}
440
442{
443 // Reset QIODevice's data
445 for (int a = 0; a < multiPart->parts.size(); a++)
446 if (!multiPart->parts[a].d->reset())
447 return false;
448 readPointer = 0;
449 return true;
450}
452{
453 qint64 bytesRead = 0, index = 0;
454
455 // skip the parts we have already read
456 while (index < multiPart->parts.size() &&
458 + multiPart->boundary.size() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
459 index++;
460
461 // read the data
462 while (bytesRead < maxSize && index < multiPart->parts.size()) {
463
464 // check whether we need to read the boundary of the current part
465 QByteArray boundaryData = "--" + multiPart->boundary + "\r\n";
466 qint64 boundaryCount = boundaryData.size();
467 qint64 partIndex = readPointer - partOffsets.at(index);
468 if (partIndex < boundaryCount) {
469 qint64 boundaryBytesRead = qMin(boundaryCount - partIndex, maxSize - bytesRead);
470 memcpy(data + bytesRead, boundaryData.constData() + partIndex, boundaryBytesRead);
471 bytesRead += boundaryBytesRead;
472 readPointer += boundaryBytesRead;
473 partIndex += boundaryBytesRead;
474 }
475
476 // check whether we need to read the data of the current part
477 if (bytesRead < maxSize && partIndex >= boundaryCount && partIndex < boundaryCount + multiPart->parts.at(index).d->size()) {
478 qint64 dataBytesRead = multiPart->parts[index].d->readData(data + bytesRead, maxSize - bytesRead);
479 if (dataBytesRead == -1)
480 return -1;
481 bytesRead += dataBytesRead;
482 readPointer += dataBytesRead;
483 partIndex += dataBytesRead;
484 }
485
486 // check whether we need to read the ending CRLF of the current part
487 if (bytesRead < maxSize && partIndex >= boundaryCount + multiPart->parts.at(index).d->size()) {
488 if (bytesRead == maxSize - 1)
489 return bytesRead;
490 memcpy(data + bytesRead, "\r\n", 2);
491 bytesRead += 2;
492 readPointer += 2;
493 index++;
494 }
495 }
496 // check whether we need to return the final boundary
497 if (bytesRead < maxSize && index == multiPart->parts.size()) {
498 QByteArray finalBoundary = "--" + multiPart->boundary + "--\r\n";
499 qint64 boundaryIndex = readPointer + finalBoundary.size() - size();
500 qint64 lastBoundaryBytesRead = qMin(finalBoundary.size() - boundaryIndex, maxSize - bytesRead);
501 memcpy(data + bytesRead, finalBoundary.constData() + boundaryIndex, lastBoundaryBytesRead);
502 bytesRead += lastBoundaryBytesRead;
503 readPointer += lastBoundaryBytesRead;
504 }
505 return bytesRead;
506}
507
509{
510 Q_UNUSED(data);
511 Q_UNUSED(maxSize);
512 return -1;
513}
514
515
517
518#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:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
QByteArray toBase64(Base64Options options=Base64Encoding) const
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:394
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.
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.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator constBegin() const noexcept
Definition qlist.h:615
void append(parameter_type t)
Definition qlist.h:441
const_iterator constEnd() const noexcept
Definition qlist.h:616
RawHeadersList allRawHeaders() const
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
void setRawHeader(const QByteArray &key, const QByteArray &value)
KnownHeaders
List of known header types that QNetworkRequest parses.
\inmodule QtCore
Definition qobject.h:90
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
void fillRange(UInt *buffer, qsizetype count)
Generates count 32- or 64-bit quantities (depending on the type UInt) and stores them in the buffer p...
Definition qrandom.h:141
\inmodule QtCore
Definition qvariant.h:64
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
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)
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:45
long long qint64
Definition qtypes.h:55
QSharedPointer< T > other(t)
[5]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent