Qt 4.8
qhttpnetworkreply.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 "qhttpnetworkreply_p.h"
44 
45 #include <qbytearraymatcher.h>
46 
47 #ifndef QT_NO_HTTP
48 
49 #ifndef QT_NO_OPENSSL
50 # include <QtNetwork/qsslkey.h>
51 # include <QtNetwork/qsslcipher.h>
52 # include <QtNetwork/qsslconfiguration.h>
53 #endif
54 
56 
58  : QObject(*new QHttpNetworkReplyPrivate(url), parent)
59 {
60 }
61 
63 {
65  if (d->connection) {
66  d->connection->d_func()->removeReply(this);
67  }
68 }
69 
71 {
72  return d_func()->url;
73 }
75 {
77  d->url = url;
78 }
79 
81 {
82  return d_func()->contentLength();
83 }
84 
86 {
88  d->setContentLength(length);
89 }
90 
92 {
93  return d_func()->fields;
94 }
95 
97 {
98  return d_func()->headerField(name, defaultValue);
99 }
100 
102 {
104  d->setHeaderField(name, data);
105 }
106 
108 {
110  d->parseHeader(header);
111 }
112 
114 {
115  return d_func()->request;
116 }
117 
119 {
121  d->request = request;
122  d->ssl = request.isSsl();
123 }
124 
126 {
127  return d_func()->statusCode;
128 }
129 
131 {
133  d->statusCode = code;
134 }
135 
137 {
138  return d_func()->errorString;
139 }
140 
142 {
143  return d_func()->reasonPhrase;
144 }
145 
147 {
149  d->errorString = error;
150 }
151 
153 {
154  return d_func()->majorVersion;
155 }
156 
158 {
159  return d_func()->minorVersion;
160 }
161 
163 {
164  Q_D(const QHttpNetworkReply);
165  if (d->connection)
166  return d->connection->d_func()->uncompressedBytesAvailable(*this);
167  else
168  return -1;
169 }
170 
172 {
173  Q_D(const QHttpNetworkReply);
174  if (d->connection)
175  return d->connection->d_func()->uncompressedBytesAvailableNextBlock(*this);
176  else
177  return -1;
178 }
179 
181 {
182  Q_D(const QHttpNetworkReply);
183  return (d->responseData.bufferCount() > 0);
184 }
185 
187 {
189  if (d->responseData.bufferCount() == 0)
190  return QByteArray();
191 
192  // we'll take the last buffer, so schedule another read from http
193  if (d->downstreamLimited && d->responseData.bufferCount() == 1)
194  d->connection->d_func()->readMoreLater(this);
195  return d->responseData.read();
196 }
197 
199 {
201  return d->responseData.readAll();
202 }
203 
205 {
207  return d->responseData.read(amount);
208 }
209 
211 {
213  return d->responseData.sizeNextBlock();
214 }
215 
217 {
219  d->downstreamLimited = dsl;
220  d->connection->d_func()->readMoreLater(this);
221 }
222 
224 {
226  d->readBufferMaxSize = size;
227 }
228 
230 {
232  return (!d->isChunked() && !d->autoDecompress && d->bodyLength > 0);
233 }
234 
236 {
239  d->userProvidedDownloadBuffer = b;
240 }
241 
243 {
245  return d->userProvidedDownloadBuffer;
246 }
247 
249 {
250  return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;
251 }
252 
254 {
255  return d_func()->pipeliningUsed;
256 }
257 
259 {
260  return d_func()->connection;
261 }
262 
263 
265  : QHttpNetworkHeaderPrivate(newUrl)
266  , state(NothingDoneState)
267  , ssl(false)
268  , statusCode(100),
269  majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0),
270  chunkedTransferEncoding(false),
271  connectionCloseEnabled(true),
272  forceConnectionCloseEnabled(false),
273  lastChunkRead(false),
274  currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0), connection(0), initInflate(false),
275  autoDecompress(false), responseData(), requestIsPrepared(false)
276  ,pipeliningUsed(false), downstreamLimited(false)
278 {
279 }
280 
282 {
283 }
284 
286 {
288  statusCode = 100;
289  bodyLength = 0;
290  contentRead = 0;
291  totalProgress = 0;
292  currentChunkSize = 0;
293  currentChunkRead = 0;
294  lastChunkRead = false;
295  connectionCloseEnabled = true;
296 #ifndef QT_NO_COMPRESS
297  if (initInflate)
298  inflateEnd(&inflateStrm);
299 #endif
300  initInflate = false;
301  streamEnd = false;
302  fields.clear();
303 }
304 
305 // TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
307 {
308  connection = 0;
309  connectionChannel = 0;
310  autoDecompress = false;
312 }
313 
314 // QHttpNetworkReplyPrivate
316 {
317  return (state != ReadingDataState ? 0 : fragment.size());
318 }
319 
321 {
322  QByteArray encoding = headerField("content-encoding");
323  return qstricmp(encoding.constData(), "gzip") == 0;
324 }
325 
327 {
328  // The header "Content-Encoding = gzip" is retained.
329  // Content-Length is removed since the actual one send by the server is for compressed data
330  QByteArray name("content-length");
332  end = fields.end();
333  while (it != end) {
334  if (qstricmp(name.constData(), it->first.constData()) == 0) {
335  fields.erase(it);
336  break;
337  }
338  ++it;
339  }
340 
341 }
342 
343 bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const
344 {
345  challenge.clear();
346  // find out the type of authentication protocol requested.
347  QByteArray header = forProxy ? "proxy-authenticate" : "www-authenticate";
348  // pick the best protocol (has to match parsing in QAuthenticatorPrivate)
349  QList<QByteArray> challenges = headerFieldValues(header);
350  for (int i = 0; i<challenges.size(); i++) {
351  QByteArray line = challenges.at(i);
352  // todo use qstrincmp
353  if (!line.toLower().startsWith("negotiate"))
354  challenge = line;
355  }
356  return !challenge.isEmpty();
357 }
358 
360 {
361  // The logic is same as the one used in void QAuthenticatorPrivate::parseHttpResponse()
363  QByteArray header = isProxy ? "proxy-authenticate" : "www-authenticate";
364  QList<QByteArray> challenges = headerFieldValues(header);
365  for (int i = 0; i<challenges.size(); i++) {
366  QByteArray line = challenges.at(i).trimmed().toLower();
367  if (method < QAuthenticatorPrivate::Basic
368  && line.startsWith("basic")) {
370  } else if (method < QAuthenticatorPrivate::Ntlm
371  && line.startsWith("ntlm")) {
373  } else if (method < QAuthenticatorPrivate::DigestMd5
374  && line.startsWith("digest")) {
376  }
377  }
378  return method;
379 }
380 
381 #ifndef QT_NO_COMPRESS
383 {
384  int method = 0; // method byte
385  int flags = 0; // flags byte
386  bool ret = false;
387 
388  // Assure two bytes in the buffer so we can peek ahead -- handle case
389  // where first byte of header is at the end of the buffer after the last
390  // gzip segment
391  pos = -1;
392  QByteArray &body = content;
393  int maxPos = body.size()-1;
394  if (maxPos < 1) {
395  return ret;
396  }
397 
398  // Peek ahead to check the gzip magic header
399  if (body[0] != char(gz_magic[0]) ||
400  body[1] != char(gz_magic[1])) {
401  return ret;
402  }
403  pos += 2;
404  // Check the rest of the gzip header
405  if (++pos <= maxPos)
406  method = body[pos];
407  if (pos++ <= maxPos)
408  flags = body[pos];
409  if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
410  return ret;
411  }
412 
413  // Discard time, xflags and OS code:
414  pos += 6;
415  if (pos > maxPos)
416  return ret;
417  if ((flags & EXTRA_FIELD) && ((pos+2) <= maxPos)) { // skip the extra field
418  unsigned len = (unsigned)body[++pos];
419  len += ((unsigned)body[++pos])<<8;
420  pos += len;
421  if (pos > maxPos)
422  return ret;
423  }
424  if ((flags & ORIG_NAME) != 0) { // skip the original file name
425  while(++pos <= maxPos && body[pos]) {}
426  }
427  if ((flags & COMMENT) != 0) { // skip the .gz file comment
428  while(++pos <= maxPos && body[pos]) {}
429  }
430  if ((flags & HEAD_CRC) != 0) { // skip the header crc
431  pos += 2;
432  if (pos > maxPos)
433  return ret;
434  }
435  ret = (pos < maxPos); // return failed, if no more bytes left
436  return ret;
437 }
438 
440 {
441  int ret = Z_DATA_ERROR;
442  unsigned have;
443  unsigned char out[CHUNK];
444  int pos = -1;
445 
446  if (!initInflate) {
447  // check the header
448  if (!gzipCheckHeader(compressed, pos))
449  return ret;
450  // allocate inflate state
451  inflateStrm.zalloc = Z_NULL;
452  inflateStrm.zfree = Z_NULL;
453  inflateStrm.opaque = Z_NULL;
454  inflateStrm.avail_in = 0;
455  inflateStrm.next_in = Z_NULL;
456  ret = inflateInit2(&inflateStrm, -MAX_WBITS);
457  if (ret != Z_OK)
458  return ret;
459  initInflate = true;
460  streamEnd = false;
461  }
462 
463  //remove the header.
464  compressed.remove(0, pos+1);
465  // expand until deflate stream ends
466  inflateStrm.next_in = (unsigned char *)compressed.data();
467  inflateStrm.avail_in = compressed.size();
468  do {
469  inflateStrm.avail_out = sizeof(out);
470  inflateStrm.next_out = out;
471  ret = inflate(&inflateStrm, Z_NO_FLUSH);
472  switch (ret) {
473  case Z_NEED_DICT:
474  ret = Z_DATA_ERROR;
475  // and fall through
476  case Z_DATA_ERROR:
477  case Z_MEM_ERROR:
478  inflateEnd(&inflateStrm);
479  initInflate = false;
480  return ret;
481  }
482  have = sizeof(out) - inflateStrm.avail_out;
483  inflated.append(QByteArray((const char *)out, have));
484  } while (inflateStrm.avail_out == 0 && inflateStrm.avail_in > 0);
485  // clean up and return
486  if (ret <= Z_ERRNO || ret == Z_STREAM_END) {
488  }
489  streamEnd = (ret == Z_STREAM_END);
490  return ret;
491 }
492 
494 {
495  if (initInflate) {
496  inflateEnd(&inflateStrm);
497  initInflate = false;
498  }
499 }
500 
501 #endif
502 
504 {
505  if (fragment.isEmpty()) {
506  // reserve bytes for the status line. This is better than always append() which reallocs the byte array
507  fragment.reserve(32);
508  }
509 
510  qint64 bytes = 0;
511  char c;
512  qint64 haveRead = 0;
513 
514  do {
515  haveRead = socket->read(&c, 1);
516  if (haveRead == -1)
517  return -1; // unexpected EOF
518  else if (haveRead == 0)
519  break; // read more later
520  else if (haveRead == 1 && fragment.size() == 0 && (c == 11 || c == '\n' || c == '\r' || c == ' ' || c == 31))
521  continue; // Ignore all whitespace that was trailing froma previous request on that socket
522 
523  bytes++;
524 
525  // allow both CRLF & LF (only) line endings
526  if (c == '\n') {
527  // remove the CR at the end
528  if (fragment.endsWith('\r')) {
530  }
531  bool ok = parseStatus(fragment);
533  fragment.clear();
534  if (!ok) {
535  return -1;
536  }
537  break;
538  } else {
539  fragment.append(c);
540  }
541 
542  // is this a valid reply?
543  if (fragment.length() >= 5 && !fragment.startsWith("HTTP/"))
544  {
545  fragment.clear();
546  return -1;
547  }
548  } while (haveRead == 1);
549 
550  return bytes;
551 }
552 
554 {
555  // from RFC 2616:
556  // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
557  // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
558  // that makes: 'HTTP/n.n xxx Message'
559  // byte count: 0123456789012
560 
561  static const int minLength = 11;
562  static const int dotPos = 6;
563  static const int spacePos = 8;
564  static const char httpMagic[] = "HTTP/";
565 
566  if (status.length() < minLength
567  || !status.startsWith(httpMagic)
568  || status.at(dotPos) != '.'
569  || status.at(spacePos) != ' ') {
570  // I don't know how to parse this status line
571  return false;
572  }
573 
574  // optimize for the valid case: defer checking until the end
575  majorVersion = status.at(dotPos - 1) - '0';
576  minorVersion = status.at(dotPos + 1) - '0';
577 
578  int i = spacePos;
579  int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length()
580  const QByteArray code = status.mid(i + 1, j - i - 1);
581 
582  bool ok;
583  statusCode = code.toInt(&ok);
584  reasonPhrase = QString::fromLatin1(status.constData() + j + 1);
585 
586  return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
587 }
588 
590 {
591  if (fragment.isEmpty()) {
592  // according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
593  // block is 381 bytes.
594  // reserve bytes. This is better than always append() which reallocs the byte array.
595  fragment.reserve(512);
596  }
597 
598  qint64 bytes = 0;
599  char c = 0;
600  bool allHeaders = false;
601  qint64 haveRead = 0;
602  do {
603  haveRead = socket->read(&c, 1);
604  if (haveRead == 0) {
605  // read more later
606  break;
607  } else if (haveRead == -1) {
608  // connection broke down
609  return -1;
610  } else {
611  fragment.append(c);
612  bytes++;
613 
614  if (c == '\n') {
615  // check for possible header endings. As per HTTP rfc,
616  // the header endings will be marked by CRLFCRLF. But
617  // we will allow CRLFCRLF, CRLFLF, LFLF
618  if (fragment.endsWith("\r\n\r\n")
619  || fragment.endsWith("\r\n\n")
620  || fragment.endsWith("\n\n"))
621  allHeaders = true;
622 
623  // there is another case: We have no headers. Then the fragment equals just the line ending
624  if ((fragment.length() == 2 && fragment.endsWith("\r\n"))
625  || (fragment.length() == 1 && fragment.endsWith("\n")))
626  allHeaders = true;
627  }
628  }
629  } while (!allHeaders && haveRead > 0);
630 
631  // we received all headers now parse them
632  if (allHeaders) {
635  fragment.clear(); // next fragment
636  bodyLength = contentLength(); // cache the length
637 
638  // cache isChunked() since it is called often
639  chunkedTransferEncoding = headerField("transfer-encoding").toLower().contains("chunked");
640 
641  // cache isConnectionCloseEnabled since it is called often
642  QByteArray connectionHeaderField = headerField("connection");
643  // check for explicit indication of close or the implicit connection close of HTTP/1.0
644  connectionCloseEnabled = (connectionHeaderField.toLower().contains("close") ||
645  headerField("proxy-connection").toLower().contains("close")) ||
646  (majorVersion == 1 && minorVersion == 0 &&
647  (connectionHeaderField.isEmpty() && !headerField("proxy-connection").toLower().contains("keep-alive")));
648  }
649  return bytes;
650 }
651 
653 {
654  // see rfc2616, sec 4 for information about HTTP/1.1 headers.
655  // allows relaxed parsing here, accepts both CRLF & LF line endings
656  const QByteArrayMatcher lf("\n");
657  const QByteArrayMatcher colon(":");
658  int i = 0;
659  while (i < header.count()) {
660  int j = colon.indexIn(header, i); // field-name
661  if (j == -1)
662  break;
663  const QByteArray field = header.mid(i, j - i).trimmed();
664  j++;
665  // any number of LWS is allowed before and after the value
666  QByteArray value;
667  do {
668  i = lf.indexIn(header, j);
669  if (i == -1)
670  break;
671  if (!value.isEmpty())
672  value += ' ';
673  // check if we have CRLF or only LF
674  bool hasCR = (i && header[i-1] == '\r');
675  int length = i -(hasCR ? 1: 0) - j;
676  value += header.mid(j, length).trimmed();
677  j = ++i;
678  } while (i < header.count() && (header.at(i) == ' ' || header.at(i) == '\t'));
679  if (i == -1)
680  break; // something is wrong
681 
682  fields.append(qMakePair(field, value));
683  }
684 }
685 
687 {
689 }
690 
692 {
694 }
695 
696 // note this function can only be used for non-chunked, non-compressed with
697 // known content length
699 {
700  // This first read is to flush the buffer inside the socket
701  qint64 haveRead = 0;
702  haveRead = socket->read(b, bodyLength - contentRead);
703  if (haveRead == -1) {
704  return 0; // ### error checking here;
705  }
706  contentRead += haveRead;
707 
708  if (contentRead == bodyLength) {
710  }
711 
712  return haveRead;
713 }
714 
715 // note this function can only be used for non-chunked, non-compressed with
716 // known content length
718 {
719 
720  qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
721  if (readBufferMaxSize)
722  toBeRead = qMin(toBeRead, readBufferMaxSize);
723  QByteArray bd;
724  bd.resize(toBeRead);
725  qint64 haveRead = socket->read(bd.data(), toBeRead);
726  if (haveRead == -1) {
727  bd.clear();
728  return 0; // ### error checking here;
729  }
730  bd.resize(haveRead);
731 
732  rb->append(bd);
733 
734  if (contentRead + haveRead == bodyLength) {
736  }
737 
738  contentRead += haveRead;
739  return haveRead;
740 }
741 
742 
744 {
745  qint64 bytes = 0;
746  if (isChunked()) {
747  // chunked transfer encoding (rfc 2616, sec 3.6)
748  bytes += readReplyBodyChunked(socket, out);
749  } else if (bodyLength > 0) {
750  // we have a Content-Length
751  bytes += readReplyBodyRaw(socket, out, bodyLength - contentRead);
752  if (contentRead + bytes == bodyLength)
754  } else {
755  // no content length. just read what's possible
756  bytes += readReplyBodyRaw(socket, out, socket->bytesAvailable());
757  }
758  contentRead += bytes;
759  return bytes;
760 }
761 
763 {
764  // FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
765  qint64 bytes = 0;
766  Q_ASSERT(socket);
767  Q_ASSERT(out);
768 
769  int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
770  if (readBufferMaxSize)
771  toBeRead = qMin<qint64>(toBeRead, readBufferMaxSize);
772 
773  while (toBeRead > 0) {
774  QByteArray byteData;
775  byteData.resize(toBeRead);
776  qint64 haveRead = socket->read(byteData.data(), byteData.size());
777  if (haveRead <= 0) {
778  // ### error checking here
779  byteData.clear();
780  return bytes;
781  }
782 
783  byteData.resize(haveRead);
784  out->append(byteData);
785  bytes += haveRead;
786  size -= haveRead;
787 
788  toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, socket->bytesAvailable()));
789  }
790  return bytes;
791 
792 }
793 
795 {
796  qint64 bytes = 0;
797  while (socket->bytesAvailable()) {
798 
799  if (readBufferMaxSize && (bytes > readBufferMaxSize))
800  break;
801 
803  // For the first chunk and when we're done with a chunk
804  currentChunkSize = 0;
805  currentChunkRead = 0;
806  if (bytes) {
807  // After a chunk
808  char crlf[2];
809  // read the "\r\n" after the chunk
810  qint64 haveRead = socket->read(crlf, 2);
811  // FIXME: This code is slightly broken and not optimal. What if the 2 bytes are not available yet?!
812  // For nice reasons (the toLong in getChunkSize accepting \n at the beginning
813  // it right now still works, but we should definitely fix this.
814 
815  if (haveRead != 2)
816  return bytes; // FIXME
817  bytes += haveRead;
818  }
819  // Note that chunk size gets stored in currentChunkSize, what is returned is the bytes read
820  bytes += getChunkSize(socket, &currentChunkSize);
821  if (currentChunkSize == -1)
822  break;
823  }
824  // if the chunk size is 0, end of the stream
825  if (currentChunkSize == 0 || lastChunkRead) {
826  lastChunkRead = true;
827  // try to read the "\r\n" after the chunk
828  char crlf[2];
829  qint64 haveRead = socket->read(crlf, 2);
830  if (haveRead > 0)
831  bytes += haveRead;
832 
833  if ((haveRead == 2 && crlf[0] == '\r' && crlf[1] == '\n') || (haveRead == 1 && crlf[0] == '\n'))
835  else if (haveRead == 1 && crlf[0] == '\r')
836  break; // Still waiting for the last \n
837  else if (haveRead > 0) {
838  // If we read something else then CRLF, we need to close the channel.
841  }
842  break;
843  }
844 
845  // otherwise, try to begin reading this chunk / to read what is missing for this chunk
846  qint64 haveRead = readReplyBodyRaw (socket, out, currentChunkSize - currentChunkRead);
847  currentChunkRead += haveRead;
848  bytes += haveRead;
849 
850  // ### error checking here
851 
852  }
853  return bytes;
854 }
855 
857 {
858  qint64 bytes = 0;
859  char crlf[2];
860  *chunkSize = -1;
861 
862  int bytesAvailable = socket->bytesAvailable();
863  // FIXME rewrite to permanent loop without bytesAvailable
864  while (bytesAvailable > bytes) {
865  qint64 sniffedBytes = socket->peek(crlf, 2);
866  int fragmentSize = fragment.size();
867 
868  // check the next two bytes for a "\r\n", skip blank lines
869  if ((fragmentSize && sniffedBytes == 2 && crlf[0] == '\r' && crlf[1] == '\n')
870  ||(fragmentSize > 1 && fragment.endsWith('\r') && crlf[0] == '\n'))
871  {
872  bytes += socket->read(crlf, 1); // read the \r or \n
873  if (crlf[0] == '\r')
874  bytes += socket->read(crlf, 1); // read the \n
875  bool ok = false;
876  // ignore the chunk-extension
878  *chunkSize = fragment.toLong(&ok, 16);
879  fragment.clear();
880  break; // size done
881  } else {
882  // read the fragment to the buffer
883  char c = 0;
884  qint64 haveRead = socket->read(&c, 1);
885  if (haveRead < 0) {
886  return -1; // FIXME
887  }
888  bytes += haveRead;
889  fragment.append(c);
890  }
891  }
892 
893  return bytes;
894 }
895 
897 {
898  responseData.append(qba);
899 
900  // clear the original! helps with implicit sharing and
901  // avoiding memcpy when the user is reading the data
902  qba.clear();
903 }
904 
906 {
907  responseData.append(data);
908 
909  // clear the original! helps with implicit sharing and
910  // avoiding memcpy when the user is reading the data
911  data.clear();
912 }
913 
915 {
916  // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
917  // instead of one QByteArray.
918  for(int i = 0; i < data.bufferCount(); i++) {
919  QByteArray &byteData = data[i];
920  compressedData.append(byteData.constData(), byteData.size());
921  }
922  data.clear();
923 }
924 
925 
927 {
928  // for 401 & 407 don't emit the data signals. Content along with these
929  // responses are send only if the authentication fails.
930  return (statusCode != 401 && statusCode != 407);
931 }
932 
934 {
935  // check whether we can expect content after the headers (rfc 2616, sec4.4)
936  if ((statusCode >= 100 && statusCode < 200)
937  || statusCode == 204 || statusCode == 304)
938  return false;
940  return false; // no body expected for HEAD request
941  qint64 expectedContentLength = contentLength();
942  if (expectedContentLength == 0)
943  return false;
944  if (expectedContentLength == -1 && bodyLength == 0) {
945  // The content-length header was stripped, but its value was 0.
946  // This would be the case for an explicitly zero-length compressed response.
947  return false;
948  }
949  return true;
950 }
951 
953 {
956 }
957 
958 
959 // SSL support below
960 #ifndef QT_NO_OPENSSL
961 
963 {
964  Q_D(const QHttpNetworkReply);
965 
966  if (!d->connectionChannel)
967  return QSslConfiguration();
968 
969  QSslSocket *sslSocket = qobject_cast<QSslSocket*>(d->connectionChannel->socket);
970  if (!sslSocket)
971  return QSslConfiguration();
972 
973  return sslSocket->sslConfiguration();
974 }
975 
977 {
979  if (d->connection)
980  d->connection->setSslConfiguration(config);
981 }
982 
984 {
986  if (d->connection)
987  d->connection->ignoreSslErrors();
988 }
989 
991 {
993  if (d->connection)
994  d->connection->ignoreSslErrors(errors);
995 }
996 
997 
998 #endif //QT_NO_OPENSSL
999 
1000 
1002 
1003 #endif // QT_NO_HTTP
T qobject_cast(QObject *object)
Definition: qobject.h:375
double d
Definition: qnumeric_p.h:62
qint64 bytesAvailableNextBlock() const
bool gzipCheckHeader(QByteArray &content, int &pos)
void setDownstreamLimited(bool t)
void setHeaderField(const QByteArray &name, const QByteArray &data)
void truncate(int pos)
Truncates the byte array at index position pos.
unsigned char c[8]
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
QHttpNetworkRequest request() const
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QString reasonPhrase() const
qint64 bytesAvailable() const
Returns the number of incoming bytes that are waiting to be read.
char * userProvidedDownloadBuffer()
#define it(className, varName)
QByteArray & append(char c)
Appends the character ch to this byte array.
void setRequest(const QHttpNetworkRequest &request)
QSslConfiguration sslConfiguration() const
Returns the socket&#39;s SSL configuration state.
Definition: qsslsocket.cpp:920
qint64 readHeader(QAbstractSocket *socket)
#define error(msg)
QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue=QByteArray()) const
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool readAnyAvailable() const
QList< QPair< QByteArray, QByteArray > > header() const
bool findChallenge(bool forProxy, QByteArray &challenge) const
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
Definition: qsslsocket.h:67
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
#define CHUNK
void setStatusCode(int code)
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
QByteArray toLower() const
Returns a lowercase copy of the byte array.
QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue=QByteArray()) const
long toLong(bool *ok=0, int base=10) const
void append(QByteDataBuffer &other)
Definition: qbytedata_p.h:77
QString errorString() const
bool isPipeliningUsed() const
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
bool startsWith(const QByteArray &a) const
Returns true if this byte array starts with byte array ba; otherwise returns false.
bool supportsUserProvidedDownloadBuffer()
#define Q_D(Class)
Definition: qglobal.h:2482
qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize)
QList< QByteArray > headerFieldValues(const QByteArray &name) const
void setContentLength(qint64 length)
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
qint64 readStatus(QAbstractSocket *socket)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool parseStatus(const QByteArray &status)
QHttpNetworkReplyPrivate(const QUrl &newUrl=QUrl())
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
QByteArray read(qint64 amount)
const char * name
QByteArray trimmed() const
Returns a byte array that has whitespace removed from the start and the end.
QList< QPair< QByteArray, QByteArray > > fields
QHttpNetworkRequest request
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
qint64 peek(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, without side effects (i.
Definition: qiodevice.cpp:1563
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
qint64 readReplyBodyRaw(QAbstractSocket *in, QByteDataBuffer *out, qint64 size)
void clear()
Removes all items from the list.
Definition: qlist.h:764
__int64 qint64
Definition: qglobal.h:942
void setReadBufferSize(qint64 size)
The QByteArrayMatcher class holds a sequence of bytes that can be quickly matched in a byte array...
Operation operation() const
QByteArray mid(int index, int len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos...
void appendUncompressedReplyData(QByteArray &qba)
int indexOf(char c, int from=0) const
Returns the index position of the first occurrence of the character ch in the byte array...
void setErrorString(const QString &error)
static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition: qzip.cpp:189
QHttpNetworkConnection * connection()
#define RESERVED
int length() const
Same as size().
Definition: qbytearray.h:356
#define EXTRA_FIELD
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
void setUrl(const QUrl &url)
static const unsigned char gz_magic[2]
enum QHttpNetworkReplyPrivate::ReplyState state
iterator erase(iterator pos)
Removes the item associated with the iterator pos from the list, and returns an iterator to the next ...
Definition: qlist.h:464
QString trimmed(QString source)
Definition: generator.cpp:233
qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out)
QPointer< QHttpNetworkConnectionChannel > connectionChannel
int count(char c) const
Returns the number of occurrences of character ch in the byte array.
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
int toInt(bool *ok=0, int base=10) const
Returns the byte array converted to an int using base base, which is 10 by default and must be betwee...
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
void resize(int size)
Sets the size of the byte array to size bytes.
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
qint64 contentLength() const
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
#define ORIG_NAME
void parseHeader(const QByteArray &header)
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
int gunzipBodyPartially(QByteArray &compressed, QByteArray &inflated)
The QSslConfiguration class holds the configuration and state of an SSL connection.
QPointer< QHttpNetworkConnection > connection
#define HEAD_CRC
void setUserProvidedDownloadBuffer(char *)
qint64 readBodyVeryFast(QAbstractSocket *socket, char *b)
Q_CORE_EXPORT int qstricmp(const char *, const char *)
char at(int i) const
Returns the character at index position i in the byte array.
Definition: qbytearray.h:413
void reserve(int size)
Attempts to allocate memory for at least size bytes.
Definition: qbytearray.h:449
QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const
static const KeyPair *const end
qint64 bytesAvailable() const
qint64 bufferCount() const
Definition: qbytedata_p.h:187
The QAbstractSocket class provides the base functionality common to all socket types.
void setSslConfiguration(const QSslConfiguration &config)
qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
QSslConfiguration sslConfiguration() const
QHttpNetworkReply(const QUrl &url=QUrl(), QObject *parent=0)
QByteArray & remove(int index, int len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
int indexIn(const QByteArray &ba, int from=0) const
Searches the byte array ba, from byte position from (default 0, i.e.
void clear()
Clears the contents of the byte array and makes it empty.
void appendCompressedReplyData(QByteDataBuffer &data)
void parseHeader(const QByteArray &header)
bool endsWith(const QByteArray &a) const
Returns true if this byte array ends with byte array ba; otherwise returns false. ...
QBool contains(char c) const
Returns true if the byte array contains the character ch; otherwise returns false.
Definition: qbytearray.h:525
The QList class is a template class that provides lists.
Definition: qdatastream.h:62