QtBase  v6.3.1
qhttpmultipart.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qhttpmultipart.h"
41 #include "qhttpmultipart_p.h"
42 #include "QtCore/qdatetime.h" // for initializing the random number generator with QTime
43 #include "QtCore/qmutex.h"
44 #include "QtCore/qrandom.h"
45 
47 
99 {
100 }
101 
106 {
107 }
108 
113 {
114  d = nullptr;
115 }
116 
121 {
122  d = other.d;
123  return *this;
124 }
125 
141 {
142  return d == other.d || *d == *other.d;
143 }
144 
160 {
162 }
163 
177 void QHttpPart::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
178 {
179  d->setRawHeader(headerName, headerValue);
180 }
181 
191 {
192  d->setBody(body);
193 }
194 
211 {
212  d->setBodyDevice(device);
213 }
214 
215 
216 
271 {
272  Q_D(QHttpMultiPart);
273  d->contentType = MixedType;
274 }
275 
283 {
284  Q_D(QHttpMultiPart);
285  d->contentType = contentType;
286 }
287 
292 {
293 }
294 
298 void QHttpMultiPart::append(const QHttpPart &httpPart)
299 {
300  d_func()->parts.append(httpPart);
301 }
302 
316 {
317  d_func()->contentType = contentType;
318 }
319 
326 {
327  return d_func()->boundary;
328 }
329 
341 {
342  d_func()->boundary = boundary;
343 }
344 
345 
346 
347 // ------------------------------------------------------------------
348 // ----------- implementations of private classes: ------------------
349 // ------------------------------------------------------------------
350 
351 
352 
354 {
355  checkHeaderCreated();
356  qint64 bytesAvailable = header.count();
357  if (bodyDevice) {
358  bytesAvailable += bodyDevice->bytesAvailable() - readPointer;
359  } else {
360  bytesAvailable += body.count() - readPointer;
361  }
362  // the device might have closed etc., so make sure we do not return a negative value
363  return qMax(bytesAvailable, (qint64) 0);
364 }
365 
367 {
368  checkHeaderCreated();
369  qint64 bytesRead = 0;
370  qint64 headerDataCount = header.count();
371 
372  // read header if it has not been read yet
373  if (readPointer < headerDataCount) {
374  bytesRead = qMin(headerDataCount - readPointer, maxSize);
375  const char *headerData = header.constData();
376  memcpy(data, headerData + readPointer, bytesRead);
377  readPointer += bytesRead;
378  }
379  // read content if there is still space
380  if (bytesRead < maxSize) {
381  if (bodyDevice) {
382  qint64 dataBytesRead = bodyDevice->read(data + bytesRead, maxSize - bytesRead);
383  if (dataBytesRead == -1)
384  return -1;
385  bytesRead += dataBytesRead;
386  readPointer += dataBytesRead;
387  } else {
388  qint64 contentBytesRead = qMin(body.count() - readPointer + headerDataCount, maxSize - bytesRead);
389  const char *contentData = body.constData();
390  // if this method is called several times, we need to find the
391  // right offset in the content ourselves:
392  memcpy(data + bytesRead, contentData + readPointer - headerDataCount, contentBytesRead);
393  bytesRead += contentBytesRead;
394  readPointer += contentBytesRead;
395  }
396  }
397  return bytesRead;
398 }
399 
401 {
402  checkHeaderCreated();
403  qint64 size = header.count();
404  if (bodyDevice) {
405  size += bodyDevice->size();
406  } else {
407  size += body.count();
408  }
409  return size;
410 }
411 
413 {
414  bool ret = true;
415  if (bodyDevice)
416  if (!bodyDevice->reset())
417  ret = false;
418  readPointer = 0;
419  return ret;
420 }
421 void QHttpPartPrivate::checkHeaderCreated() const
422 {
423  if (!headerCreated) {
424  // copied from QHttpNetworkRequestPrivate::header() and adapted
427  for (; it != fields.constEnd(); ++it)
428  header += it->first + ": " + it->second + "\r\n";
429  header += "\r\n";
430  headerCreated = true;
431  }
432 }
433 
435 {
436  // 24 random bytes, becomes 32 characters when encoded to Base64
437  quint32 random[6];
439  boundary = "boundary_.oOo._"
440  + QByteArray::fromRawData(reinterpret_cast<char *>(random), sizeof(random)).toBase64();
441 
442  // boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
443  Q_ASSERT(boundary.count() <= 70);
444 }
445 
447 {
448  // if not done yet, we calculate the size and the offsets of each part,
449  // including boundary (needed later in readData)
450  if (deviceSize == -1) {
451  qint64 currentSize = 0;
452  qint64 boundaryCount = multiPart->boundary.count();
453  for (int a = 0; a < multiPart->parts.count(); a++) {
454  partOffsets.append(currentSize);
455  // 4 additional bytes for the "--" before and the "\r\n" after the boundary,
456  // and 2 bytes for the "\r\n" after the content
457  currentSize += boundaryCount + 4 + multiPart->parts.at(a).d->size() + 2;
458  }
459  currentSize += boundaryCount + 6; // size for ending boundary, 2 beginning and ending dashes and "\r\n"
460  deviceSize = currentSize;
461  }
462  return deviceSize;
463 }
464 
466 {
467  for (int a = 0; a < multiPart->parts.count(); a++) {
469  // we are sequential if any of the bodyDevices of our parts are sequential;
470  // when reading from a byte array, we are not sequential
471  if (device && device->isSequential())
472  return true;
473  }
474  return false;
475 }
476 
478 {
479  // Reset QIODevice's data
481  for (int a = 0; a < multiPart->parts.count(); a++)
482  if (!multiPart->parts[a].d->reset())
483  return false;
484  readPointer = 0;
485  return true;
486 }
488 {
489  qint64 bytesRead = 0, index = 0;
490 
491  // skip the parts we have already read
492  while (index < multiPart->parts.count() &&
494  + multiPart->boundary.count() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
495  index++;
496 
497  // read the data
498  while (bytesRead < maxSize && index < multiPart->parts.count()) {
499 
500  // check whether we need to read the boundary of the current part
501  QByteArray boundaryData = "--" + multiPart->boundary + "\r\n";
502  qint64 boundaryCount = boundaryData.count();
503  qint64 partIndex = readPointer - partOffsets.at(index);
504  if (partIndex < boundaryCount) {
505  qint64 boundaryBytesRead = qMin(boundaryCount - partIndex, maxSize - bytesRead);
506  memcpy(data + bytesRead, boundaryData.constData() + partIndex, boundaryBytesRead);
507  bytesRead += boundaryBytesRead;
508  readPointer += boundaryBytesRead;
509  partIndex += boundaryBytesRead;
510  }
511 
512  // check whether we need to read the data of the current part
513  if (bytesRead < maxSize && partIndex >= boundaryCount && partIndex < boundaryCount + multiPart->parts.at(index).d->size()) {
514  qint64 dataBytesRead = multiPart->parts[index].d->readData(data + bytesRead, maxSize - bytesRead);
515  if (dataBytesRead == -1)
516  return -1;
517  bytesRead += dataBytesRead;
518  readPointer += dataBytesRead;
519  partIndex += dataBytesRead;
520  }
521 
522  // check whether we need to read the ending CRLF of the current part
523  if (bytesRead < maxSize && partIndex >= boundaryCount + multiPart->parts.at(index).d->size()) {
524  if (bytesRead == maxSize - 1)
525  return bytesRead;
526  memcpy(data + bytesRead, "\r\n", 2);
527  bytesRead += 2;
528  readPointer += 2;
529  index++;
530  }
531  }
532  // check whether we need to return the final boundary
533  if (bytesRead < maxSize && index == multiPart->parts.count()) {
534  QByteArray finalBoundary = "--" + multiPart->boundary + "--\r\n";
535  qint64 boundaryIndex = readPointer + finalBoundary.count() - size();
536  qint64 lastBoundaryBytesRead = qMin(finalBoundary.count() - boundaryIndex, maxSize - bytesRead);
537  memcpy(data + bytesRead, finalBoundary.constData() + boundaryIndex, lastBoundaryBytesRead);
538  bytesRead += lastBoundaryBytesRead;
539  readPointer += lastBoundaryBytesRead;
540  }
541  return bytesRead;
542 }
543 
545 {
546  Q_UNUSED(data);
547  Q_UNUSED(maxSize);
548  return -1;
549 }
550 
551 
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
const char * constData() const noexcept
Definition: qbytearray.h:144
QByteArray toBase64(Base64Options options=Base64Encoding) const
qsizetype count(char c) const
static QByteArray fromRawData(const char *data, qsizetype size)
Definition: qbytearray.h:396
The QHttpMultiPart class resembles a MIME multipart message to be sent over HTTP.
void append(const QHttpPart &httpPart)
QByteArray boundary() const
void setContentType(ContentType contentType)
void setBoundary(const QByteArray &boundary)
QHttpMultiPart(QObject *parent=nullptr)
virtual bool isSequential() const override
virtual qint64 size() const override
virtual bool reset() override
QList< qint64 > partOffsets
virtual qint64 readData(char *data, qint64 maxSize) override
virtual qint64 writeData(const char *data, qint64 maxSize) override
QHttpMultiPartPrivate * multiPart
QList< QHttpPart > parts
The QHttpPart class holds a body part to be used inside a HTTP multipart MIME message.
bool operator==(const QHttpPart &other) const
void setBodyDevice(QIODevice *device)
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
void setBody(const QByteArray &body)
QHttpPart & operator=(QHttpPart &&other) noexcept
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
void setBody(const QByteArray &newBody)
QIODevice * bodyDevice
qint64 readData(char *data, qint64 maxSize)
qint64 bytesAvailable() const
void setBodyDevice(QIODevice *device)
qint64 size() const
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:70
virtual qint64 size() const
Definition: qiodevice.cpp:874
virtual qint64 bytesAvailable() const
Definition: qiodevice.cpp:995
virtual bool reset()
Definition: qiodevice.cpp:975
qint64 read(char *data, qint64 maxlen)
Definition: qiodevice.cpp:1030
Definition: qlist.h:108
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
const_iterator constBegin() const noexcept
Definition: qlist.h:630
qsizetype count() const noexcept
Definition: qlist.h:415
void append(parameter_type t)
Definition: qlist.h:469
const_iterator constEnd() const noexcept
Definition: qlist.h:631
RawHeadersList allRawHeaders() const
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
void setRawHeader(const QByteArray &key, const QByteArray &value)
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
Definition: qrandom.h:311
void fillRange(UInt *buffer, qsizetype count)
Definition: qrandom.h:177
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
#define this
Definition: dialogs.cpp:56
std::enable_if< std::is_integral< T >::value &&!std::is_same< T, bool >::value, GeneratorWrapper< T > >::type random(T a, T b)
Definition: catch_p_p.h:4651
typename C::const_iterator const_iterator
EGLOutputLayerEXT EGLint EGLAttrib value
unsigned int quint32
Definition: qglobal.h:288
long long qint64
Definition: qglobal.h:298
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:84
Q_UNUSED(salary)
[21]
QSharedPointer< T > other(t)
[5]
QString contentType
QHttpRequestHeader header("GET", QUrl::toPercentEncoding("/index.html"))
[1]
QStringList::Iterator it
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent