Qt 4.8
qhttpmultipart.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qhttpmultipart.h"
43 #include "qhttpmultipart_p.h"
44 #include "QtCore/qdatetime.h" // for initializing the random number generator with QTime
45 #include "QtCore/qmutex.h"
46 #include "QtCore/qthreadstorage.h"
47 
49 
103 {
104 }
105 
109 QHttpPart::QHttpPart(const QHttpPart &other) : d(other.d)
110 {
111 }
112 
117 {
118  d = 0;
119 }
120 
125 {
126  d = other.d;
127  return *this;
128 }
129 
136 bool QHttpPart::operator==(const QHttpPart &other) const
137 {
138  return d == other.d || *d == *other.d;
139 }
140 
159 {
160  d->setCookedHeader(header, value);
161 }
162 
177 {
178  d->setRawHeader(headerName, headerValue);
179 }
180 
190 {
191  d->setBody(body);
192 }
193 
210 {
211  d->setBodyDevice(device);
212 }
213 
214 
215 
276 {
278  d->contentType = MixedType;
279 }
280 
288 {
290  d->contentType = contentType;
291 }
292 
297 {
298 }
299 
303 void QHttpMultiPart::append(const QHttpPart &httpPart)
304 {
305  d_func()->parts.append(httpPart);
306 }
307 
321 {
322  d_func()->contentType = contentType;
323 }
324 
331 {
332  return d_func()->boundary;
333 }
334 
346 {
347  d_func()->boundary = boundary;
348 }
349 
350 
351 
352 // ------------------------------------------------------------------
353 // ----------- implementations of private classes: ------------------
354 // ------------------------------------------------------------------
355 
356 
357 
359 {
360  checkHeaderCreated();
361  qint64 bytesAvailable = header.count();
362  if (bodyDevice) {
363  bytesAvailable += bodyDevice->bytesAvailable() - readPointer;
364  } else {
365  bytesAvailable += body.count() - readPointer;
366  }
367  // the device might have closed etc., so make sure we do not return a negative value
368  return qMax(bytesAvailable, (qint64) 0);
369 }
370 
372 {
373  checkHeaderCreated();
374  qint64 bytesRead = 0;
375  qint64 headerDataCount = header.count();
376 
377  // read header if it has not been read yet
378  if (readPointer < headerDataCount) {
379  bytesRead = qMin(headerDataCount - readPointer, maxSize);
380  const char *headerData = header.constData();
381  memcpy(data, headerData + readPointer, bytesRead);
382  readPointer += bytesRead;
383  }
384  // read content if there is still space
385  if (bytesRead < maxSize) {
386  if (bodyDevice) {
387  qint64 dataBytesRead = bodyDevice->read(data + bytesRead, maxSize - bytesRead);
388  if (dataBytesRead == -1)
389  return -1;
390  bytesRead += dataBytesRead;
391  readPointer += dataBytesRead;
392  } else {
393  qint64 contentBytesRead = qMin(body.count() - readPointer + headerDataCount, maxSize - bytesRead);
394  const char *contentData = body.constData();
395  // if this method is called several times, we need to find the
396  // right offset in the content ourselves:
397  memcpy(data + bytesRead, contentData + readPointer - headerDataCount, contentBytesRead);
398  bytesRead += contentBytesRead;
399  readPointer += contentBytesRead;
400  }
401  }
402  return bytesRead;
403 }
404 
406 {
407  checkHeaderCreated();
408  qint64 size = header.count();
409  if (bodyDevice) {
410  size += bodyDevice->size();
411  } else {
412  size += body.count();
413  }
414  return size;
415 }
416 
418 {
419  bool ret = true;
420  if (bodyDevice)
421  if (!bodyDevice->reset())
422  ret = false;
423  readPointer = 0;
424  return ret;
425 }
427 {
428  if (!headerCreated) {
429  // copied from QHttpNetworkRequestPrivate::header() and adapted
430  QList<QPair<QByteArray, QByteArray> > fields = allRawHeaders();
431  QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
432  for (; it != fields.constEnd(); ++it)
433  header += it->first + ": " + it->second + "\r\n";
434  header += "\r\n";
435  headerCreated = true;
436  }
437 }
438 
439 Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
440 
442 {
443  if (!seedCreatedStorage()->hasLocalData()) {
444  qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
445  seedCreatedStorage()->setLocalData(new bool(true));
446  }
447 
448  boundary = QByteArray("boundary_.oOo._")
452 
453  // boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
454  if (boundary.count() > 70)
455  boundary = boundary.left(70);
456 }
457 
459 {
460  // if not done yet, we calculate the size and the offsets of each part,
461  // including boundary (needed later in readData)
462  if (deviceSize == -1) {
463  qint64 currentSize = 0;
464  qint64 boundaryCount = multiPart->boundary.count();
465  for (int a = 0; a < multiPart->parts.count(); a++) {
466  partOffsets.append(currentSize);
467  // 4 additional bytes for the "--" before and the "\r\n" after the boundary,
468  // and 2 bytes for the "\r\n" after the content
469  currentSize += boundaryCount + 4 + multiPart->parts.at(a).d->size() + 2;
470  }
471  currentSize += boundaryCount + 6; // size for ending boundary, 2 beginning and ending dashes and "\r\n"
472  deviceSize = currentSize;
473  }
474  return deviceSize;
475 }
476 
478 {
479  for (int a = 0; a < multiPart->parts.count(); a++) {
480  QIODevice *device = multiPart->parts.at(a).d->bodyDevice;
481  // we are sequential if any of the bodyDevices of our parts are sequential;
482  // when reading from a byte array, we are not sequential
483  if (device && device->isSequential())
484  return true;
485  }
486  return false;
487 }
488 
490 {
491  for (int a = 0; a < multiPart->parts.count(); a++)
492  if (!multiPart->parts[a].d->reset())
493  return false;
494  readPointer = 0;
495  return true;
496 }
498 {
499  qint64 bytesRead = 0, index = 0;
500 
501  // skip the parts we have already read
502  while (index < multiPart->parts.count() &&
503  readPointer >= partOffsets.at(index) + multiPart->parts.at(index).d->size()
504  + multiPart->boundary.count() + 6) // 6 == 2 boundary dashes, \r\n after boundary, \r\n after multipart
505  index++;
506 
507  // read the data
508  while (bytesRead < maxSize && index < multiPart->parts.count()) {
509 
510  // check whether we need to read the boundary of the current part
511  QByteArray boundaryData = "--" + multiPart->boundary + "\r\n";
512  qint64 boundaryCount = boundaryData.count();
513  qint64 partIndex = readPointer - partOffsets.at(index);
514  if (partIndex < boundaryCount) {
515  qint64 boundaryBytesRead = qMin(boundaryCount - partIndex, maxSize - bytesRead);
516  memcpy(data + bytesRead, boundaryData.constData() + partIndex, boundaryBytesRead);
517  bytesRead += boundaryBytesRead;
518  readPointer += boundaryBytesRead;
519  partIndex += boundaryBytesRead;
520  }
521 
522  // check whether we need to read the data of the current part
523  if (bytesRead < maxSize && partIndex >= boundaryCount && partIndex < boundaryCount + multiPart->parts.at(index).d->size()) {
524  qint64 dataBytesRead = multiPart->parts[index].d->readData(data + bytesRead, maxSize - bytesRead);
525  if (dataBytesRead == -1)
526  return -1;
527  bytesRead += dataBytesRead;
528  readPointer += dataBytesRead;
529  partIndex += dataBytesRead;
530  }
531 
532  // check whether we need to read the ending CRLF of the current part
533  if (bytesRead < maxSize && partIndex >= boundaryCount + multiPart->parts.at(index).d->size()) {
534  if (bytesRead == maxSize - 1)
535  return bytesRead;
536  memcpy(data + bytesRead, "\r\n", 2);
537  bytesRead += 2;
538  readPointer += 2;
539  index++;
540  }
541  }
542  // check whether we need to return the final boundary
543  if (bytesRead < maxSize && index == multiPart->parts.count()) {
544  QByteArray finalBoundary = "--" + multiPart->boundary + "--\r\n";
545  qint64 boundaryIndex = readPointer + finalBoundary.count() - size();
546  qint64 lastBoundaryBytesRead = qMin(finalBoundary.count() - boundaryIndex, maxSize - bytesRead);
547  memcpy(data + bytesRead, finalBoundary.constData() + boundaryIndex, lastBoundaryBytesRead);
548  bytesRead += lastBoundaryBytesRead;
549  readPointer += lastBoundaryBytesRead;
550  }
551  return bytesRead;
552 }
553 
555 {
556  Q_UNUSED(data);
557  Q_UNUSED(maxSize);
558  return -1;
559 }
560 
561 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
void checkHeaderCreated() const
double d
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
virtual qint64 writeData(const char *data, qint64 maxSize)
Writes up to maxSize bytes from data to the device.
#define it(className, varName)
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
Q_GLOBAL_STATIC(QThreadStorage< bool *>, seedCreatedStorage)
void setRawHeader(const QByteArray &key, const QByteArray &value)
void append(const QHttpPart &httpPart)
Appends httpPart to this multipart.
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)...
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the list.
Definition: qlist.h:269
long ASN1_INTEGER_get ASN1_INTEGER * a
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
Q_CORE_EXPORT int qrand()
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
KnownHeaders
List of known header types that QNetworkRequest parses.
~QHttpMultiPart()
Destroys the multipart.
virtual qint64 size() const
For open random-access devices, this function returns the size of the device.
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
Sets the header headerName to be of value headerValue.
QByteArray boundary() const
returns the boundary.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
void setBody(const QByteArray &newBody)
QHttpMultiPartIODevice * device
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
~QHttpPart()
Destroys this QHttpPart.
QHttpPart()
Constructs an empty QHttpPart object.
void setBody(const QByteArray &body)
Sets the body of this MIME part to body.
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
qint64 bytesAvailable() const
static const char * data(const QByteArray &arr)
__int64 qint64
Definition: qglobal.h:942
QByteArray left(int len) const
Returns a byte array that contains the leftmost len bytes of this byte array.
QSharedDataPointer< QHttpPartPrivate > d
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
Definition: qiodevice.cpp:454
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
int count(char c) const
Returns the number of occurrences of character ch in the byte array.
static QTime currentTime()
Returns the current time as reported by the system clock.
Definition: qdatetime.cpp:3125
QHttpMultiPart(QObject *parent=0)
Constructs a QHttpMultiPart with content type MixedType and sets parent as the parent object...
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
void setBodyDevice(QIODevice *device)
virtual bool reset()
Seeks to the start of input for random-access devices.
QList< QHttpPart > parts
void setBodyDevice(QIODevice *device)
Sets the device to read the content from to device.
qint64 readData(char *data, qint64 maxSize)
QByteArray toBase64() const
Returns a copy of the byte array, encoded as Base64.
The QHttpMultiPart class resembles a MIME multipart message to be sent over HTTP. ...
quint16 index
The QHttpPart class holds a body part to be used inside a HTTP multipart MIME message.
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
ContentType
List of known content types for a multipart subtype as described in RFC 2046 and others.
QHttpPart & operator=(const QHttpPart &other)
Creates a copy of other.
Q_CORE_EXPORT void qsrand(uint seed)
qint64 size() const
virtual qint64 readData(char *data, qint64 maxSize)
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
void setContentType(ContentType contentType)
Sets the content type to contentType.
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
Sets the value of the known header header to be value, overriding any previously set headers...
The QThreadStorage class provides per-thread data storage.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...
void setBoundary(const QByteArray &boundary)
Sets the boundary to boundary.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:272