Qt 4.8
qhttpnetworkconnectionchannel.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 
44 #include "private/qnoncontiguousbytedevice_p.h"
45 
46 #include <qpair.h>
47 #include <qdebug.h>
48 
49 #ifndef QT_NO_HTTP
50 
51 #ifndef QT_NO_OPENSSL
52 # include <QtNetwork/qsslkey.h>
53 # include <QtNetwork/qsslcipher.h>
54 # include <QtNetwork/qsslconfiguration.h>
55 #endif
56 
57 #ifndef QT_NO_BEARERMANAGEMENT
58 #include "private/qnetworksession_p.h"
59 #endif
60 
62 
63 // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
64 
66  : socket(0)
67  , ssl(false)
68  , state(IdleState)
69  , reply(0)
70  , written(0)
71  , bytesTotal(0)
72  , resendCurrent(false)
73  , lastStatus(0)
74  , pendingEncrypt(false)
79  , proxyCredentialsSent(false)
80 #ifndef QT_NO_OPENSSL
81  , ignoreAllSslErrors(false)
82 #endif
84  , connection(0)
85 {
86  // Inlining this function in the header leads to compiler error on
87  // release-armv5, on at least timebox 9.2 and 10.1.
88 }
89 
91 {
92 #ifndef QT_NO_OPENSSL
93  if (connection->d_func()->encrypt)
94  socket = new QSslSocket;
95  else
96  socket = new QTcpSocket;
97 #else
98  socket = new QTcpSocket;
99 #endif
100 #ifndef QT_NO_BEARERMANAGEMENT
101  //push session down to socket
102  if (networkSession)
103  socket->setProperty("_q_networksession", QVariant::fromValue(networkSession));
104 #endif
105 #ifndef QT_NO_NETWORKPROXY
106  // Set by QNAM anyway, but let's be safe here
108 #endif
109 
110  QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
111  this, SLOT(_q_bytesWritten(qint64)),
114  this, SLOT(_q_connected()),
116  QObject::connect(socket, SIGNAL(readyRead()),
117  this, SLOT(_q_readyRead()),
119 
120  // The disconnected() and error() signals may already come
121  // while calling connectToHost().
122  // In case of a cached hostname or an IP this
123  // will then emit a signal to the user of QNetworkReply
124  // but cannot be caught because the user did not have a chance yet
125  // to connect to QNetworkReply's signals.
126  qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
127  QObject::connect(socket, SIGNAL(disconnected()),
128  this, SLOT(_q_disconnected()),
133 
134 
135 #ifndef QT_NO_NETWORKPROXY
136  QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
139 #endif
140 
141 #ifndef QT_NO_OPENSSL
142  QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
143  if (sslSocket) {
144  // won't be a sslSocket if encrypt is false
145  QObject::connect(sslSocket, SIGNAL(encrypted()),
146  this, SLOT(_q_encrypted()),
148  QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
151  QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
154  }
155 #endif
156 }
157 
158 
160 {
163  else
165 
166  socket->close();
167 }
168 
169 
171 {
172  if (!reply) {
173  // heh, how should that happen!
174  qWarning() << "QHttpNetworkConnectionChannel::sendRequest() called without QHttpNetworkReply";
176  return false;
177  }
178 
179  switch (state) {
180  case QHttpNetworkConnectionChannel::IdleState: { // write the header
181  if (!ensureConnection()) {
182  // wait for the connection (and encryption) to be done
183  // sendRequest will be called again from either
184  // _q_connected or _q_encrypted
185  return false;
186  }
187  written = 0; // excluding the header
188  bytesTotal = 0;
189 
190  QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
191  replyPrivate->clear();
192  replyPrivate->connection = connection;
193  replyPrivate->connectionChannel = this;
194  replyPrivate->autoDecompress = request.d->autoDecompress;
195  replyPrivate->pipeliningUsed = false;
196 
197  // if the url contains authentication parameters, use the new ones
198  // both channels will use the new authentication parameters
200  QUrl url = request.url();
202  if (url.userName() != auth.user()
203  || (!url.password().isEmpty() && url.password() != auth.password())) {
204  auth.setUser(url.userName());
205  auth.setPassword(url.password());
206  connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
207  }
208  // clear the userinfo, since we use the same request for resending
209  // userinfo in url can conflict with the one in the authenticator
210  url.setUserInfo(QString());
211  request.setUrl(url);
212  }
213  // Will only be false if QtWebKit is performing a cross-origin XMLHttpRequest
214  // and withCredentials has not been set to true.
215  if (request.withCredentials())
216  connection->d_func()->createAuthorization(socket, request);
217 #ifndef QT_NO_NETWORKPROXY
219  (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
220 #else
222 #endif
223  socket->write(header);
224  // flushing is dangerous (QSslSocket calls transmit which might read or error)
225 // socket->flush();
226  QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
227  if (uploadByteDevice) {
228  // connect the signals so this function gets called again
229  QObject::connect(uploadByteDevice, SIGNAL(readyRead()),this, SLOT(_q_uploadDataReadyRead()));
230 
232 
233  state = QHttpNetworkConnectionChannel::WritingState; // start writing data
234  sendRequest(); //recurse
235  } else {
236  state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
237  sendRequest(); //recurse
238  }
239 
240  break;
241  }
243  {
244  // write the data
245  QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
246  if (!uploadByteDevice || bytesTotal == written) {
247  if (uploadByteDevice)
249  state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
250  sendRequest(); // recurse
251  break;
252  }
253 
254  // only feed the QTcpSocket buffer when there is less than 32 kB in it
255  const qint64 socketBufferFill = 32*1024;
256  const qint64 socketWriteMaxSize = 16*1024;
257 
258 
259 #ifndef QT_NO_OPENSSL
260  QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
261  // if it is really an ssl socket, check more than just bytesToWrite()
262  while ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0))
263  <= socketBufferFill && bytesTotal != written)
264 #else
265  while (socket->bytesToWrite() <= socketBufferFill
266  && bytesTotal != written)
267 #endif
268  {
269  // get pointer to upload data
270  qint64 currentReadSize = 0;
271  qint64 desiredReadSize = qMin(socketWriteMaxSize, bytesTotal - written);
272  const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
273 
274  if (currentReadSize == -1) {
275  // premature eof happened
276  connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
277  return false;
278  break;
279  } else if (readPointer == 0 || currentReadSize == 0) {
280  // nothing to read currently, break the loop
281  break;
282  } else {
283  qint64 currentWriteSize = socket->write(readPointer, currentReadSize);
284  if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
285  // socket broke down
286  connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
287  return false;
288  } else {
289  written += currentWriteSize;
290  uploadByteDevice->advanceReadPointer(currentWriteSize);
291 
293 
294  if (written == bytesTotal) {
295  // make sure this function is called once again
297  sendRequest();
298  break;
299  }
300  }
301  }
302  }
303  break;
304  }
305 
307  {
308  QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
309  if (uploadByteDevice) {
310  QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(_q_uploadDataReadyRead()));
311  }
312 
313  // HTTP pipelining
314  //connection->d_func()->fillPipeline(socket);
315  //socket->flush();
316 
317  // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
318  // this is needed if the sends an reply before we have finished sending the request. In that
319  // case receiveReply had been called before but ignored the server reply
320  if (socket->bytesAvailable())
321  QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
322  break;
323  }
325  // ignore _q_bytesWritten in these states
326  // fall through
327  default:
328  break;
329  }
330  return true;
331 }
332 
333 
335 {
336  Q_ASSERT(socket);
337 
338  if (!reply) {
339  if (socket->bytesAvailable() > 0)
340  qWarning() << "QHttpNetworkConnectionChannel::_q_receiveReply() called without QHttpNetworkReply,"
341  << socket->bytesAvailable() << "bytes on socket.";
342 
343  close();
344  return;
345  }
346 
347  // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
348  // this function is called from _q_disconnected which is called because
349  // of ~QHttpNetworkConnectionPrivate
350  if (!qobject_cast<QHttpNetworkConnection*>(connection)) {
351  return;
352  }
353 
354  QAbstractSocket::SocketState socketState = socket->state();
355 
356  // connection might be closed to signal the end of data
357  if (socketState == QAbstractSocket::UnconnectedState) {
358  if (socket->bytesAvailable() <= 0) {
359  if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
360  // finish this reply. this case happens when the server did not send a content length
362  allDone();
363  return;
364  } else {
366  return;
367  }
368  } else {
369  // socket not connected but still bytes for reading.. just continue in this function
370  }
371  }
372 
373  // read loop for the response
374  qint64 bytes = 0;
375  qint64 lastBytes = bytes;
376  do {
377  lastBytes = bytes;
378 
380  switch (state) {
382  state = reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
383  // fallthrough
384  }
386  qint64 statusBytes = reply->d_func()->readStatus(socket);
387  if (statusBytes == -1) {
388  // connection broke while reading status. also handled if later _q_disconnected is called
390  return;
391  }
392  bytes += statusBytes;
393  lastStatus = reply->d_func()->statusCode;
394  break;
395  }
397  QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
398  qint64 headerBytes = replyPrivate->readHeader(socket);
399  if (headerBytes == -1) {
400  // connection broke while reading headers. also handled if later _q_disconnected is called
402  return;
403  }
404  bytes += headerBytes;
405  // If headers were parsed successfully now it is the ReadingDataState
406  if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
407  if (replyPrivate->isGzipped() && replyPrivate->autoDecompress) {
408  // remove the Content-Length from header
409  replyPrivate->removeAutoDecompressHeader();
410  } else {
411  replyPrivate->autoDecompress = false;
412  }
413  if (replyPrivate->statusCode == 100) {
414  replyPrivate->clearHttpLayerInformation();
416  break; // ignore
417  }
418  if (replyPrivate->shouldEmitSignals())
420  // After headerChanged had been emitted
421  // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
422  // this is handled in the ReadingDataState however
423 
424  if (!replyPrivate->expectContent()) {
426  allDone();
427  break;
428  }
429  }
430  break;
431  }
433  QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
435  replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
436  // (only do the following when still connected, not when we have already been disconnected and there is still data)
437  // We already have some HTTP body data. We don't read more from the socket until
438  // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
439  // we could not limit our read buffer usage.
440  // We only do this when shouldEmitSignals==true because our HTTP parsing
441  // always needs to parse the 401/407 replies. Therefore they don't really obey
442  // to the read buffer maximum size, but we don't care since they should be small.
443  return;
444  }
445 
446  if (replyPrivate->userProvidedDownloadBuffer) {
447  // the user provided a direct buffer where we should put all our data in.
448  // this only works when we can tell the user the content length and he/she can allocate
449  // the buffer in that size.
450  // note that this call will read only from the still buffered data
451  qint64 haveRead = replyPrivate->readBodyVeryFast(socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
452  bytes += haveRead;
453  replyPrivate->totalProgress += haveRead;
454 
455  // the user will get notified of it via progress signal
456  if (haveRead > 0)
457  emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
458  } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
459  && replyPrivate->bodyLength > 0) {
460  // bulk files like images should fulfill these properties and
461  // we can therefore save on memory copying
462  qint64 haveRead = replyPrivate->readBodyFast(socket, &replyPrivate->responseData);
463  bytes += haveRead;
464  replyPrivate->totalProgress += haveRead;
465  if (replyPrivate->shouldEmitSignals()) {
466  emit reply->readyRead();
467  emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
468  }
469  }
470  else
471  {
472  // use the traditional slower reading (for compressed encoding, chunked encoding,
473  // no content-length etc)
474  QByteDataBuffer byteDatas;
475  qint64 haveRead = replyPrivate->readBody(socket, &byteDatas);
476  if (haveRead) {
477  bytes += haveRead;
478  if (replyPrivate->autoDecompress)
479  replyPrivate->appendCompressedReplyData(byteDatas);
480  else
481  replyPrivate->appendUncompressedReplyData(byteDatas);
482 
483  if (!replyPrivate->autoDecompress) {
484  replyPrivate->totalProgress += bytes;
485  if (replyPrivate->shouldEmitSignals()) {
486  // important: At the point of this readyRead(), the byteDatas list must be empty,
487  // else implicit sharing will trigger memcpy when the user is reading data!
488  emit reply->readyRead();
489  emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
490  }
491  }
492 #ifndef QT_NO_COMPRESS
493  else if (!expand(false)) { // expand a chunk if possible
494  // If expand() failed we can just return, it had already called connection->emitReplyError()
495  return;
496  }
497 #endif
498  }
499  }
500  // still in ReadingDataState? This function will be called again by the socket's readyRead
502  break;
503 
504  // everything done, fall through
505  }
507  allDone();
508  break;
509  default:
510  break;
511  }
512  } while (bytes != lastBytes && reply);
513 }
514 
515 // called when unexpectedly reading a -1 or when data is expected but socket is closed
517 {
518  Q_ASSERT(reply);
519  if (reconnectAttempts <= 0) {
520  // too many errors reading/receiving/parsing the status, close the socket and emit error
522  close();
523  reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket);
526  } else {
528  reply->d_func()->clear();
529  reply->d_func()->connection = connection;
530  reply->d_func()->connectionChannel = this;
532  }
533 }
534 
536 {
537  QAbstractSocket::SocketState socketState = socket->state();
538 
539  // resend this request after we receive the disconnected signal
540  if (socketState == QAbstractSocket::ClosingState) {
541  if (reply)
542  resendCurrent = true;
543  return false;
544  }
545 
546  // already trying to connect?
547  if (socketState == QAbstractSocket::HostLookupState ||
548  socketState == QAbstractSocket::ConnectingState) {
549  return false;
550  }
551 
552  // make sure that this socket is in a connected state, if not initiate
553  // connection to the host.
554  if (socketState != QAbstractSocket::ConnectedState) {
555  // connect to the host if not already connected.
558 
559  // reset state
562  proxyCredentialsSent = false;
565  priv->hasFailed = false;
568  priv->hasFailed = false;
569 
570  // This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done"
571  // is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the
572  // last header for Authorization is generated by the QAuthenticator. Basic & Digest logic does not
573  // check the "phase" for generating the Authorization header. NTLM authentication is a two stage
574  // process & needs the "phase". To make sure the QAuthenticator uses the current username/password
575  // the phase is reset to Start.
577  if (priv && priv->phase == QAuthenticatorPrivate::Done)
580  if (priv && priv->phase == QAuthenticatorPrivate::Done)
582 
583  QString connectHost = connection->d_func()->hostName;
584  qint16 connectPort = connection->d_func()->port;
585 
586 #ifndef QT_NO_NETWORKPROXY
587  // HTTPS always use transparent proxy.
588  if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) {
589  connectHost = connection->d_func()->networkProxy.hostName();
590  connectPort = connection->d_func()->networkProxy.port();
591  }
593  // Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
594  QByteArray value;
595  // ensureConnection is called before any request has been assigned, but can also be called again if reconnecting
596  if (request.url().isEmpty())
597  value = connection->d_func()->predictNextRequest().headerField("user-agent");
598  else
599  value = request.headerField("user-agent");
600  if (!value.isEmpty())
601  socket->setProperty("_q_user-agent", value);
602  }
603 #endif
604  if (ssl) {
605 #ifndef QT_NO_OPENSSL
606  QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
607  sslSocket->connectToHostEncrypted(connectHost, connectPort);
608  if (ignoreAllSslErrors)
609  sslSocket->ignoreSslErrors();
611 
612  // limit the socket read buffer size. we will read everything into
613  // the QHttpNetworkReply anyway, so let's grow only that and not
614  // here and there.
615  socket->setReadBufferSize(64*1024);
616 #else
617  connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
618 #endif
619  } else {
620  // In case of no proxy we can use the Unbuffered QTcpSocket
621 #ifndef QT_NO_NETWORKPROXY
622  if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
625 #endif
626  socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered);
627  // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
628  socket->setReadBufferSize(1*1024);
629 #ifndef QT_NO_NETWORKPROXY
630  } else {
631  socket->connectToHost(connectHost, connectPort);
632 
633  // limit the socket read buffer size. we will read everything into
634  // the QHttpNetworkReply anyway, so let's grow only that and not
635  // here and there.
636  socket->setReadBufferSize(64*1024);
637  }
638 #endif
639  }
640  return false;
641  }
642  return true;
643 }
644 
645 
646 #ifndef QT_NO_COMPRESS
648 {
649  Q_ASSERT(socket);
650  Q_ASSERT(reply);
651 
652  qint64 total = reply->d_func()->compressedData.size();
653  if (total >= CHUNK || dataComplete) {
654  // uncompress the data
655  QByteArray content, inflated;
656  content = reply->d_func()->compressedData;
657  reply->d_func()->compressedData.clear();
658 
659  int ret = Z_OK;
660  if (content.size())
661  ret = reply->d_func()->gunzipBodyPartially(content, inflated);
662  if (ret >= Z_OK) {
663  if (dataComplete && ret == Z_OK && !reply->d_func()->streamEnd) {
664  reply->d_func()->gunzipBodyPartiallyEnd();
665  reply->d_func()->streamEnd = true;
666  }
667  if (inflated.size()) {
668  reply->d_func()->totalProgress += inflated.size();
669  reply->d_func()->appendUncompressedReplyData(inflated);
670  if (reply->d_func()->shouldEmitSignals()) {
671  // important: At the point of this readyRead(), inflated must be cleared,
672  // else implicit sharing will trigger memcpy when the user is reading data!
673  emit reply->readyRead();
674  emit reply->dataReadProgress(reply->d_func()->totalProgress, 0);
675  }
676  }
677  } else {
678  connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);
679  return false;
680  }
681  }
682  return true;
683 }
684 #endif
685 
686 
688 {
689  Q_ASSERT(reply);
690 #ifndef QT_NO_COMPRESS
691  // expand the whole data.
692  if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) {
693  bool expandResult = expand(true);
694  // If expand() failed we can just return, it had already called connection->emitReplyError()
695  if (!expandResult)
696  return;
697  }
698 #endif
699 
700  if (!reply) {
701  qWarning() << "QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt-project.org/";
702  return;
703  }
704 
705  // while handling 401 & 407, we might reset the status code, so save this.
706  bool emitFinished = reply->d_func()->shouldEmitSignals();
707  bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled();
709 
710  handleStatus();
711  // handleStatus() might have removed the reply because it already called connection->emitReplyError()
712 
713  // queue the finished signal, this is required since we might send new requests from
714  // slot connected to it. The socket will not fire readyRead signal, if we are already
715  // in the slot connected to readyRead
716  if (reply && emitFinished)
718 
719 
720  // reset the reconnection attempts after we receive a complete reply.
721  // in case of failures, each channel will attempt two reconnects before emitting error.
722  reconnectAttempts = 2;
723 
724  // now the channel can be seen as free/idle again, all signal emissions for the reply have been done
727 
728  // if it does not need to be sent again we can set it to 0
729  // the previous code did not do that and we had problems with accidental re-sending of a
730  // finished request.
731  // Note that this may trigger a segfault at some other point. But then we can fix the underlying
732  // problem.
733  if (!resendCurrent) {
735  reply = 0;
736  }
737 
738  // move next from pipeline to current request
739  if (!alreadyPipelinedRequests.isEmpty()) {
740  if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
741  // move the pipelined ones back to the main queue
743  close();
744  } else {
745  // there were requests pipelined in and we can continue
746  HttpMessagePair messagePair = alreadyPipelinedRequests.takeFirst();
747 
748  request = messagePair.first;
749  reply = messagePair.second;
751  resendCurrent = false;
752 
753  written = 0; // message body, excluding the header, irrelevant here
754  bytesTotal = 0; // message body total, excluding the header, irrelevant here
755 
756  // pipeline even more
757  connection->d_func()->fillPipeline(socket);
758 
759  // continue reading
760  //_q_receiveReply();
761  // this was wrong, allDone gets called from that function anyway.
762  }
763  } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) {
764  // this is weird. we had nothing pipelined but still bytes available. better close it.
765  close();
766 
768  } else if (alreadyPipelinedRequests.isEmpty()) {
769  if (connectionCloseEnabled)
771  close();
772  if (qobject_cast<QHttpNetworkConnection*>(connection))
774  }
775 }
776 
778 {
779  Q_ASSERT(reply);
780  // detect HTTP Pipelining support
781  QByteArray serverHeaderField;
782  if (
783  // check for HTTP/1.1
784  (reply->d_func()->majorVersion == 1 && reply->d_func()->minorVersion == 1)
785  // check for not having connection close
786  && (!reply->d_func()->isConnectionCloseEnabled())
787  // check if it is still connected
789  // check for broken servers in server reply header
790  // this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
791  && (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
792  && (!serverHeaderField.contains("Microsoft-IIS/5."))
793  && (!serverHeaderField.contains("Netscape-Enterprise/3."))
794  // this is adpoted from the knowledge of the Nokia 7.x browser team (DEF143319)
795  && (!serverHeaderField.contains("WebLogic"))
796  && (!serverHeaderField.startsWith("Rocket")) // a Python Web Server, see Web2py.com
797  ) {
799  } else {
801  }
802 }
803 
804 // called when the connection broke and we need to queue some pipelined requests again
806 {
807  for (int i = 0; i < alreadyPipelinedRequests.length(); i++)
808  connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i));
809  alreadyPipelinedRequests.clear();
810 
811  // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
812  // this function is called from _q_disconnected which is called because
813  // of ~QHttpNetworkConnectionPrivate
814  if (qobject_cast<QHttpNetworkConnection*>(connection))
816 }
817 
819 {
820  Q_ASSERT(socket);
821  Q_ASSERT(reply);
822 
823  int statusCode = reply->statusCode();
824  bool resend = false;
825 
826  switch (statusCode) {
827  case 401: // auth required
828  case 407: // proxy auth required
829  if (connection->d_func()->handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend)) {
830  if (resend) {
831  if (!resetUploadData())
832  break;
833 
834  reply->d_func()->eraseData();
835 
836  if (alreadyPipelinedRequests.isEmpty()) {
837  // this does a re-send without closing the connection
838  resendCurrent = true;
840  } else {
841  // we had requests pipelined.. better close the connection in closeAndResendCurrentRequest
844  }
845  } else {
846  //authentication cancelled, close the channel.
847  close();
848  }
849  } else {
851  emit reply->readyRead();
852  QNetworkReply::NetworkError errorCode = (statusCode == 407)
855  reply->d_func()->errorString = connection->d_func()->errorDetail(errorCode, socket);
856  emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
857  }
858  break;
859  default:
860  if (qobject_cast<QHttpNetworkConnection*>(connection))
862  }
863 }
864 
866 {
867  if (!reply) {
868  //this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending
869  return false;
870  }
871  QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
872  if (!uploadByteDevice)
873  return true;
874 
875  if (uploadByteDevice->reset()) {
876  written = 0;
877  return true;
878  } else {
879  connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError);
880  return false;
881  }
882 }
883 
884 
886 {
887  // this is only called for simple GET
888 
891  reply->d_func()->clear();
892  reply->d_func()->connection = connection;
893  reply->d_func()->connectionChannel = this;
894  reply->d_func()->autoDecompress = request.d->autoDecompress;
895  reply->d_func()->pipeliningUsed = true;
896 
897 #ifndef QT_NO_NETWORKPROXY
899  (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy)));
900 #else
902 #endif
903 
904  alreadyPipelinedRequests.append(pair);
905 
906  // pipelineFlush() needs to be called at some point afterwards
907 }
908 
910 {
911  if (pipeline.isEmpty())
912  return;
913 
914  // The goal of this is so that we have everything in one TCP packet.
915  // For the Unbuffered QTcpSocket this is manually needed, the buffered
916  // QTcpSocket does it automatically.
917  // Also, sometimes the OS does it for us (Nagle's algorithm) but that
918  // happens only sometimes.
920  pipeline.clear();
921 }
922 
923 
925 {
927  close();
928  if (reply)
929  resendCurrent = true;
930  if (qobject_cast<QHttpNetworkConnection*>(connection))
932 }
933 
935 {
937 }
938 
940 {
942 }
943 
945 {
947 }
948 
950 {
952 }
953 
954 //private slots
956 {
958  // We got a readyRead but no bytes are available..
959  // This happens for the Unbuffered QTcpSocket
960  // Also check if socket is in ConnectedState since
961  // this function may also be invoked via the event loop.
962  char c;
963  qint64 ret = socket->peek(&c, 1);
964  if (ret < 0) {
965  _q_error(socket->error());
966  // We still need to handle the reply so it emits its signals etc.
967  if (reply)
968  _q_receiveReply();
969  return;
970  }
971  }
972 
973  if (isSocketWaiting() || isSocketReading()) {
975  if (reply)
976  _q_receiveReply();
977  }
978 }
979 
981 {
982  Q_UNUSED(bytes);
983  // bytes have been written to the socket. write even more of them :)
984  if (isSocketWriting())
985  sendRequest();
986  // otherwise we do nothing
987 }
988 
990 {
994  return;
995  }
996 
997  // read the available data before closing
998  if (isSocketWaiting() || isSocketReading()) {
999  if (reply) {
1001  _q_receiveReply();
1002  }
1004  // re-sending request because the socket was in ClosingState
1006  }
1008 
1010  close();
1011 }
1012 
1013 
1015 {
1016  // improve performance since we get the request sent by the kernel ASAP
1017  //socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
1018  // We have this commented out now. It did not have the effect we wanted. If we want to
1019  // do this properly, Qt has to combine multiple HTTP requests into one buffer
1020  // and send this to the kernel in one syscall and then the kernel immediately sends
1021  // it as one TCP packet because of TCP_NODELAY.
1022  // However, this code is currently not in Qt, so we rely on the kernel combining
1023  // the requests into one TCP packet.
1024 
1025  // not sure yet if it helps, but it makes sense
1027 
1029 
1030  // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
1031  //channels[i].reconnectAttempts = 2;
1032  if (!pendingEncrypt) {
1034  if (!reply)
1035  connection->d_func()->dequeueRequest(socket);
1036  if (reply)
1037  sendRequest();
1038  }
1039 }
1040 
1041 
1043 {
1044  if (!socket)
1045  return;
1047 
1048  switch (socketError) {
1051  break;
1054  break;
1056  // try to reconnect/resend before sending an error.
1057  // while "Reading" the _q_disconnected() will handle this.
1059  if (reconnectAttempts-- > 0) {
1061  return;
1062  } else {
1064  }
1066  if (!reply)
1067  break;
1068 
1069  if (!reply->d_func()->expectContent()) {
1070  // No content expected, this is a valid way to have the connection closed by the server
1071  return;
1072  }
1073  if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
1074  // There was no content-length header and it's not chunked encoding,
1075  // so this is a valid way to have the connection closed by the server
1076  return;
1077  }
1078  // ok, we got a disconnect even though we did not expect it
1079  // Try to read everything from the socket before we emit the error.
1080  if (socket->bytesAvailable()) {
1081  // Read everything from the socket into the reply buffer.
1082  // we can ignore the readbuffersize as the data is already
1083  // in memory and we will not recieve more data on the socket.
1085  _q_receiveReply();
1086 #ifndef QT_NO_OPENSSL
1087  if (ssl) {
1088  // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
1089  // So we need to check this if the socket is a QSslSocket. When the socket is flushed
1090  // it will force a decrypt of the encrypted data in the plainsocket.
1091  QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
1092  qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
1093  while (sslSocket->encryptedBytesAvailable()) {
1094  sslSocket->flush();
1095  _q_receiveReply();
1096  qint64 afterFlush = sslSocket->encryptedBytesAvailable();
1097  if (afterFlush == beforeFlush)
1098  break;
1099  beforeFlush = afterFlush;
1100  }
1101  }
1102 #endif
1103  }
1104 
1106  } else {
1108  }
1109  break;
1111  // try to reconnect/resend before sending an error.
1114  return;
1115  }
1116  errorCode = QNetworkReply::TimeoutError;
1117  break;
1120  break;
1123  break;
1124  default:
1125  // all other errors are treated as NetworkError
1127  break;
1128  }
1130  QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
1131 
1132  // Need to dequeu the request so that we can emit the error.
1133  if (!reply)
1134  connection->d_func()->dequeueRequest(socket);
1135  if (reply) {
1136  reply->d_func()->errorString = errorString;
1137  emit reply->finishedWithError(errorCode, errorString);
1138  reply = 0;
1139  }
1140  // send the next request
1141  QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
1142 
1143  if (that) //signal emission triggered event loop
1144  close();
1145 }
1146 
1147 #ifndef QT_NO_NETWORKPROXY
1149 {
1150  // Need to dequeue the request before we can emit the error.
1151  if (!reply)
1152  connection->d_func()->dequeueRequest(socket);
1153  if (reply)
1154  connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
1155 }
1156 #endif
1157 
1159 {
1160  sendRequest();
1161 }
1162 
1163 #ifndef QT_NO_OPENSSL
1165 {
1166  if (!socket)
1167  return; // ### error
1169  pendingEncrypt = false;
1170  if (!reply)
1171  connection->d_func()->dequeueRequest(socket);
1172  if (reply)
1173  sendRequest();
1174 }
1175 
1177 {
1178  if (!socket)
1179  return;
1180  //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
1181  // Also pause the connection because socket notifiers may fire while an user
1182  // dialog is displaying
1183  connection->d_func()->pauseConnection();
1184  if (pendingEncrypt && !reply)
1185  connection->d_func()->dequeueRequest(socket);
1186  if (reply)
1187  emit reply->sslErrors(errors);
1188  connection->d_func()->resumeConnection();
1189 }
1190 
1192 {
1193  Q_UNUSED(bytes);
1194  // bytes have been written to the socket. write even more of them :)
1195  if (isSocketWriting())
1196  sendRequest();
1197  // otherwise we do nothing
1198 }
1199 
1200 #endif
1201 
1203 {
1204  // Inlining this function in the header leads to compiler error on
1205  // release-armv5, on at least timebox 9.2 and 10.1.
1206  connection = c;
1207 }
1208 
1210 
1211 #include "moc_qhttpnetworkconnectionchannel_p.cpp"
1212 
1213 #endif // QT_NO_HTTP
QNetworkProxy::ProxyType type() const
Returns the proxy type for this instance.
QSharedDataPointer< QHttpNetworkRequestPrivate > d
void setUserInfo(const QString &userInfo)
Sets the user info of the URL to userInfo.
Definition: qurl.cpp:4615
virtual bool reset()=0
Moves the internal read pointer back to the beginning.
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
qint64 bytesAvailable() const
Returns the number of incoming bytes that are waiting to be read.
QAuthenticatorPrivate::Method authMethod
QByteArray & append(char c)
Appends the character ch to this byte array.
qint64 readHeader(QAbstractSocket *socket)
qint64 encryptedBytesToWrite() const
Returns the number of encrypted bytes that are waiting to be written to the network.
Definition: qsslsocket.cpp:783
#define error(msg)
QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue=QByteArray()) const
QNetworkProxy transparentProxy() const
void connectToHost(const QString &hostName, quint16 port, OpenMode mode=ReadWrite)
Attempts to make a connection to hostName on the given port.
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void _q_sslErrors(const QList< QSslError > &errors)
QNetworkProxy proxy() const
Returns the network proxy for this socket.
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition: qurl.cpp:4317
#define SLOT(a)
Definition: qobjectdefs.h:226
QString errorString() const
Returns a human-readable description of the last device error that occurred.
Definition: qiodevice.cpp:1671
T1 first
Definition: qpair.h:65
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
Definition: qsslsocket.h:67
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object&#39;s name property to value.
Definition: qobject.cpp:3755
T2 second
Definition: qpair.h:66
NetworkError
Indicates all possible error conditions found during the processing of the request.
Definition: qnetworkreply.h:70
#define CHUNK
QNetworkProxy cacheProxy() const
void dataSendProgress(qint64 done, qint64 total)
QString errorString() const
void ignoreSslErrors(const QList< QSslError > &errors)
This method tells QSslSocket to ignore only the errors given in errors.
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
T * qobject_cast(QObject *object)
Definition: qobject.h:375
void setUser(const QString &user)
Sets the user used for authentication.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
bool startsWith(const QByteArray &a) const
Returns true if this byte array starts with byte array ba; otherwise returns false.
qint64 encryptedBytesAvailable() const
Returns the number of encrypted bytes that are awaiting decryption.
Definition: qsslsocket.cpp:766
void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
Sets the given option to the value described by value.
virtual const char * readPointer(qint64 maximumLength, qint64 &len)=0
Return a byte pointer for at most maximumLength bytes of that device.
static QAuthenticatorPrivate * getPrivate(QAuthenticator &auth)
void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail=QString())
void _q_error(QAbstractSocket::SocketError)
Q_GUI_EXPORT QString errorString(EGLint code=eglGetError())
Definition: qegl.cpp:743
SocketState
This enum describes the different states in which a socket can be.
QNonContiguousByteDevice * uploadByteDevice() const
#define SIGNAL(a)
Definition: qobjectdefs.h:227
The QNetworkProxy class provides a network layer proxy.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static QIntfbScreen * connected
QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue=QByteArray()) const
QSharedPointer< QNetworkSession > networkSession
void setUrl(const QUrl &url)
QPointer< QHttpNetworkConnection > connection
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define emit
Definition: qobjectdefs.h:76
SocketError
This enum describes the socket errors that can occur.
void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode=ReadWrite)
Starts an encrypted connection to the device hostName on port, using mode as the OpenMode ...
Definition: qsslsocket.cpp:414
short qint16
Definition: qglobal.h:935
qint64 peek(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, without side effects (i.
Definition: qiodevice.cpp:1563
void sslErrors(const QList< QSslError > &errors)
QString userInfo() const
Returns the user info of the URL, or an empty string if the user info is undefined.
Definition: qurl.cpp:4631
Q_CORE_EXPORT void qWarning(const char *,...)
The QTcpSocket class provides a TCP socket.
Definition: qtcpsocket.h:56
void setReadBufferSize(qint64 size)
Sets the size of QAbstractSocket&#39;s internal read buffer to be size bytes.
__int64 qint64
Definition: qglobal.h:942
bool isEmpty() const
Definition: qbytedata_p.h:192
void setReadBufferSize(qint64 size)
static QVariant fromValue(const T &value)
Returns a QVariant containing a copy of value.
Definition: qvariant.h:336
void appendUncompressedReplyData(QByteArray &qba)
void close()
Closes the I/O device for the socket, disconnects the socket&#39;s connection with the host...
The QAuthenticator class provides an authentication object.
#define None
QHttpNetworkConnection * connection()
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
QString userName() const
Returns the user name of the URL if it is defined; otherwise an empty string is returned.
Definition: qurl.cpp:4667
enum QHttpNetworkReplyPrivate::ReplyState state
void setProxy(const QNetworkProxy &networkProxy)
Sets the explicit network proxy for this socket to networkProxy.
qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out)
QPointer< QHttpNetworkConnectionChannel > connectionChannel
bool flush()
This function writes as much as possible from the internal write buffer to the underlying network soc...
Definition: qsslsocket.cpp:856
static QByteArray header(const QHttpNetworkRequest &request, bool throughProxy)
virtual bool advanceReadPointer(qint64 amount)=0
The old readPointer is invalid after this call.
QString user() const
returns the user used for authentication.
qint64 contentLength() const
static const QMetaObjectPrivate * priv(const uint *data)
qint64 bytesToWrite() const
Returns the number of bytes that are waiting to be written.
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
A QNonContiguousByteDevice is a representation of a file, array or buffer that allows access with a r...
QPointer< QHttpNetworkConnection > connection
void setPassword(const QString &password)
Sets the password used for authentication.
qint64 readBodyVeryFast(QAbstractSocket *socket, char *b)
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
QString password() const
returns the password used for authentication.
SocketError error() const
Returns the type of error that last occurred.
void dataReadProgress(int done, int total)
#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
QString password() const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition: qurl.cpp:4754
qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
void setConnection(QHttpNetworkConnection *c)
void clear()
Clears the contents of the byte array and makes it empty.
void appendCompressedReplyData(QByteDataBuffer &data)
SocketState state() const
Returns the state of the socket.
QBool contains(char c) const
Returns true if the byte array contains the character ch; otherwise returns false.
Definition: qbytearray.h:525
QAuthenticatorPrivate::Method proxyAuthMethod