Changeset 561 for trunk/src/network/access
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 44 edited
- 13 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/network/access/access.pri
r2 r561 3 3 HEADERS += access/qftp.h \ 4 4 access/qhttp.h \ 5 access/qhttpnetworkheader_p.h \ 6 access/qhttpnetworkrequest_p.h \ 7 access/qhttpnetworkreply_p.h \ 5 8 access/qhttpnetworkconnection_p.h \ 9 access/qhttpnetworkconnectionchannel_p.h \ 10 access/qfilenetworkreply_p.h \ 6 11 access/qnetworkaccessmanager.h \ 7 12 access/qnetworkaccessmanager_p.h \ … … 16 21 access/qnetworkcookie.h \ 17 22 access/qnetworkcookie_p.h \ 23 access/qnetworkcookiejar.h \ 24 access/qnetworkcookiejar_p.h \ 18 25 access/qnetworkrequest.h \ 19 26 access/qnetworkrequest_p.h \ … … 28 35 SOURCES += access/qftp.cpp \ 29 36 access/qhttp.cpp \ 37 access/qhttpnetworkheader.cpp \ 38 access/qhttpnetworkrequest.cpp \ 39 access/qhttpnetworkreply.cpp \ 30 40 access/qhttpnetworkconnection.cpp \ 41 access/qhttpnetworkconnectionchannel.cpp \ 42 access/qfilenetworkreply.cpp \ 31 43 access/qnetworkaccessmanager.cpp \ 32 44 access/qnetworkaccesscache.cpp \ … … 39 51 access/qnetworkaccesshttpbackend.cpp \ 40 52 access/qnetworkcookie.cpp \ 53 access/qnetworkcookiejar.cpp \ 41 54 access/qnetworkrequest.cpp \ 42 55 access/qnetworkreply.cpp \ … … 49 62 INCLUDEPATH += ../3rdparty/zlib 50 63 } else:!contains(QT_CONFIG, no-zlib) { 51 unix:LIBS += -lz64 unix:LIBS_PRIVATE += -lz 52 65 # win32:LIBS += libz.lib 53 66 } -
trunk/src/network/access/qabstractnetworkcache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 284 284 285 285 /*! 286 \since 4.6 287 286 288 Returns all the attributes stored with this cache item. 287 289 … … 294 296 295 297 /*! 298 \since 4.6 299 296 300 Sets all attributes of this cache item to be the map \a attributes. 297 301 -
trunk/src/network/access/qabstractnetworkcache.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qabstractnetworkcache_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qftp.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 315 315 bytesFromSocket.clear(); 316 316 317 if (socket) 317 if (socket) { 318 318 delete socket; 319 socket = 0; 320 } 319 321 socket = new QTcpSocket(this); 320 322 socket->setObjectName(QLatin1String("QFtpDTP Passive state socket")); … … 870 872 // qDebug("QFtpPI state: %d [connected()]", state); 871 873 #endif 874 // try to improve performance by setting TCP_NODELAY 875 commandSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1); 876 872 877 emit connectState(QFtp::Connected); 873 878 } … … 1292 1297 \brief The QFtp class provides an implementation of the client side of FTP protocol. 1293 1298 1294 \ingroup io1299 \ingroup network 1295 1300 \inmodule QtNetwork 1296 \mainclass 1301 1297 1302 1298 1303 This class provides a direct interface to FTP that allows you to … … 1341 1346 their results. 1342 1347 1343 Example: If you want to download the INSTALL file from Trolltech's1348 Example: If you want to download the INSTALL file from the Qt 1344 1349 FTP server, you would write this: 1345 1350 … … 1386 1391 non-Unix FTP servers. 1387 1392 1388 \sa Q Http, QNetworkAccessManager, QNetworkRequest, QNetworkReply,1393 \sa QNetworkAccessManager, QNetworkRequest, QNetworkReply, 1389 1394 {FTP Example} 1390 1395 */ … … 1659 1664 int QFtp::connectToHost(const QString &host, quint16 port) 1660 1665 { 1661 d_func()->pi.transferConnectionExtended = true;1662 1666 QStringList cmds; 1663 1667 cmds << host; 1664 1668 cmds << QString::number((uint)port); 1665 return d_func()->addCommand(new QFtpCommand(ConnectToHost, cmds)); 1669 int id = d_func()->addCommand(new QFtpCommand(ConnectToHost, cmds)); 1670 d_func()->pi.transferConnectionExtended = true; 1671 return id; 1666 1672 } 1667 1673 … … 1722 1728 int QFtp::setTransferMode(TransferMode mode) 1723 1729 { 1730 int id = d_func()->addCommand(new QFtpCommand(SetTransferMode, QStringList())); 1724 1731 d_func()->pi.transferConnectionExtended = true; 1725 1732 d_func()->transferMode = mode; 1726 return d_func()->addCommand(new QFtpCommand(SetTransferMode, QStringList()));1733 return id; 1727 1734 } 1728 1735 … … 1731 1738 port. Calling this function with \a host empty disables proxying. 1732 1739 1733 QFtp does not support FTP-over-HTTP proxy servers. Use QHttp for1734 this.1740 QFtp does not support FTP-over-HTTP proxy servers. Use 1741 QNetworkAccessManager for this. 1735 1742 */ 1736 1743 int QFtp::setProxy(const QString &host, quint16 port) -
trunk/src/network/access/qftp.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qhttp.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 65 65 #endif 66 66 67 #ifndef QT_NO_HTTP 68 67 69 QT_BEGIN_NAMESPACE 68 69 #ifndef QT_NO_HTTP70 70 71 71 class QHttpNormalRequest; … … 122 122 void _q_slotClosed(); 123 123 void _q_slotBytesWritten(qint64 numBytes); 124 #ifndef QT_NO_OPENSSL 125 void _q_slotEncryptedBytesWritten(qint64 numBytes); 126 #endif 124 127 void _q_slotDoFinished(); 125 128 void _q_slotSendRequest(); … … 135 138 void closeConn(); 136 139 void setSock(QTcpSocket *sock); 140 141 void postMoreData(); 137 142 138 143 QTcpSocket *socket; … … 514 519 /*! 515 520 \class QHttpHeader 521 \obsolete 516 522 \brief The QHttpHeader class contains header information for HTTP. 517 523 518 \ingroup io524 \ingroup network 519 525 \inmodule QtNetwork 520 526 … … 625 631 QHttpHeader::~QHttpHeader() 626 632 { 627 delete d_ptr;628 633 } 629 634 … … 951 956 952 957 /*! 953 Returns true if the header has an entry for the thespecial HTTP958 Returns true if the header has an entry for the special HTTP 954 959 header field \c content-type; otherwise returns false. 955 960 … … 1008 1013 /*! 1009 1014 \class QHttpResponseHeader 1015 \obsolete 1010 1016 \brief The QHttpResponseHeader class contains response header information for HTTP. 1011 1017 1012 \ingroup io1018 \ingroup network 1013 1019 \inmodule QtNetwork 1014 1020 … … 1153 1159 } 1154 1160 1155 /*! \ reimp1161 /*! \internal 1156 1162 */ 1157 1163 bool QHttpResponseHeader::parseLine(const QString &line, int number) … … 1212 1218 /*! 1213 1219 \class QHttpRequestHeader 1220 \obsolete 1214 1221 \brief The QHttpRequestHeader class contains request header information for HTTP. 1215 1222 1216 \ingroup io1223 \ingroup network 1217 1224 \inmodule QtNetwork 1218 1225 … … 1367 1374 } 1368 1375 1369 /*! \ reimp1376 /*! \internal 1370 1377 */ 1371 1378 bool QHttpRequestHeader::parseLine(const QString &line, int number) … … 1414 1421 /*! 1415 1422 \class QHttp 1423 \obsolete 1416 1424 \reentrant 1417 1425 1418 1426 \brief The QHttp class provides an implementation of the HTTP protocol. 1419 1427 1420 \ingroup io1428 \ingroup network 1421 1429 \inmodule QtNetwork 1422 \mainclass 1430 1423 1431 1424 1432 This class provides a direct interface to HTTP that allows you to 1425 have more control over the requests and that allows you to access1426 the response header fields.However, for new applications, it is1433 download and upload data with the HTTP protocol. 1434 However, for new applications, it is 1427 1435 recommended to use QNetworkAccessManager and QNetworkReply, as 1428 those classes possess a simpler, yet more powerful API. 1436 those classes possess a simpler, yet more powerful API 1437 and a more modern protocol implementation. 1429 1438 1430 1439 The class works asynchronously, so there are no blocking … … 1447 1456 1448 1457 To make an HTTP request you must set up suitable HTTP headers. The 1449 following example demonstrates, how to request the main HTML page 1450 from the Trolltech home page (i.e., the URL 1451 \c http://qtsoftware.com/index.html): 1458 following example demonstrates how to request the main HTML page 1459 from the Qt website (i.e., the URL \c http://qt.nokia.com/index.html): 1452 1460 1453 1461 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 2 … … 1593 1601 This enum is used to specify the mode of connection to use: 1594 1602 1595 \value ConnectionModeHttp The connection is a regular H ttpconnection to the server1596 \value ConnectionModeHttps The H ttpsprotocol is used and the connection is encrypted using SSL.1597 1598 When using the H ttpsmode, care should be taken to connect to the sslErrors signal, and1599 handle possible S slerrors.1603 \value ConnectionModeHttp The connection is a regular HTTP connection to the server 1604 \value ConnectionModeHttps The HTTPS protocol is used and the connection is encrypted using SSL. 1605 1606 When using the HTTPS mode, care should be taken to connect to the sslErrors signal, and 1607 handle possible SSL errors. 1600 1608 1601 1609 \sa QSslSocket … … 2035 2043 2036 2044 If port is 0, it will use the default port for the \a mode used 2037 (80 for H ttp and 443 fopr Https).2045 (80 for HTTP and 443 for HTTPS). 2038 2046 2039 2047 The function does not block; instead, it returns immediately. The request … … 2162 2170 2163 2171 \a path must be a absolute path like \c /index.html or an 2164 absolute URI like \c http:// qtsoftware.com/index.html and2172 absolute URI like \c http://example.com/index.html and 2165 2173 must be encoded with either QUrl::toPercentEncoding() or 2166 2174 QUrl::encodedPath(). … … 2201 2209 2202 2210 \a path must be an absolute path like \c /index.html or an 2203 absolute URI like \c http:// qtsoftware.com/index.html and2211 absolute URI like \c http://example.com/index.html and 2204 2212 must be encoded with either QUrl::toPercentEncoding() or 2205 2213 QUrl::encodedPath(). … … 2252 2260 2253 2261 \a path must be an absolute path like \c /index.html or an 2254 absolute URI like \c http:// qtsoftware.com/index.html.2262 absolute URI like \c http://example.com/index.html. 2255 2263 2256 2264 The function does not block; instead, it returns immediately. The request … … 2657 2665 } 2658 2666 2667 #ifndef QT_NO_OPENSSL 2668 void QHttpPrivate::_q_slotEncryptedBytesWritten(qint64 written) 2669 { 2670 Q_UNUSED(written); 2671 postMoreData(); 2672 } 2673 #endif 2674 2659 2675 void QHttpPrivate::_q_slotBytesWritten(qint64 written) 2660 2676 { … … 2662 2678 bytesDone += written; 2663 2679 emit q->dataSendProgress(bytesDone, bytesTotal); 2664 2680 postMoreData(); 2681 } 2682 2683 // Send the POST data 2684 void QHttpPrivate::postMoreData() 2685 { 2665 2686 if (pendingPost) 2666 2687 return; … … 2669 2690 return; 2670 2691 2692 // the following is backported code from Qt 4.6 QNetworkAccessManager. 2693 // We also have to check the encryptedBytesToWrite() if it is an SSL socket. 2694 #ifndef QT_NO_OPENSSL 2695 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); 2696 // if it is really an ssl socket, check more than just bytesToWrite() 2697 if ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0)) == 0) { 2698 #else 2671 2699 if (socket->bytesToWrite() == 0) { 2700 #endif 2672 2701 int max = qMin<qint64>(4096, postDevice->size() - postDevice->pos()); 2673 2702 QByteArray arr; … … 3087 3116 q, SLOT(_q_slotBytesWritten(qint64))); 3088 3117 #ifndef QT_NO_NETWORKPROXY 3089 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator*)),3090 q, SIGNAL(proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator*)));3118 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), 3119 q, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); 3091 3120 #endif 3092 3121 3093 3122 #ifndef QT_NO_OPENSSL 3094 3123 if (qobject_cast<QSslSocket *>(socket)) { 3095 QObject::connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), 3096 q, SIGNAL(sslErrors(const QList<QSslError> &))); 3124 QObject::connect(socket, SIGNAL(sslErrors(QList<QSslError>)), 3125 q, SIGNAL(sslErrors(QList<QSslError>))); 3126 QObject::connect(socket, SIGNAL(encryptedBytesWritten(qint64)), 3127 q, SLOT(_q_slotEncryptedBytesWritten(qint64))); 3097 3128 } 3098 3129 #endif -
trunk/src/network/access/qhttp.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 47 47 #include <QtCore/qmap.h> 48 48 #include <QtCore/qpair.h> 49 #include <QtCore/qscopedpointer.h> 49 50 50 51 QT_BEGIN_HEADER … … 109 110 QHttpHeader(QHttpHeaderPrivate &dd, const QString &str = QString()); 110 111 QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header); 111 Q HttpHeaderPrivate *d_ptr;112 QScopedPointer<QHttpHeaderPrivate> d_ptr; 112 113 113 114 private: … … 290 291 Q_PRIVATE_SLOT(d_func(), void _q_slotClosed()) 291 292 Q_PRIVATE_SLOT(d_func(), void _q_slotBytesWritten(qint64 numBytes)) 293 #ifndef QT_NO_OPENSSL 294 Q_PRIVATE_SLOT(d_func(), void _q_slotEncryptedBytesWritten(qint64 numBytes)) 295 #endif 292 296 Q_PRIVATE_SLOT(d_func(), void _q_slotDoFinished()) 293 297 Q_PRIVATE_SLOT(d_func(), void _q_slotSendRequest()) -
trunk/src/network/access/qhttpnetworkconnection.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 41 41 42 42 #include "qhttpnetworkconnection_p.h" 43 #include "qhttpnetworkconnectionchannel_p.h" 44 #include "private/qnoncontiguousbytedevice_p.h" 43 45 #include <private/qnetworkrequest_p.h> 44 46 #include <private/qobject_p.h> … … 46 48 #include <qnetworkproxy.h> 47 49 #include <qauthenticator.h> 48 #include <qbytearraymatcher.h> 50 49 51 #include <qbuffer.h> 50 52 #include <qpair.h> … … 60 62 #endif 61 63 62 #ifndef QT_NO_COMPRESS 63 # include <zlib.h> 64 static const unsigned char gz_magic[2] = {0x1f, 0x8b}; // gzip magic header 65 // gzip flag byte 66 #define HEAD_CRC 0x02 // bit 1 set: header CRC present 67 #define EXTRA_FIELD 0x04 // bit 2 set: extra field present 68 #define ORIG_NAME 0x08 // bit 3 set: original file name present 69 #define COMMENT 0x10 // bit 4 set: file comment present 70 #define RESERVED 0xE0 // bits 5..7: reserved 71 #define CHUNK 16384 64 65 66 QT_BEGIN_NAMESPACE 67 68 #ifdef Q_OS_SYMBIAN 69 const int QHttpNetworkConnectionPrivate::defaultChannelCount = 3; 70 #else 71 const int QHttpNetworkConnectionPrivate::defaultChannelCount = 6; 72 72 #endif 73 73 74 QT_BEGIN_NAMESPACE 75 76 class QHttpNetworkHeaderPrivate : public QSharedData 77 { 78 public: 79 QUrl url; 80 QList<QPair<QByteArray, QByteArray> > fields; 81 82 QHttpNetworkHeaderPrivate(const QUrl &newUrl = QUrl()); 83 QHttpNetworkHeaderPrivate(const QHttpNetworkHeaderPrivate &other); 84 inline qint64 contentLength() const; 85 inline void setContentLength(qint64 length); 86 87 inline QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const; 88 inline QList<QByteArray> headerFieldValues(const QByteArray &name) const; 89 inline void setHeaderField(const QByteArray &name, const QByteArray &data); 90 bool operator==(const QHttpNetworkHeaderPrivate &other) const; 91 92 }; 93 94 QHttpNetworkHeaderPrivate::QHttpNetworkHeaderPrivate(const QUrl &newUrl) 95 :url(newUrl) 96 { 97 } 98 99 QHttpNetworkHeaderPrivate::QHttpNetworkHeaderPrivate(const QHttpNetworkHeaderPrivate &other) 100 :QSharedData(other) 101 { 102 url = other.url; 103 fields = other.fields; 104 } 105 106 qint64 QHttpNetworkHeaderPrivate::contentLength() const 107 { 108 bool ok = false; 109 QByteArray value = headerField("content-length"); 110 qint64 length = value.toULongLong(&ok); 111 if (ok) 112 return length; 113 return -1; // the header field is not set 114 } 115 116 void QHttpNetworkHeaderPrivate::setContentLength(qint64 length) 117 { 118 setHeaderField("Content-Length", QByteArray::number(length)); 119 } 120 121 QByteArray QHttpNetworkHeaderPrivate::headerField(const QByteArray &name, const QByteArray &defaultValue) const 122 { 123 QList<QByteArray> allValues = headerFieldValues(name); 124 if (allValues.isEmpty()) 125 return defaultValue; 126 127 QByteArray result; 128 bool first = true; 129 foreach (QByteArray value, allValues) { 130 if (!first) 131 result += ", "; 132 first = false; 133 result += value; 134 } 135 return result; 136 } 137 138 QList<QByteArray> QHttpNetworkHeaderPrivate::headerFieldValues(const QByteArray &name) const 139 { 140 QList<QByteArray> result; 141 QByteArray lowerName = name.toLower(); 142 QList<QPair<QByteArray, QByteArray> >::ConstIterator it = fields.constBegin(), 143 end = fields.constEnd(); 144 for ( ; it != end; ++it) 145 if (lowerName == it->first.toLower()) 146 result += it->second; 147 148 return result; 149 } 150 151 void QHttpNetworkHeaderPrivate::setHeaderField(const QByteArray &name, const QByteArray &data) 152 { 153 QByteArray lowerName = name.toLower(); 154 QList<QPair<QByteArray, QByteArray> >::Iterator it = fields.begin(); 155 while (it != fields.end()) { 156 if (lowerName == it->first.toLower()) 157 it = fields.erase(it); 158 else 159 ++it; 160 } 161 fields.append(qMakePair(name, data)); 162 } 163 164 bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &other) const 165 { 166 return (url == other.url); 167 } 168 169 // QHttpNetworkRequestPrivate 170 class QHttpNetworkRequestPrivate : public QHttpNetworkHeaderPrivate 171 { 172 public: 173 QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, 174 QHttpNetworkRequest::Priority pri, const QUrl &newUrl = QUrl()); 175 QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate &other); 176 ~QHttpNetworkRequestPrivate(); 177 bool operator==(const QHttpNetworkRequestPrivate &other) const; 178 QByteArray methodName() const; 179 QByteArray uri(bool throughProxy) const; 180 181 static QByteArray header(const QHttpNetworkRequest &request, bool throughProxy); 182 183 QHttpNetworkRequest::Operation operation; 184 QHttpNetworkRequest::Priority priority; 185 mutable QIODevice *data; 186 bool autoDecompress; 187 }; 188 189 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, 190 QHttpNetworkRequest::Priority pri, const QUrl &newUrl) 191 : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), data(0), 192 autoDecompress(false) 193 { 194 } 195 196 QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequestPrivate &other) 197 : QHttpNetworkHeaderPrivate(other) 198 { 199 operation = other.operation; 200 priority = other.priority; 201 data = other.data; 202 autoDecompress = other.autoDecompress; 203 } 204 205 QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate() 206 { 207 } 208 209 bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &other) const 210 { 211 return QHttpNetworkHeaderPrivate::operator==(other) 212 && (operation == other.operation) 213 && (data == other.data); 214 } 215 216 QByteArray QHttpNetworkRequestPrivate::methodName() const 217 { 218 QByteArray ba; 219 switch (operation) { 220 case QHttpNetworkRequest::Options: 221 ba += "OPTIONS"; 222 break; 223 case QHttpNetworkRequest::Get: 224 ba += "GET"; 225 break; 226 case QHttpNetworkRequest::Head: 227 ba += "HEAD"; 228 break; 229 case QHttpNetworkRequest::Post: 230 ba += "POST"; 231 break; 232 case QHttpNetworkRequest::Put: 233 ba += "PUT"; 234 break; 235 case QHttpNetworkRequest::Delete: 236 ba += "DELETE"; 237 break; 238 case QHttpNetworkRequest::Trace: 239 ba += "TRACE"; 240 break; 241 case QHttpNetworkRequest::Connect: 242 ba += "CONNECT"; 243 break; 244 default: 245 break; 246 } 247 return ba; 248 } 249 250 QByteArray QHttpNetworkRequestPrivate::uri(bool throughProxy) const 251 { 252 QUrl::FormattingOptions format(QUrl::RemoveFragment); 253 254 // for POST, query data is send as content 255 if (operation == QHttpNetworkRequest::Post && !data) 256 format |= QUrl::RemoveQuery; 257 // for requests through proxy, the Request-URI contains full url 258 if (throughProxy) 259 format |= QUrl::RemoveUserInfo; 260 else 261 format |= QUrl::RemoveScheme | QUrl::RemoveAuthority; 262 QByteArray uri = url.toEncoded(format); 263 if (uri.isEmpty() || (throughProxy && url.path().isEmpty())) 264 uri += '/'; 265 return uri; 266 } 267 268 QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy) 269 { 270 QByteArray ba = request.d->methodName(); 271 QByteArray uri = request.d->uri(throughProxy); 272 ba += " " + uri; 273 274 QString majorVersion = QString::number(request.majorVersion()); 275 QString minorVersion = QString::number(request.minorVersion()); 276 ba += " HTTP/" + majorVersion.toLatin1() + "." + minorVersion.toLatin1() + "\r\n"; 277 278 QList<QPair<QByteArray, QByteArray> > fields = request.header(); 279 QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin(); 280 for (; it != fields.constEnd(); ++it) 281 ba += it->first + ": " + it->second + "\r\n"; 282 if (request.d->operation == QHttpNetworkRequest::Post) { 283 // add content type, if not set in the request 284 if (request.headerField("content-type").isEmpty()) 285 ba += "Content-Type: application/x-www-form-urlencoded\r\n"; 286 if (!request.d->data && request.d->url.hasQuery()) { 287 QByteArray query = request.d->url.encodedQuery(); 288 ba += "Content-Length: "+ QByteArray::number(query.size()) + "\r\n"; 289 ba += "\r\n"; 290 ba += query; 291 } else { 292 ba += "\r\n"; 293 } 294 } else { 295 ba += "\r\n"; 296 } 297 return ba; 298 } 299 300 class QHttpNetworkReplyPrivate : public QObjectPrivate, public QHttpNetworkHeaderPrivate 301 { 302 public: 303 QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl()); 304 ~QHttpNetworkReplyPrivate(); 305 qint64 readStatus(QAbstractSocket *socket); 306 void parseStatus(const QByteArray &status); 307 qint64 readHeader(QAbstractSocket *socket); 308 void parseHeader(const QByteArray &header); 309 qint64 readBody(QAbstractSocket *socket, QIODevice *out); 310 bool findChallenge(bool forProxy, QByteArray &challenge) const; 311 QAuthenticatorPrivate::Method authenticationMethod(bool isProxy) const; 312 void clear(); 313 314 qint64 transferRaw(QIODevice *in, QIODevice *out, qint64 size); 315 qint64 transferChunked(QIODevice *in, QIODevice *out); 316 qint64 getChunkSize(QIODevice *in, qint64 *chunkSize); 317 318 qint64 bytesAvailable() const; 319 bool isChunked(); 320 bool connectionCloseEnabled(); 321 bool isGzipped(); 322 #ifndef QT_NO_COMPRESS 323 bool gzipCheckHeader(QByteArray &content, int &pos); 324 int gunzipBodyPartially(QByteArray &compressed, QByteArray &inflated); 325 #endif 326 void removeAutoDecompressHeader(); 327 328 enum ReplyState { 329 NothingDoneState, 330 ReadingStatusState, 331 ReadingHeaderState, 332 ReadingDataState, 333 AllDoneState 334 } state; 335 336 QHttpNetworkRequest request; 337 int statusCode; 338 int majorVersion; 339 int minorVersion; 340 QString errorString; 341 QString reasonPhrase; 342 qint64 bodyLength; 343 qint64 contentRead; 344 qint64 totalProgress; 345 QByteArray fragment; 346 qint64 currentChunkSize; 347 qint64 currentChunkRead; 348 QPointer<QHttpNetworkConnection> connection; 349 bool initInflate; 350 bool streamEnd; 351 #ifndef QT_NO_COMPRESS 352 z_stream inflateStrm; 353 #endif 354 bool autoDecompress; 355 356 QByteArray responseData; // uncompressed body 357 QByteArray compressedData; // compressed body (temporary) 358 QBuffer requestDataBuffer; 359 bool requestIsBuffering; 360 bool requestIsPrepared; 361 }; 362 363 QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) 364 : QHttpNetworkHeaderPrivate(newUrl), state(NothingDoneState), statusCode(100), 365 majorVersion(0), minorVersion(0), bodyLength(0), contentRead(0), totalProgress(0), 366 currentChunkSize(0), currentChunkRead(0), connection(0), initInflate(false), 367 autoDecompress(false), requestIsBuffering(false), requestIsPrepared(false) 368 { 369 } 370 371 QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate() 372 { 373 } 374 375 void QHttpNetworkReplyPrivate::clear() 376 { 377 state = NothingDoneState; 378 statusCode = 100; 379 bodyLength = 0; 380 contentRead = 0; 381 totalProgress = 0; 382 currentChunkSize = 0; 383 currentChunkRead = 0; 384 connection = 0; 385 #ifndef QT_NO_COMPRESS 386 if (initInflate) 387 inflateEnd(&inflateStrm); 388 #endif 389 initInflate = false; 390 streamEnd = false; 391 autoDecompress = false; 392 fields.clear(); 393 } 394 395 // QHttpNetworkReplyPrivate 396 qint64 QHttpNetworkReplyPrivate::bytesAvailable() const 397 { 398 return (state != ReadingDataState ? 0 : fragment.size()); 399 } 400 401 bool QHttpNetworkReplyPrivate::isGzipped() 402 { 403 QByteArray encoding = headerField("content-encoding"); 404 return encoding.toLower() == "gzip"; 405 } 406 407 void QHttpNetworkReplyPrivate::removeAutoDecompressHeader() 408 { 409 // The header "Content-Encoding = gzip" is retained. 410 // Content-Length is removed since the actual one send by the server is for compressed data 411 QByteArray name("content-length"); 412 QByteArray lowerName = name.toLower(); 413 QList<QPair<QByteArray, QByteArray> >::Iterator it = fields.begin(), 414 end = fields.end(); 415 while (it != end) { 416 if (name == it->first.toLower()) { 417 fields.erase(it); 418 break; 419 } 420 ++it; 421 } 422 423 } 424 425 bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const 426 { 427 challenge.clear(); 428 // find out the type of authentication protocol requested. 429 QByteArray header = forProxy ? "proxy-authenticate" : "www-authenticate"; 430 // pick the best protocol (has to match parsing in QAuthenticatorPrivate) 431 QList<QByteArray> challenges = headerFieldValues(header); 432 for (int i = 0; i<challenges.size(); i++) { 433 QByteArray line = challenges.at(i); 434 if (!line.toLower().startsWith("negotiate")) 435 challenge = line; 436 } 437 return !challenge.isEmpty(); 438 } 439 440 QAuthenticatorPrivate::Method QHttpNetworkReplyPrivate::authenticationMethod(bool isProxy) const 441 { 442 // The logic is same as the one used in void QAuthenticatorPrivate::parseHttpResponse() 443 QAuthenticatorPrivate::Method method = QAuthenticatorPrivate::None; 444 QByteArray header = isProxy ? "proxy-authenticate" : "www-authenticate"; 445 QList<QByteArray> challenges = headerFieldValues(header); 446 for (int i = 0; i<challenges.size(); i++) { 447 QByteArray line = challenges.at(i).trimmed().toLower(); 448 if (method < QAuthenticatorPrivate::Basic 449 && line.startsWith("basic")) { 450 method = QAuthenticatorPrivate::Basic; 451 } else if (method < QAuthenticatorPrivate::Ntlm 452 && line.startsWith("ntlm")) { 453 method = QAuthenticatorPrivate::Ntlm; 454 } else if (method < QAuthenticatorPrivate::DigestMd5 455 && line.startsWith("digest")) { 456 method = QAuthenticatorPrivate::DigestMd5; 457 } 458 } 459 return method; 460 } 461 462 #ifndef QT_NO_COMPRESS 463 bool QHttpNetworkReplyPrivate::gzipCheckHeader(QByteArray &content, int &pos) 464 { 465 int method = 0; // method byte 466 int flags = 0; // flags byte 467 bool ret = false; 468 469 // Assure two bytes in the buffer so we can peek ahead -- handle case 470 // where first byte of header is at the end of the buffer after the last 471 // gzip segment 472 pos = -1; 473 QByteArray &body = content; 474 int maxPos = body.size()-1; 475 if (maxPos < 1) { 476 return ret; 477 } 478 479 // Peek ahead to check the gzip magic header 480 if (body[0] != char(gz_magic[0]) || 481 body[1] != char(gz_magic[1])) { 482 return ret; 483 } 484 pos += 2; 485 // Check the rest of the gzip header 486 if (++pos <= maxPos) 487 method = body[pos]; 488 if (pos++ <= maxPos) 489 flags = body[pos]; 490 if (method != Z_DEFLATED || (flags & RESERVED) != 0) { 491 return ret; 492 } 493 494 // Discard time, xflags and OS code: 495 pos += 6; 496 if (pos > maxPos) 497 return ret; 498 if ((flags & EXTRA_FIELD) && ((pos+2) <= maxPos)) { // skip the extra field 499 unsigned len = (unsigned)body[++pos]; 500 len += ((unsigned)body[++pos])<<8; 501 pos += len; 502 if (pos > maxPos) 503 return ret; 504 } 505 if ((flags & ORIG_NAME) != 0) { // skip the original file name 506 while(++pos <= maxPos && body[pos]) {} 507 } 508 if ((flags & COMMENT) != 0) { // skip the .gz file comment 509 while(++pos <= maxPos && body[pos]) {} 510 } 511 if ((flags & HEAD_CRC) != 0) { // skip the header crc 512 pos += 2; 513 if (pos > maxPos) 514 return ret; 515 } 516 ret = (pos < maxPos); // return failed, if no more bytes left 517 return ret; 518 } 519 520 int QHttpNetworkReplyPrivate::gunzipBodyPartially(QByteArray &compressed, QByteArray &inflated) 521 { 522 int ret = Z_DATA_ERROR; 523 unsigned have; 524 unsigned char out[CHUNK]; 525 int pos = -1; 526 527 if (!initInflate) { 528 // check the header 529 if (!gzipCheckHeader(compressed, pos)) 530 return ret; 531 // allocate inflate state 532 inflateStrm.zalloc = Z_NULL; 533 inflateStrm.zfree = Z_NULL; 534 inflateStrm.opaque = Z_NULL; 535 inflateStrm.avail_in = 0; 536 inflateStrm.next_in = Z_NULL; 537 ret = inflateInit2(&inflateStrm, -MAX_WBITS); 538 if (ret != Z_OK) 539 return ret; 540 initInflate = true; 541 streamEnd = false; 542 } 543 544 //remove the header. 545 compressed.remove(0, pos+1); 546 // expand until deflate stream ends 547 inflateStrm.next_in = (unsigned char *)compressed.data(); 548 inflateStrm.avail_in = compressed.size(); 549 do { 550 inflateStrm.avail_out = sizeof(out); 551 inflateStrm.next_out = out; 552 ret = inflate(&inflateStrm, Z_NO_FLUSH); 553 switch (ret) { 554 case Z_NEED_DICT: 555 ret = Z_DATA_ERROR; 556 // and fall through 557 case Z_DATA_ERROR: 558 case Z_MEM_ERROR: 559 inflateEnd(&inflateStrm); 560 initInflate = false; 561 return ret; 562 } 563 have = sizeof(out) - inflateStrm.avail_out; 564 inflated.append(QByteArray((const char *)out, have)); 565 } while (inflateStrm.avail_out == 0); 566 // clean up and return 567 if (ret <= Z_ERRNO || ret == Z_STREAM_END) { 568 inflateEnd(&inflateStrm); 569 initInflate = false; 570 } 571 streamEnd = (ret == Z_STREAM_END); 572 return ret; 573 } 574 #endif 575 576 qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) 577 { 578 qint64 bytes = 0; 579 char c; 580 581 while (socket->bytesAvailable()) { 582 // allow both CRLF & LF (only) line endings 583 if (socket->peek(&c, 1) == 1 && c == '\n') { 584 bytes += socket->read(&c, 1); // read the "n" 585 // remove the CR at the end 586 if (fragment.endsWith('\r')) { 587 fragment.truncate(fragment.length()-1); 588 } 589 parseStatus(fragment); 590 state = ReadingHeaderState; 591 fragment.clear(); // next fragment 592 break; 593 } else { 594 c = 0; 595 bytes += socket->read(&c, 1); 596 fragment.append(c); 597 } 598 } 599 return bytes; 600 } 601 602 void QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) 603 { 604 const QByteArrayMatcher sp(" "); 605 int i = sp.indexIn(status); 606 const QByteArray version = status.mid(0, i); 607 int j = sp.indexIn(status, i + 1); 608 const QByteArray code = status.mid(i + 1, j - i - 1); 609 const QByteArray reason = status.mid(j + 1, status.count() - j); 610 611 const QByteArrayMatcher slash("/"); 612 int k = slash.indexIn(version); 613 const QByteArrayMatcher dot("."); 614 int l = dot.indexIn(version, k); 615 const QByteArray major = version.mid(k + 1, l - k - 1); 616 const QByteArray minor = version.mid(l + 1, version.count() - l); 617 618 majorVersion = QString::fromAscii(major.constData()).toInt(); 619 minorVersion = QString::fromAscii(minor.constData()).toInt(); 620 statusCode = QString::fromAscii(code.constData()).toInt(); 621 reasonPhrase = QString::fromAscii(reason.constData()); 622 } 623 624 qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) 625 { 626 qint64 bytes = 0; 627 char crlfcrlf[5]; 628 crlfcrlf[4] = '\0'; 629 char c = 0; 630 bool allHeaders = false; 631 while (!allHeaders && socket->bytesAvailable()) { 632 if (socket->peek(&c, 1) == 1 && c == '\n') { 633 // check for possible header endings. As per HTTP rfc, 634 // the header endings will be marked by CRLFCRLF. But 635 // we will allow CRLFLF, LFLF & CRLFCRLF 636 if (fragment.endsWith("\n\r") || fragment.endsWith('\n')) 637 allHeaders = true; 638 } 639 bytes += socket->read(&c, 1); 640 fragment.append(c); 641 } 642 // we received all headers now parse them 643 if (allHeaders) { 644 parseHeader(fragment); 645 state = ReadingDataState; 646 fragment.clear(); // next fragment 647 bodyLength = contentLength(); // cache the length 648 } 649 return bytes; 650 } 651 652 void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header) 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 686 bool QHttpNetworkReplyPrivate::isChunked() 687 { 688 return headerField("transfer-encoding").toLower().contains("chunked"); 689 } 690 691 bool QHttpNetworkReplyPrivate::connectionCloseEnabled() 692 { 693 return (headerField("connection").toLower().contains("close") || 694 headerField("proxy-connection").toLower().contains("close")); 695 } 696 697 qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QIODevice *out) 698 { 699 qint64 bytes = 0; 700 if (isChunked()) { 701 bytes += transferChunked(socket, out); // chunked transfer encoding (rfc 2616, sec 3.6) 702 } else if (bodyLength > 0) { // we have a Content-Length 703 bytes += transferRaw(socket, out, bodyLength - contentRead); 704 if (contentRead + bytes == bodyLength) 705 state = AllDoneState; 706 } else { 707 bytes += transferRaw(socket, out, socket->bytesAvailable()); 708 } 709 if (state == AllDoneState) 710 socket->readAll(); // Read the rest to clean (CRLF) 711 contentRead += bytes; 712 return bytes; 713 } 714 715 qint64 QHttpNetworkReplyPrivate::transferRaw(QIODevice *in, QIODevice *out, qint64 size) 716 { 717 qint64 bytes = 0; 718 Q_ASSERT(in); 719 Q_ASSERT(out); 720 721 int toBeRead = qMin<qint64>(128*1024, qMin<qint64>(size, in->bytesAvailable())); 722 QByteArray raw(toBeRead, 0); 723 while (size > 0) { 724 qint64 read = in->read(raw.data(), raw.size()); 725 if (read == 0) 726 return bytes; 727 // ### error checking here 728 qint64 written = out->write(raw.data(), read); 729 if (written == 0) 730 return bytes; 731 if (read != written) 732 qDebug() << "### read" << read << "written" << written; 733 bytes += read; 734 size -= read; 735 out->waitForBytesWritten(-1); // throttle 736 } 737 return bytes; 738 739 } 740 741 qint64 QHttpNetworkReplyPrivate::transferChunked(QIODevice *in, QIODevice *out) 742 { 743 qint64 bytes = 0; 744 while (in->bytesAvailable()) { // while we can read from input 745 // if we are done with the current chunk, get the size of the new chunk 746 if (currentChunkRead >= currentChunkSize) { 747 currentChunkSize = 0; 748 currentChunkRead = 0; 749 if (bytes) { 750 char crlf[2]; 751 bytes += in->read(crlf, 2); // read the "\r\n" after the chunk 752 } 753 bytes += getChunkSize(in, ¤tChunkSize); 754 if (currentChunkSize == -1) 755 break; 756 } 757 // if the chunk size is 0, end of the stream 758 if (currentChunkSize == 0) { 759 state = AllDoneState; 760 break; 761 } 762 // otherwise, read data 763 qint64 readSize = qMin(in->bytesAvailable(), currentChunkSize - currentChunkRead); 764 QByteArray buffer(readSize, 0); 765 qint64 read = in->read(buffer.data(), readSize); 766 bytes += read; 767 currentChunkRead += read; 768 qint64 written = out->write(buffer); 769 Q_UNUSED(written); // Avoid compile warning when building release 770 Q_ASSERT(read == written); 771 // ### error checking here 772 out->waitForBytesWritten(-1); 773 } 774 return bytes; 775 } 776 777 qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *in, qint64 *chunkSize) 778 { 779 qint64 bytes = 0; 780 char crlf[2]; 781 *chunkSize = -1; 782 int bytesAvailable = in->bytesAvailable(); 783 while (bytesAvailable > bytes) { 784 qint64 sniffedBytes = in->peek(crlf, 2); 785 int fragmentSize = fragment.size(); 786 // check the next two bytes for a "\r\n", skip blank lines 787 if ((fragmentSize && sniffedBytes == 2 && crlf[0] == '\r' && crlf[1] == '\n') 788 ||(fragmentSize > 1 && fragment.endsWith('\r') && crlf[0] == '\n')) 789 { 790 bytes += in->read(crlf, 1); // read the \r or \n 791 if (crlf[0] == '\r') 792 bytes += in->read(crlf, 1); // read the \n 793 bool ok = false; 794 // ignore the chunk-extension 795 fragment = fragment.mid(0, fragment.indexOf(';')).trimmed(); 796 *chunkSize = fragment.toLong(&ok, 16); 797 fragment.clear(); 798 break; // size done 799 } else { 800 // read the fragment to the buffer 801 char c = 0; 802 bytes += in->read(&c, 1); 803 fragment.append(c); 804 } 805 } 806 return bytes; 807 } 808 809 // QHttpNetworkConnectionPrivate 810 811 typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair; 812 813 class QHttpNetworkConnectionPrivate : public QObjectPrivate 814 { 815 Q_DECLARE_PUBLIC(QHttpNetworkConnection) 816 public: 817 QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt); 818 ~QHttpNetworkConnectionPrivate(); 819 void init(); 820 void connectSignals(QAbstractSocket *socket); 821 822 enum SocketState { 823 IdleState = 0, // ready to send request 824 ConnectingState = 1, // connecting to host 825 WritingState = 2, // writing the data 826 WaitingState = 4, // waiting for reply 827 ReadingState = 8, // reading the reply 828 Wait4AuthState = 0x10, // blocked for send till the current authentication slot is done 829 BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|Wait4AuthState) 830 }; 831 832 enum { ChunkSize = 4096 }; 833 834 int indexOf(QAbstractSocket *socket) const; 835 bool isSocketBusy(QAbstractSocket *socket) const; 836 bool isSocketWriting(QAbstractSocket *socket) const; 837 bool isSocketWaiting(QAbstractSocket *socket) const; 838 bool isSocketReading(QAbstractSocket *socket) const; 839 840 QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request); 841 void unqueueRequest(QAbstractSocket *socket); 842 void prepareRequest(HttpMessagePair &request); 843 bool sendRequest(QAbstractSocket *socket); 844 void receiveReply(QAbstractSocket *socket, QHttpNetworkReply *reply); 845 void resendCurrentRequest(QAbstractSocket *socket); 846 void closeChannel(int channel); 847 void copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy); 848 849 // private slots 850 void _q_bytesWritten(qint64 bytes); // proceed sending 851 void _q_readyRead(); // pending data to read 852 void _q_disconnected(); // disconnected from host 853 void _q_startNextRequest(); // send the next request from the queue 854 void _q_restartPendingRequest(); // send the currently blocked request 855 void _q_connected(); // start sending request 856 void _q_error(QAbstractSocket::SocketError); // error from socket 857 #ifndef QT_NO_NETWORKPROXY 858 void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy 859 #endif 860 void _q_dataReadyReadNoBuffer(); 861 void _q_dataReadyReadBuffer(); 862 863 void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request); 864 bool ensureConnection(QAbstractSocket *socket); 865 QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket); 866 void eraseData(QHttpNetworkReply *reply); 867 #ifndef QT_NO_COMPRESS 868 bool expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete); 869 #endif 870 void bufferData(HttpMessagePair &request); 871 void removeReply(QHttpNetworkReply *reply); 872 873 QString hostName; 874 quint16 port; 875 bool encrypt; 876 877 struct Channel { 878 QAbstractSocket *socket; 879 SocketState state; 880 QHttpNetworkRequest request; // current request 881 QHttpNetworkReply *reply; // current reply for this request 882 qint64 written; 883 qint64 bytesTotal; 884 bool resendCurrent; 885 int lastStatus; // last status received on this channel 886 bool pendingEncrypt; // for https (send after encrypted) 887 int reconnectAttempts; // maximum 2 reconnection attempts 888 QAuthenticatorPrivate::Method authMehtod; 889 QAuthenticatorPrivate::Method proxyAuthMehtod; 890 QAuthenticator authenticator; 891 QAuthenticator proxyAuthenticator; 892 #ifndef QT_NO_OPENSSL 893 bool ignoreSSLErrors; 894 #endif 895 Channel() :state(IdleState), reply(0), written(0), bytesTotal(0), resendCurrent(false), reconnectAttempts(2), 896 authMehtod(QAuthenticatorPrivate::None), proxyAuthMehtod(QAuthenticatorPrivate::None) 897 #ifndef QT_NO_OPENSSL 898 , ignoreSSLErrors(false) 899 #endif 900 {} 901 }; 902 static const int channelCount; 903 Channel channels[2]; // maximum of 2 socket connections to the server 904 bool pendingAuthSignal; // there is an incomplete authentication signal 905 bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal 906 907 void appendData(QHttpNetworkReply &reply, const QByteArray &fragment, bool compressed); 908 qint64 bytesAvailable(const QHttpNetworkReply &reply, bool compressed = false) const; 909 qint64 read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize, bool compressed); 910 void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode); 911 bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend); 912 void allDone(QAbstractSocket *socket, QHttpNetworkReply *reply); 913 void handleStatus(QAbstractSocket *socket, QHttpNetworkReply *reply); 914 inline bool emitSignals(QHttpNetworkReply *reply); 915 inline bool expectContent(QHttpNetworkReply *reply); 916 917 #ifndef QT_NO_OPENSSL 918 void _q_encrypted(); // start sending request (https) 919 void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket 920 QSslConfiguration sslConfiguration(const QHttpNetworkReply &reply) const; 921 #endif 922 923 #ifndef QT_NO_NETWORKPROXY 924 QNetworkProxy networkProxy; 925 #endif 926 927 //The request queues 928 QList<HttpMessagePair> highPriorityQueue; 929 QList<HttpMessagePair> lowPriorityQueue; 930 }; 931 932 const int QHttpNetworkConnectionPrivate::channelCount = 2; 74 // the maximum amount of requests that might be pipelined into a socket 75 // from what was suggested, 3 seems to be OK 76 const int QHttpNetworkConnectionPrivate::defaultPipelineLength = 3; 77 933 78 934 79 QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt) 935 80 : hostName(hostName), port(port), encrypt(encrypt), 81 channelCount(defaultChannelCount), 936 82 pendingAuthSignal(false), pendingProxyAuthSignal(false) 937 83 #ifndef QT_NO_NETWORKPROXY … … 939 85 #endif 940 86 { 941 } 87 channels = new QHttpNetworkConnectionChannel[channelCount]; 88 } 89 90 QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt) 91 : hostName(hostName), port(port), encrypt(encrypt), 92 channelCount(channelCount), 93 pendingAuthSignal(false), pendingProxyAuthSignal(false) 94 #ifndef QT_NO_NETWORKPROXY 95 , networkProxy(QNetworkProxy::NoProxy) 96 #endif 97 { 98 channels = new QHttpNetworkConnectionChannel[channelCount]; 99 } 100 101 942 102 943 103 QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() 944 104 { 945 105 for (int i = 0; i < channelCount; ++i) { 946 channels[i].socket->close(); 947 delete channels[i].socket; 948 } 949 } 950 951 void QHttpNetworkConnectionPrivate::connectSignals(QAbstractSocket *socket) 952 { 953 Q_Q(QHttpNetworkConnection); 954 955 QObject::connect(socket, SIGNAL(bytesWritten(qint64)), 956 q, SLOT(_q_bytesWritten(qint64)), 957 Qt::DirectConnection); 958 QObject::connect(socket, SIGNAL(connected()), 959 q, SLOT(_q_connected()), 960 Qt::DirectConnection); 961 QObject::connect(socket, SIGNAL(readyRead()), 962 q, SLOT(_q_readyRead()), 963 Qt::DirectConnection); 964 QObject::connect(socket, SIGNAL(disconnected()), 965 q, SLOT(_q_disconnected()), 966 Qt::DirectConnection); 967 QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), 968 q, SLOT(_q_error(QAbstractSocket::SocketError)), 969 Qt::DirectConnection); 970 #ifndef QT_NO_NETWORKPROXY 971 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), 972 q, SLOT(_q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), 973 Qt::DirectConnection); 974 #endif 975 976 #ifndef QT_NO_OPENSSL 977 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); 978 QObject::connect(sslSocket, SIGNAL(encrypted()), 979 q, SLOT(_q_encrypted()), 980 Qt::DirectConnection); 981 QObject::connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError>&)), 982 q, SLOT(_q_sslErrors(const QList<QSslError>&)), 983 Qt::DirectConnection); 984 #endif 106 if (channels[i].socket) { 107 channels[i].socket->close(); 108 delete channels[i].socket; 109 } 110 } 111 delete []channels; 985 112 } 986 113 987 114 void QHttpNetworkConnectionPrivate::init() 988 115 { 989 for (int i = 0; i < channelCount; ++i) { 990 #ifndef QT_NO_OPENSSL 991 channels[i].socket = new QSslSocket; 992 #else 993 channels[i].socket = new QTcpSocket; 994 #endif 995 connectSignals(channels[i].socket); 116 for (int i = 0; i < channelCount; i++) { 117 channels[i].setConnection(this->q_func()); 118 channels[i].init(); 996 119 } 997 120 } … … 1002 125 if (channels[i].socket == socket) 1003 126 return i; 1004 return -1; 1005 } 1006 1007 bool QHttpNetworkConnectionPrivate::isSocketBusy(QAbstractSocket *socket) const 1008 { 1009 int i = indexOf(socket); 1010 return (channels[i].state & BusyState); 1011 } 1012 1013 bool QHttpNetworkConnectionPrivate::isSocketWriting(QAbstractSocket *socket) const 1014 { 1015 int i = indexOf(socket); 1016 return (i != -1 && (channels[i].state & WritingState)); 1017 } 1018 1019 bool QHttpNetworkConnectionPrivate::isSocketWaiting(QAbstractSocket *socket) const 1020 { 1021 int i = indexOf(socket); 1022 return (i != -1 && (channels[i].state & WaitingState)); 1023 } 1024 1025 bool QHttpNetworkConnectionPrivate::isSocketReading(QAbstractSocket *socket) const 1026 { 1027 int i = indexOf(socket); 1028 return (i != -1 && (channels[i].state & ReadingState)); 1029 } 1030 1031 1032 void QHttpNetworkConnectionPrivate::appendData(QHttpNetworkReply &reply, const QByteArray &fragment, bool compressed) 1033 { 1034 QByteArray *ba = (compressed) ? &reply.d_func()->compressedData : &reply.d_func()->responseData; 1035 ba->append(fragment); 1036 return; 1037 } 1038 1039 qint64 QHttpNetworkConnectionPrivate::bytesAvailable(const QHttpNetworkReply &reply, bool compressed) const 1040 { 1041 const QByteArray *ba = (compressed) ? &reply.d_func()->compressedData : &reply.d_func()->responseData; 1042 return ba->size(); 1043 } 1044 1045 qint64 QHttpNetworkConnectionPrivate::read(QHttpNetworkReply &reply, QByteArray &data, qint64 maxSize, bool compressed) 1046 { 1047 QByteArray *ba = (compressed) ? &reply.d_func()->compressedData : &reply.d_func()->responseData; 1048 if (maxSize == -1 || maxSize >= ba->size()) { 1049 // read the whole data 1050 data = *ba; 1051 ba->clear(); 1052 } else { 1053 // read only the requested length 1054 data = ba->mid(0, maxSize); 1055 ba->remove(0, maxSize); 1056 } 1057 return data.size(); 1058 } 1059 1060 void QHttpNetworkConnectionPrivate::eraseData(QHttpNetworkReply *reply) 1061 { 1062 reply->d_func()->compressedData.clear(); 1063 reply->d_func()->responseData.clear(); 127 128 qFatal("Called with unknown socket object."); 129 return 0; 130 } 131 132 qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const 133 { 134 return reply.d_func()->responseData.byteAmount(); 135 } 136 137 qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const 138 { 139 return reply.d_func()->responseData.sizeNextBlock(); 1064 140 } 1065 141 … … 1072 148 QByteArray value; 1073 149 // check if Content-Length is provided 1074 QIODevice *data = request.data(); 1075 if (data && request.contentLength() == -1) { 1076 if (!data->isSequential()) 1077 request.setContentLength(data->size()); 1078 else 1079 bufferData(messagePair); // ### or do chunked upload 150 QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); 151 if (uploadByteDevice) { 152 if (request.contentLength() != -1 && uploadByteDevice->size() != -1) { 153 // both values known, take the smaller one. 154 request.setContentLength(qMin(uploadByteDevice->size(), request.contentLength())); 155 } else if (request.contentLength() == -1 && uploadByteDevice->size() != -1) { 156 // content length not supplied by user, but the upload device knows it 157 request.setContentLength(uploadByteDevice->size()); 158 } else if (request.contentLength() != -1 && uploadByteDevice->size() == -1) { 159 // everything OK, the user supplied us the contentLength 160 } else if (request.contentLength() == -1 && uploadByteDevice->size() == -1) { 161 qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given"); 162 } 1080 163 } 1081 164 // set the Connection/Proxy-Connection: Keep-Alive headers … … 1093 176 } 1094 177 #endif 1095 // set the gzip header 178 179 // If the request had a accept-encoding set, we better not mess 180 // with it. If it was not set, we announce that we understand gzip 181 // and remember this fact in request.d->autoDecompress so that 182 // we can later decompress the HTTP reply if it has such an 183 // encoding. 1096 184 value = request.headerField("accept-encoding"); 1097 185 if (value.isEmpty()) { … … 1104 192 #endif 1105 193 } 194 195 // some websites mandate an accept-language header and fail 196 // if it is not sent. This is a problem with the website and 197 // not with us, but we work around this by setting 198 // one always. 199 value = request.headerField("accept-language"); 200 if (value.isEmpty()) { 201 QString systemLocale = QLocale::system().name().replace(QChar::fromAscii('_'),QChar::fromAscii('-')); 202 QString acceptLanguage; 203 if (systemLocale == QLatin1String("C")) 204 acceptLanguage = QString::fromAscii("en,*"); 205 else if (systemLocale.startsWith(QLatin1String("en-"))) 206 acceptLanguage = QString::fromAscii("%1,*").arg(systemLocale); 207 else 208 acceptLanguage = QString::fromAscii("%1,en,*").arg(systemLocale); 209 request.setHeaderField("Accept-Language", acceptLanguage.toAscii()); 210 } 211 1106 212 // set the User Agent 1107 213 value = request.headerField("user-agent"); … … 1125 231 } 1126 232 1127 bool QHttpNetworkConnectionPrivate::ensureConnection(QAbstractSocket *socket) 1128 { 1129 // make sure that this socket is in a connected state, if not initiate 1130 // connection to the host. 1131 if (socket->state() != QAbstractSocket::ConnectedState) { 1132 // connect to the host if not already connected. 1133 int index = indexOf(socket); 1134 channels[index].state = ConnectingState; 1135 channels[index].pendingEncrypt = encrypt; 1136 1137 // This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done" 1138 // is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the 1139 // last header for Authorization is generated by the QAuthenticator. Basic & Digest logic does not 1140 // check the "phase" for generating the Authorization header. NTLM authentication is a two stage 1141 // process & needs the "phase". To make sure the QAuthenticator uses the current username/password 1142 // the phase is reset to Start. 1143 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[index].authenticator); 1144 if (priv && priv->phase == QAuthenticatorPrivate::Done) 1145 priv->phase = QAuthenticatorPrivate::Start; 1146 priv = QAuthenticatorPrivate::getPrivate(channels[index].proxyAuthenticator); 1147 if (priv && priv->phase == QAuthenticatorPrivate::Done) 1148 priv->phase = QAuthenticatorPrivate::Start; 1149 1150 QString connectHost = hostName; 1151 qint16 connectPort = port; 1152 1153 #ifndef QT_NO_NETWORKPROXY 1154 // HTTPS always use transparent proxy. 1155 if (networkProxy.type() != QNetworkProxy::NoProxy && !encrypt) { 1156 connectHost = networkProxy.hostName(); 1157 connectPort = networkProxy.port(); 1158 } 1159 #endif 1160 if (encrypt) { 1161 #ifndef QT_NO_OPENSSL 1162 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket); 1163 sslSocket->connectToHostEncrypted(connectHost, connectPort); 1164 if (channels[index].ignoreSSLErrors) 1165 sslSocket->ignoreSslErrors(); 1166 #else 1167 emitReplyError(socket, channels[index].reply, QNetworkReply::ProtocolUnknownError); 1168 #endif 1169 } else { 1170 socket->connectToHost(connectHost, connectPort); 1171 } 1172 return false; 1173 } 1174 return true; 1175 } 1176 1177 1178 bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket) 1179 { 1180 Q_Q(QHttpNetworkConnection); 1181 1182 int i = indexOf(socket); 1183 switch (channels[i].state) { 1184 case IdleState: { // write the header 1185 if (!ensureConnection(socket)) { 1186 // wait for the connection (and encryption) to be done 1187 // sendRequest will be called again from either 1188 // _q_connected or _q_encrypted 1189 return false; 1190 } 1191 channels[i].written = 0; // excluding the header 1192 channels[i].bytesTotal = 0; 1193 if (channels[i].reply) { 1194 channels[i].reply->d_func()->clear(); 1195 channels[i].reply->d_func()->connection = q; 1196 channels[i].reply->d_func()->autoDecompress = channels[i].request.d->autoDecompress; 1197 } 1198 channels[i].state = WritingState; 1199 channels[i].pendingEncrypt = false; 1200 // if the url contains authentication parameters, use the new ones 1201 // both channels will use the new authentication parameters 1202 if (!channels[i].request.url().userInfo().isEmpty()) { 1203 QUrl url = channels[i].request.url(); 1204 QAuthenticator &auth = channels[i].authenticator; 1205 if (url.userName() != auth.user() 1206 || (!url.password().isEmpty() && url.password() != auth.password())) { 1207 auth.setUser(url.userName()); 1208 auth.setPassword(url.password()); 1209 copyCredentials(i, &auth, false); 1210 } 1211 // clear the userinfo, since we use the same request for resending 1212 // userinfo in url can conflict with the one in the authenticator 1213 url.setUserInfo(QString()); 1214 channels[i].request.setUrl(url); 1215 } 1216 createAuthorization(socket, channels[i].request); 1217 #ifndef QT_NO_NETWORKPROXY 1218 QByteArray header = QHttpNetworkRequestPrivate::header(channels[i].request, 1219 (networkProxy.type() != QNetworkProxy::NoProxy)); 1220 #else 1221 QByteArray header = QHttpNetworkRequestPrivate::header(channels[i].request, 1222 false); 1223 #endif 1224 socket->write(header); 1225 QIODevice *data = channels[i].request.d->data; 1226 QHttpNetworkReply *reply = channels[i].reply; 1227 if (reply && reply->d_func()->requestDataBuffer.size()) 1228 data = &channels[i].reply->d_func()->requestDataBuffer; 1229 if (data && (data->isOpen() || data->open(QIODevice::ReadOnly))) { 1230 if (data->isSequential()) { 1231 channels[i].bytesTotal = -1; 1232 QObject::connect(data, SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadNoBuffer())); 1233 QObject::connect(data, SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadNoBuffer())); 1234 } else { 1235 channels[i].bytesTotal = data->size(); 1236 } 1237 } else { 1238 channels[i].state = WaitingState; 1239 break; 1240 } 1241 // write the initial chunk together with the headers 1242 // fall through 1243 } 1244 case WritingState: { // write the data 1245 QIODevice *data = channels[i].request.d->data; 1246 if (channels[i].reply->d_func()->requestDataBuffer.size()) 1247 data = &channels[i].reply->d_func()->requestDataBuffer; 1248 if (!data || channels[i].bytesTotal == channels[i].written) { 1249 channels[i].state = WaitingState; // now wait for response 1250 break; 1251 } 1252 1253 QByteArray chunk; 1254 chunk.resize(ChunkSize); 1255 qint64 readSize = data->read(chunk.data(), ChunkSize); 1256 if (readSize == -1) { 1257 // source has reached EOF 1258 channels[i].state = WaitingState; // now wait for response 1259 } else if (readSize > 0) { 1260 // source gave us something useful 1261 channels[i].written += socket->write(chunk.data(), readSize); 1262 if (channels[i].reply) 1263 emit channels[i].reply->dataSendProgress(channels[i].written, channels[i].bytesTotal); 1264 } 1265 break; 1266 } 1267 case WaitingState: 1268 case ReadingState: 1269 case Wait4AuthState: 1270 // ignore _q_bytesWritten in these states 1271 // fall through 1272 default: 1273 break; 1274 } 1275 return true; 1276 } 1277 1278 bool QHttpNetworkConnectionPrivate::emitSignals(QHttpNetworkReply *reply) 1279 { 1280 // for 401 & 407 don't emit the data signals. Content along with these 1281 // responses are send only if the authentication fails. 1282 return (reply && reply->d_func()->statusCode != 401 && reply->d_func()->statusCode != 407); 1283 } 1284 1285 bool QHttpNetworkConnectionPrivate::expectContent(QHttpNetworkReply *reply) 1286 { 1287 // check whether we can expect content after the headers (rfc 2616, sec4.4) 1288 if (!reply) 1289 return false; 1290 if ((reply->d_func()->statusCode >= 100 && reply->d_func()->statusCode < 200) 1291 || reply->d_func()->statusCode == 204 || reply->d_func()->statusCode == 304) 1292 return false; 1293 if (reply->d_func()->request.operation() == QHttpNetworkRequest::Head) 1294 return !emitSignals(reply); 1295 if (reply->d_func()->contentLength() == 0) 1296 return false; 1297 return true; 1298 } 233 234 1299 235 1300 236 void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket, … … 1309 245 int i = indexOf(socket); 1310 246 // remove the corrupt data if any 1311 eraseData(channels[i].reply);1312 c loseChannel(i);247 reply->d_func()->eraseData(); 248 channels[i].close(); 1313 249 // send the next request 1314 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);1315 }1316 }1317 1318 #ifndef QT_NO_COMPRESS1319 bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete)1320 {1321 Q_ASSERT(socket);1322 Q_ASSERT(reply);1323 1324 qint64 total = bytesAvailable(*reply, true);1325 if (total >= CHUNK || dataComplete) {1326 int i = indexOf(socket);1327 // uncompress the data1328 QByteArray content, inflated;1329 read(*reply, content, -1, true);1330 int ret = Z_OK;1331 if (content.size())1332 ret = reply->d_func()->gunzipBodyPartially(content, inflated);1333 int retCheck = (dataComplete) ? Z_STREAM_END : Z_OK;1334 if (ret >= retCheck) {1335 if (inflated.size()) {1336 reply->d_func()->totalProgress += inflated.size();1337 appendData(*reply, inflated, false);1338 if (emitSignals(reply)) {1339 emit reply->readyRead();1340 // make sure that the reply is valid1341 if (channels[i].reply != reply)1342 return true;1343 emit reply->dataReadProgress(reply->d_func()->totalProgress, 0);1344 // make sure that the reply is valid1345 if (channels[i].reply != reply)1346 return true;1347 1348 }1349 }1350 } else {1351 emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);1352 return false;1353 }1354 }1355 return true;1356 }1357 #endif1358 1359 void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpNetworkReply *reply)1360 {1361 Q_ASSERT(socket);1362 1363 Q_Q(QHttpNetworkConnection);1364 qint64 bytes = 0;1365 QAbstractSocket::SocketState state = socket->state();1366 int i = indexOf(socket);1367 1368 // connection might be closed to signal the end of data1369 if (state == QAbstractSocket::UnconnectedState) {1370 if (!socket->bytesAvailable()) {1371 if (reply && reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {1372 reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;1373 channels[i].state = IdleState;1374 allDone(socket, reply);1375 } else {1376 // try to reconnect/resend before sending an error.1377 if (channels[i].reconnectAttempts-- > 0) {1378 resendCurrentRequest(socket);1379 } else {1380 reply->d_func()->errorString = errorDetail(QNetworkReply::RemoteHostClosedError, socket);1381 emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString);1382 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);1383 }1384 }1385 }1386 }1387 1388 // read loop for the response1389 while (socket->bytesAvailable()) {1390 QHttpNetworkReplyPrivate::ReplyState state = reply ? reply->d_func()->state : QHttpNetworkReplyPrivate::AllDoneState;1391 switch (state) {1392 case QHttpNetworkReplyPrivate::NothingDoneState:1393 case QHttpNetworkReplyPrivate::ReadingStatusState:1394 bytes += reply->d_func()->readStatus(socket);1395 channels[i].lastStatus = reply->d_func()->statusCode;1396 break;1397 case QHttpNetworkReplyPrivate::ReadingHeaderState:1398 bytes += reply->d_func()->readHeader(socket);1399 if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {1400 if (reply->d_func()->isGzipped() && reply->d_func()->autoDecompress) {1401 // remove the Content-Length from header1402 reply->d_func()->removeAutoDecompressHeader();1403 } else {1404 reply->d_func()->autoDecompress = false;1405 }1406 if (reply && reply->d_func()->statusCode == 100) {1407 reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;1408 break; // ignore1409 }1410 if (emitSignals(reply))1411 emit reply->headerChanged();1412 if (!expectContent(reply)) {1413 reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;1414 channels[i].state = IdleState;1415 allDone(socket, reply);1416 return;1417 }1418 }1419 break;1420 case QHttpNetworkReplyPrivate::ReadingDataState: {1421 QBuffer fragment;1422 fragment.open(QIODevice::WriteOnly);1423 bytes = reply->d_func()->readBody(socket, &fragment);1424 if (bytes) {1425 appendData(*reply, fragment.data(), reply->d_func()->autoDecompress);1426 if (!reply->d_func()->autoDecompress) {1427 reply->d_func()->totalProgress += fragment.size();1428 if (emitSignals(reply)) {1429 emit reply->readyRead();1430 // make sure that the reply is valid1431 if (channels[i].reply != reply)1432 return;1433 emit reply->dataReadProgress(reply->d_func()->totalProgress, reply->d_func()->bodyLength);1434 // make sure that the reply is valid1435 if (channels[i].reply != reply)1436 return;1437 }1438 }1439 #ifndef QT_NO_COMPRESS1440 else if (!expand(socket, reply, false)) { // expand a chunk if possible1441 return; // ### expand failed1442 }1443 #endif1444 }1445 if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState)1446 break;1447 // everything done, fall through1448 }1449 case QHttpNetworkReplyPrivate::AllDoneState:1450 channels[i].state = IdleState;1451 allDone(socket, reply);1452 break;1453 default:1454 break;1455 }1456 }1457 }1458 1459 void QHttpNetworkConnectionPrivate::allDone(QAbstractSocket *socket, QHttpNetworkReply *reply)1460 {1461 #ifndef QT_NO_COMPRESS1462 // expand the whole data.1463 if (expectContent(reply) && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd)1464 expand(socket, reply, true); // ### if expand returns false, its an error1465 #endif1466 // while handling 401 & 407, we might reset the status code, so save this.1467 bool emitFinished = emitSignals(reply);1468 handleStatus(socket, reply);1469 // ### at this point there should be no more data on the socket1470 // close if server requested1471 int i = indexOf(socket);1472 if (reply->d_func()->connectionCloseEnabled())1473 closeChannel(i);1474 // queue the finished signal, this is required since we might send new requests from1475 // slot connected to it. The socket will not fire readyRead signal, if we are already1476 // in the slot connected to readyRead1477 if (emitFinished)1478 QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection);1479 // reset the reconnection attempts after we receive a complete reply.1480 // in case of failures, each channel will attempt two reconnects before emitting error.1481 channels[i].reconnectAttempts = 2;1482 }1483 1484 void QHttpNetworkConnectionPrivate::handleStatus(QAbstractSocket *socket, QHttpNetworkReply *reply)1485 {1486 Q_ASSERT(socket);1487 Q_ASSERT(reply);1488 1489 Q_Q(QHttpNetworkConnection);1490 1491 int statusCode = reply->statusCode();1492 bool resend = false;1493 1494 switch (statusCode) {1495 case 401:1496 case 407:1497 handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend);1498 if (resend) {1499 eraseData(reply);1500 sendRequest(socket);1501 }1502 break;1503 default:1504 250 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); 1505 251 } … … 1528 274 1529 275 276 // handles the authentication for one channel and eventually re-starts the other channels 1530 277 bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, 1531 278 bool isProxy, bool &resend) … … 1567 314 if ((isProxy && pendingProxyAuthSignal) ||(!isProxy && pendingAuthSignal)) { 1568 315 // drop the request 1569 eraseData(channels[i].reply);1570 c loseChannel(i);316 reply->d_func()->eraseData(); 317 channels[i].close(); 1571 318 channels[i].lastStatus = 0; 1572 channels[i].state = Wait4AuthState;319 channels[i].state = QHttpNetworkConnectionChannel::Wait4AuthState; 1573 320 return false; 1574 321 } 1575 322 // cannot use this socket until the slot returns 1576 channels[i].state = WaitingState;323 channels[i].state = QHttpNetworkConnectionChannel::WaitingState; 1577 324 socket->blockSignals(true); 1578 325 if (!isProxy) { … … 1589 336 socket->blockSignals(false); 1590 337 // socket free to use 1591 channels[i].state = IdleState;338 channels[i].state = QHttpNetworkConnectionChannel::IdleState; 1592 339 if (priv->phase != QAuthenticatorPrivate::Done) { 1593 340 // send any pending requests 1594 341 copyCredentials(i, auth, isProxy); 1595 QMetaObject::invokeMethod(q, "_q_restart PendingRequest", Qt::QueuedConnection);342 QMetaObject::invokeMethod(q, "_q_restartAuthPendingRequests", Qt::QueuedConnection); 1596 343 } 1597 344 } … … 1601 348 emit channels[i].reply->headerChanged(); 1602 349 emit channels[i].reply->readyRead(); 1603 emit channels[i].reply->finished();1604 350 QNetworkReply::NetworkError errorCode = 1605 351 isProxy … … 1613 359 // remove pending request on the other channels 1614 360 for (int j = 0; j < channelCount; ++j) { 1615 if (j != i && channels[j].state == Wait4AuthState)1616 channels[j].state = IdleState;361 if (j != i && channels[j].state == QHttpNetworkConnectionChannel::Wait4AuthState) 362 channels[j].state = QHttpNetworkConnectionChannel::IdleState; 1617 363 } 1618 364 return true; … … 1630 376 1631 377 int i = indexOf(socket); 378 1632 379 if (channels[i].authMehtod != QAuthenticatorPrivate::None) { 1633 380 if (!(channels[i].authMehtod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) { … … 1635 382 if (priv && priv->method != QAuthenticatorPrivate::None) { 1636 383 QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false)); 1637 request.setHeaderField(" authorization", response);384 request.setHeaderField("Authorization", response); 1638 385 } 1639 386 } … … 1644 391 if (priv && priv->method != QAuthenticatorPrivate::None) { 1645 392 QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false)); 1646 request.setHeaderField(" proxy-authorization", response);393 request.setHeaderField("Proxy-Authorization", response); 1647 394 } 1648 395 } … … 1673 420 } 1674 421 1675 void QHttpNetworkConnectionPrivate::unqueueRequest(QAbstractSocket *socket) 422 void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) 423 { 424 Q_Q(QHttpNetworkConnection); 425 426 QHttpNetworkRequest request = pair.first; 427 switch (request.priority()) { 428 case QHttpNetworkRequest::HighPriority: 429 highPriorityQueue.prepend(pair); 430 break; 431 case QHttpNetworkRequest::NormalPriority: 432 case QHttpNetworkRequest::LowPriority: 433 lowPriorityQueue.prepend(pair); 434 break; 435 } 436 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); 437 } 438 439 void QHttpNetworkConnectionPrivate::dequeueAndSendRequest(QAbstractSocket *socket) 1676 440 { 1677 441 Q_ASSERT(socket); … … 1680 444 1681 445 if (!highPriorityQueue.isEmpty()) { 1682 for (int j = highPriorityQueue.count() - 1; j >= 0; --j) { 1683 HttpMessagePair &messagePair = highPriorityQueue[j]; 1684 if (!messagePair.second->d_func()->requestIsPrepared) 1685 prepareRequest(messagePair); 1686 if (!messagePair.second->d_func()->requestIsBuffering) { 1687 channels[i].request = messagePair.first; 1688 channels[i].reply = messagePair.second; 1689 sendRequest(socket); 1690 highPriorityQueue.removeAt(j); 1691 return; 1692 } 1693 } 446 // remove from queue before sendRequest! else we might pipeline the same request again 447 HttpMessagePair messagePair = highPriorityQueue.takeLast(); 448 if (!messagePair.second->d_func()->requestIsPrepared) 449 prepareRequest(messagePair); 450 channels[i].request = messagePair.first; 451 channels[i].reply = messagePair.second; 452 channels[i].sendRequest(); 453 return; 1694 454 } 1695 455 1696 456 if (!lowPriorityQueue.isEmpty()) { 1697 for (int j = lowPriorityQueue.count() - 1; j >= 0; --j) { 1698 HttpMessagePair &messagePair = lowPriorityQueue[j]; 1699 if (!messagePair.second->d_func()->requestIsPrepared) 1700 prepareRequest(messagePair); 1701 if (!messagePair.second->d_func()->requestIsBuffering) { 1702 channels[i].request = messagePair.first; 1703 channels[i].reply = messagePair.second; 1704 sendRequest(socket); 1705 lowPriorityQueue.removeAt(j); 1706 return; 1707 } 1708 } 1709 } 1710 } 1711 1712 void QHttpNetworkConnectionPrivate::closeChannel(int channel) 1713 { 1714 QAbstractSocket *socket = channels[channel].socket; 1715 socket->blockSignals(true); 1716 socket->close(); 1717 socket->blockSignals(false); 1718 channels[channel].state = IdleState; 1719 } 1720 1721 void QHttpNetworkConnectionPrivate::resendCurrentRequest(QAbstractSocket *socket) 1722 { 1723 Q_Q(QHttpNetworkConnection); 1724 Q_ASSERT(socket); 457 // remove from queue before sendRequest! else we might pipeline the same request again 458 HttpMessagePair messagePair = lowPriorityQueue.takeLast(); 459 if (!messagePair.second->d_func()->requestIsPrepared) 460 prepareRequest(messagePair); 461 channels[i].request = messagePair.first; 462 channels[i].reply = messagePair.second; 463 channels[i].sendRequest(); 464 return; 465 } 466 } 467 468 // this is called from _q_startNextRequest and when a request has been sent down a socket from the channel 469 void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket) 470 { 471 // return fast if there is nothing to pipeline 472 if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) 473 return; 474 1725 475 int i = indexOf(socket); 1726 closeChannel(i); 1727 channels[i].resendCurrent = true; 1728 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); 1729 } 476 477 bool highPriorityQueueProcessingDone = false; 478 bool lowPriorityQueueProcessingDone = false; 479 480 while (!highPriorityQueueProcessingDone && !lowPriorityQueueProcessingDone) { 481 // this loop runs once per request we intend to pipeline in. 482 483 if (channels[i].pipeliningSupported != QHttpNetworkConnectionChannel::PipeliningProbablySupported) 484 return; 485 486 // the current request that is in must already support pipelining 487 if (!channels[i].request.isPipeliningAllowed()) 488 return; 489 490 // the current request must be a idempotent (right now we only check GET) 491 if (channels[i].request.operation() != QHttpNetworkRequest::Get) 492 return; 493 494 // check if socket is connected 495 if (socket->state() != QAbstractSocket::ConnectedState) 496 return; 497 498 // check for resendCurrent 499 if (channels[i].resendCurrent) 500 return; 501 502 // we do not like authentication stuff 503 // ### make sure to be OK with this in later releases 504 if (!channels[i].authenticator.isNull() || !channels[i].authenticator.user().isEmpty()) 505 return; 506 if (!channels[i].proxyAuthenticator.isNull() || !channels[i].proxyAuthenticator.user().isEmpty()) 507 return; 508 509 // check for pipeline length 510 if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) 511 return; 512 513 // must be in ReadingState or WaitingState 514 if (! (channels[i].state == QHttpNetworkConnectionChannel::WaitingState 515 || channels[i].state == QHttpNetworkConnectionChannel::ReadingState)) 516 return; 517 518 highPriorityQueueProcessingDone = fillPipeline(highPriorityQueue, channels[i]); 519 // not finished with highPriorityQueue? then loop again 520 if (!highPriorityQueueProcessingDone) 521 continue; 522 // highPriorityQueue was processed, now deal with the lowPriorityQueue 523 lowPriorityQueueProcessingDone = fillPipeline(lowPriorityQueue, channels[i]); 524 } 525 } 526 527 // returns true when the processing of a queue has been done 528 bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel) 529 { 530 if (queue.isEmpty()) 531 return true; 532 533 for (int i = queue.count() - 1; i >= 0; --i) { 534 HttpMessagePair messagePair = queue.at(i); 535 const QHttpNetworkRequest &request = messagePair.first; 536 537 // we currently do not support pipelining if HTTP authentication is used 538 if (!request.url().userInfo().isEmpty()) 539 continue; 540 541 // take only GET requests 542 if (request.operation() != QHttpNetworkRequest::Get) 543 continue; 544 545 if (!request.isPipeliningAllowed()) 546 continue; 547 548 // remove it from the queue 549 queue.takeAt(i); 550 // we modify the queue we iterate over here, but since we return from the function 551 // afterwards this is fine. 552 553 // actually send it 554 if (!messagePair.second->d_func()->requestIsPrepared) 555 prepareRequest(messagePair); 556 channel.pipelineInto(messagePair); 557 558 // return false because we processed something and need to process again 559 return false; 560 } 561 562 // return true, the queue has been processed and not changed 563 return true; 564 } 565 1730 566 1731 567 QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket* socket) … … 1771 607 } 1772 608 609 // this is called from the destructor of QHttpNetworkReply. It is called when 610 // the reply was finished correctly or when it was aborted. 1773 611 void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) 1774 612 { 1775 613 Q_Q(QHttpNetworkConnection); 1776 614 1777 // remove the from active list.615 // check if the reply is currently being processed or it is pipelined in 1778 616 for (int i = 0; i < channelCount; ++i) { 617 // is the reply associated the currently processing of this channel? 1779 618 if (channels[i].reply == reply) { 1780 619 channels[i].reply = 0; 1781 closeChannel(i); 620 621 if (!reply->isFinished() && !channels[i].alreadyPipelinedRequests.isEmpty()) { 622 // the reply had to be prematurely removed, e.g. it was not finished 623 // therefore we have to requeue the already pipelined requests. 624 channels[i].requeueCurrentlyPipelinedRequests(); 625 } 626 627 // if HTTP mandates we should close 628 // or the reply is not finished yet, e.g. it was aborted 629 // we have to close that connection 630 if (reply->d_func()->isConnectionCloseEnabled() || !reply->isFinished()) 631 channels[i].close(); 632 1782 633 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); 1783 634 return; 635 } 636 637 // is the reply inside the pipeline of this channel already? 638 for (int j = 0; j < channels[i].alreadyPipelinedRequests.length(); j++) { 639 if (channels[i].alreadyPipelinedRequests.at(j).second == reply) { 640 // Remove that HttpMessagePair 641 channels[i].alreadyPipelinedRequests.removeAt(j); 642 643 channels[i].requeueCurrentlyPipelinedRequests(); 644 645 // Since some requests had already been pipelined, but we removed 646 // one and re-queued the others 647 // we must force a connection close after the request that is 648 // currently in processing has been finished. 649 if (channels[i].reply) 650 channels[i].reply->d_func()->forceConnectionCloseEnabled = true; 651 652 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); 653 return; 654 } 1784 655 } 1785 656 } … … 1809 680 1810 681 1811 //private slots1812 void QHttpNetworkConnectionPrivate::_q_readyRead()1813 {1814 Q_Q(QHttpNetworkConnection);1815 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());1816 if (!socket)1817 return; // ### error1818 if (isSocketWaiting(socket) || isSocketReading(socket)) {1819 int i = indexOf(socket);1820 channels[i].state = ReadingState;1821 if (channels[i].reply)1822 receiveReply(socket, channels[i].reply);1823 }1824 // ### error1825 }1826 1827 void QHttpNetworkConnectionPrivate::_q_bytesWritten(qint64 bytes)1828 {1829 Q_UNUSED(bytes);1830 Q_Q(QHttpNetworkConnection);1831 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());1832 if (!socket)1833 return; // ### error1834 if (isSocketWriting(socket))1835 sendRequest(socket);1836 // otherwise we do nothing1837 }1838 1839 void QHttpNetworkConnectionPrivate::_q_disconnected()1840 {1841 Q_Q(QHttpNetworkConnection);1842 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());1843 if (!socket)1844 return; // ### error1845 // read the available data before closing1846 int i = indexOf(socket);1847 if (isSocketWaiting(socket) || isSocketReading(socket)) {1848 channels[i].state = ReadingState;1849 if (channels[i].reply)1850 receiveReply(socket, channels[i].reply);1851 }1852 channels[i].state = IdleState;1853 }1854 682 1855 683 void QHttpNetworkConnectionPrivate::_q_startNextRequest() 1856 684 { 1857 // send the current request again 1858 if (channels[0].resendCurrent || channels[1].resendCurrent) { 1859 int i = channels[0].resendCurrent ? 0:1; 1860 QAbstractSocket *socket = channels[i].socket; 1861 channels[i].resendCurrent = false; 1862 channels[i].state = IdleState; 1863 if (channels[i].reply) 1864 sendRequest(socket); 685 //resend the necessary ones. 686 for (int i = 0; i < channelCount; ++i) { 687 if (channels[i].resendCurrent) { 688 channels[i].resendCurrent = false; 689 channels[i].state = QHttpNetworkConnectionChannel::IdleState; 690 if (channels[i].reply) 691 channels[i].sendRequest(); 692 } 693 } 694 QAbstractSocket *socket = 0; 695 for (int i = 0; i < channelCount; ++i) { 696 QAbstractSocket *chSocket = channels[i].socket; 697 // send the request using the idle socket 698 if (!channels[i].isSocketBusy()) { 699 socket = chSocket; 700 break; 701 } 702 } 703 704 // this socket is free, 705 if (socket) 706 dequeueAndSendRequest(socket); 707 708 // try to push more into all sockets 709 // ### FIXME we should move this to the beginning of the function 710 // as soon as QtWebkit is properly using the pipelining 711 // (e.g. not for XMLHttpRequest or the first page load) 712 // ### FIXME we should also divide the requests more even 713 // on the connected sockets 714 //tryToFillPipeline(socket); 715 // return fast if there is nothing to pipeline 716 if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) 1865 717 return; 1866 } 1867 // send the request using the idle socket 1868 QAbstractSocket *socket = channels[0].socket; 1869 if (isSocketBusy(socket)) { 1870 socket = (isSocketBusy(channels[1].socket) ? 0 :channels[1].socket); 1871 } 1872 1873 if (!socket) { 1874 return; // this will be called after finishing current request. 1875 } 1876 unqueueRequest(socket); 1877 } 1878 1879 void QHttpNetworkConnectionPrivate::_q_restartPendingRequest() 718 for (int j = 0; j < channelCount; j++) 719 fillPipeline(channels[j].socket); 720 } 721 722 void QHttpNetworkConnectionPrivate::_q_restartAuthPendingRequests() 1880 723 { 1881 724 // send the request using the idle socket 1882 725 for (int i = 0 ; i < channelCount; ++i) { 1883 QAbstractSocket *socket = channels[i].socket; 1884 if (channels[i].state == Wait4AuthState) { 1885 channels[i].state = IdleState; 726 if (channels[i].state == QHttpNetworkConnectionChannel::Wait4AuthState) { 727 channels[i].state = QHttpNetworkConnectionChannel::IdleState; 1886 728 if (channels[i].reply) 1887 sendRequest(socket); 1888 } 1889 } 1890 } 1891 1892 void QHttpNetworkConnectionPrivate::_q_connected() 1893 { 1894 Q_Q(QHttpNetworkConnection); 1895 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender()); 1896 if (!socket) 1897 return; // ### error 1898 int i = indexOf(socket); 1899 // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! 1900 //channels[i].reconnectAttempts = 2; 1901 if (!channels[i].pendingEncrypt) { 1902 channels[i].state = IdleState; 1903 if (channels[i].reply) 1904 sendRequest(socket); 1905 else 1906 closeChannel(i); 1907 } 1908 } 1909 1910 1911 void QHttpNetworkConnectionPrivate::_q_error(QAbstractSocket::SocketError socketError) 1912 { 1913 Q_Q(QHttpNetworkConnection); 1914 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender()); 1915 if (!socket) 1916 return; 1917 bool send2Reply = false; 1918 int i = indexOf(socket); 1919 QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError; 1920 1921 switch (socketError) { 1922 case QAbstractSocket::HostNotFoundError: 1923 errorCode = QNetworkReply::HostNotFoundError; 1924 break; 1925 case QAbstractSocket::ConnectionRefusedError: 1926 errorCode = QNetworkReply::ConnectionRefusedError; 1927 break; 1928 case QAbstractSocket::RemoteHostClosedError: 1929 // try to reconnect/resend before sending an error. 1930 // while "Reading" the _q_disconnected() will handle this. 1931 if (channels[i].state != IdleState && channels[i].state != ReadingState) { 1932 if (channels[i].reconnectAttempts-- > 0) { 1933 resendCurrentRequest(socket); 1934 return; 1935 } else { 1936 send2Reply = true; 1937 errorCode = QNetworkReply::RemoteHostClosedError; 1938 } 1939 } else { 1940 return; 1941 } 1942 break; 1943 case QAbstractSocket::SocketTimeoutError: 1944 // try to reconnect/resend before sending an error. 1945 if (channels[i].state == WritingState && (channels[i].reconnectAttempts-- > 0)) { 1946 resendCurrentRequest(socket); 1947 return; 1948 } 1949 send2Reply = true; 1950 errorCode = QNetworkReply::TimeoutError; 1951 break; 1952 case QAbstractSocket::ProxyAuthenticationRequiredError: 1953 errorCode = QNetworkReply::ProxyAuthenticationRequiredError; 1954 break; 1955 case QAbstractSocket::SslHandshakeFailedError: 1956 errorCode = QNetworkReply::SslHandshakeFailedError; 1957 break; 1958 default: 1959 // all other errors are treated as NetworkError 1960 errorCode = QNetworkReply::UnknownNetworkError; 1961 break; 1962 } 1963 QPointer<QObject> that = q; 1964 QString errorString = errorDetail(errorCode, socket); 1965 if (send2Reply) { 1966 if (channels[i].reply) { 1967 channels[i].reply->d_func()->errorString = errorString; 1968 // this error matters only to this reply 1969 emit channels[i].reply->finishedWithError(errorCode, errorString); 1970 } 1971 // send the next request 1972 QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection); 1973 } else { 1974 // the failure affects all requests. 1975 emit q->error(errorCode, errorString); 1976 } 1977 if (that) //signals make enter the event loop 1978 closeChannel(i); 1979 } 1980 1981 #ifndef QT_NO_NETWORKPROXY 1982 void QHttpNetworkConnectionPrivate::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth) 1983 { 1984 Q_Q(QHttpNetworkConnection); 1985 emit q->proxyAuthenticationRequired(proxy, auth, q); 1986 } 1987 #endif 1988 1989 void QHttpNetworkConnectionPrivate::_q_dataReadyReadNoBuffer() 1990 { 1991 Q_Q(QHttpNetworkConnection); 1992 // data emitted either readyRead() 1993 // find out which channel it is for 1994 QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); 1995 1996 // won't match anything if the qobject_cast above failed 1997 for (int i = 0; i < channelCount; ++i) { 1998 if (sender == channels[i].request.data()) { 1999 sendRequest(channels[i].socket); 2000 break; 2001 } 2002 } 2003 } 2004 2005 void QHttpNetworkConnectionPrivate::_q_dataReadyReadBuffer() 2006 { 2007 Q_Q(QHttpNetworkConnection); 2008 QIODevice *sender = qobject_cast<QIODevice *>(q->sender()); 2009 HttpMessagePair *thePair = 0; 2010 for (int i = 0; !thePair && i < lowPriorityQueue.size(); ++i) 2011 if (lowPriorityQueue.at(i).first.data() == sender) 2012 thePair = &lowPriorityQueue[i]; 2013 2014 for (int i = 0; !thePair && i < highPriorityQueue.size(); ++i) 2015 if (highPriorityQueue.at(i).first.data() == sender) 2016 thePair = &highPriorityQueue[i]; 2017 2018 if (thePair) { 2019 bufferData(*thePair); 2020 2021 // are we finished buffering? 2022 if (!thePair->second->d_func()->requestIsBuffering) 2023 _q_startNextRequest(); 2024 } 2025 } 2026 2027 void QHttpNetworkConnectionPrivate::bufferData(HttpMessagePair &messagePair) 2028 { 2029 Q_Q(QHttpNetworkConnection); 2030 QHttpNetworkRequest &request = messagePair.first; 2031 QHttpNetworkReply *reply = messagePair.second; 2032 Q_ASSERT(request.data()); 2033 if (!reply->d_func()->requestIsBuffering) { // first time 2034 QObject::connect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); 2035 QObject::connect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); 2036 reply->d_func()->requestIsBuffering = true; 2037 reply->d_func()->requestDataBuffer.open(QIODevice::ReadWrite); 2038 } 2039 2040 // always try to read at least one byte 2041 // ### FIXME! use a QRingBuffer 2042 qint64 bytesToRead = qMax<qint64>(1, request.data()->bytesAvailable()); 2043 QByteArray newData; 2044 newData.resize(bytesToRead); 2045 qint64 bytesActuallyRead = request.data()->read(newData.data(), bytesToRead); 2046 2047 if (bytesActuallyRead > 0) { 2048 // we read something 2049 newData.chop(bytesToRead - bytesActuallyRead); 2050 reply->d_func()->requestDataBuffer.write(newData); 2051 } else if (bytesActuallyRead == -1) { // last time 2052 QObject::disconnect(request.data(), SIGNAL(readyRead()), q, SLOT(_q_dataReadyReadBuffer())); 2053 QObject::disconnect(request.data(), SIGNAL(readChannelFinished()), q, SLOT(_q_dataReadyReadBuffer())); 2054 2055 request.setContentLength(reply->d_func()->requestDataBuffer.size()); 2056 reply->d_func()->requestDataBuffer.seek(0); 2057 reply->d_func()->requestIsBuffering = false; 2058 } 2059 } 2060 2061 // QHttpNetworkConnection 729 channels[i].sendRequest(); 730 } 731 } 732 } 733 2062 734 2063 735 QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent) 2064 736 : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) 737 { 738 Q_D(QHttpNetworkConnection); 739 d->init(); 740 } 741 742 QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, QObject *parent) 743 : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt)), parent) 2065 744 { 2066 745 Q_D(QHttpNetworkConnection); … … 2151 830 #endif 2152 831 2153 // QHttpNetworkRequest2154 2155 QHttpNetworkRequest::QHttpNetworkRequest(const QUrl &url, Operation operation, Priority priority)2156 : d(new QHttpNetworkRequestPrivate(operation, priority, url))2157 {2158 }2159 2160 QHttpNetworkRequest::QHttpNetworkRequest(const QHttpNetworkRequest &other)2161 : QHttpNetworkHeader(other), d(other.d)2162 {2163 }2164 2165 QHttpNetworkRequest::~QHttpNetworkRequest()2166 {2167 }2168 2169 QUrl QHttpNetworkRequest::url() const2170 {2171 return d->url;2172 }2173 void QHttpNetworkRequest::setUrl(const QUrl &url)2174 {2175 d->url = url;2176 }2177 2178 qint64 QHttpNetworkRequest::contentLength() const2179 {2180 return d->contentLength();2181 }2182 2183 void QHttpNetworkRequest::setContentLength(qint64 length)2184 {2185 d->setContentLength(length);2186 }2187 2188 QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const2189 {2190 return d->fields;2191 }2192 2193 QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const2194 {2195 return d->headerField(name, defaultValue);2196 }2197 2198 void QHttpNetworkRequest::setHeaderField(const QByteArray &name, const QByteArray &data)2199 {2200 d->setHeaderField(name, data);2201 }2202 2203 QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other)2204 {2205 d = other.d;2206 return *this;2207 }2208 2209 bool QHttpNetworkRequest::operator==(const QHttpNetworkRequest &other) const2210 {2211 return d->operator==(*other.d);2212 }2213 2214 QHttpNetworkRequest::Operation QHttpNetworkRequest::operation() const2215 {2216 return d->operation;2217 }2218 2219 void QHttpNetworkRequest::setOperation(Operation operation)2220 {2221 d->operation = operation;2222 }2223 2224 QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const2225 {2226 return d->priority;2227 }2228 2229 void QHttpNetworkRequest::setPriority(Priority priority)2230 {2231 d->priority = priority;2232 }2233 2234 QIODevice *QHttpNetworkRequest::data() const2235 {2236 return d->data;2237 }2238 2239 void QHttpNetworkRequest::setData(QIODevice *data)2240 {2241 d->data = data;2242 }2243 2244 int QHttpNetworkRequest::majorVersion() const2245 {2246 return 1;2247 }2248 2249 int QHttpNetworkRequest::minorVersion() const2250 {2251 return 1;2252 }2253 2254 // QHttpNetworkReply2255 2256 QHttpNetworkReply::QHttpNetworkReply(const QUrl &url, QObject *parent)2257 : QObject(*new QHttpNetworkReplyPrivate(url), parent)2258 {2259 }2260 2261 QHttpNetworkReply::~QHttpNetworkReply()2262 {2263 Q_D(QHttpNetworkReply);2264 if (d->connection) {2265 d->connection->d_func()->removeReply(this);2266 }2267 }2268 2269 QUrl QHttpNetworkReply::url() const2270 {2271 return d_func()->url;2272 }2273 void QHttpNetworkReply::setUrl(const QUrl &url)2274 {2275 Q_D(QHttpNetworkReply);2276 d->url = url;2277 }2278 2279 qint64 QHttpNetworkReply::contentLength() const2280 {2281 return d_func()->contentLength();2282 }2283 2284 void QHttpNetworkReply::setContentLength(qint64 length)2285 {2286 Q_D(QHttpNetworkReply);2287 d->setContentLength(length);2288 }2289 2290 QList<QPair<QByteArray, QByteArray> > QHttpNetworkReply::header() const2291 {2292 return d_func()->fields;2293 }2294 2295 QByteArray QHttpNetworkReply::headerField(const QByteArray &name, const QByteArray &defaultValue) const2296 {2297 return d_func()->headerField(name, defaultValue);2298 }2299 2300 void QHttpNetworkReply::setHeaderField(const QByteArray &name, const QByteArray &data)2301 {2302 Q_D(QHttpNetworkReply);2303 d->setHeaderField(name, data);2304 }2305 2306 void QHttpNetworkReply::parseHeader(const QByteArray &header)2307 {2308 Q_D(QHttpNetworkReply);2309 d->parseHeader(header);2310 }2311 2312 QHttpNetworkRequest QHttpNetworkReply::request() const2313 {2314 return d_func()->request;2315 }2316 2317 void QHttpNetworkReply::setRequest(const QHttpNetworkRequest &request)2318 {2319 Q_D(QHttpNetworkReply);2320 d->request = request;2321 }2322 2323 int QHttpNetworkReply::statusCode() const2324 {2325 return d_func()->statusCode;2326 }2327 2328 void QHttpNetworkReply::setStatusCode(int code)2329 {2330 Q_D(QHttpNetworkReply);2331 d->statusCode = code;2332 }2333 2334 QString QHttpNetworkReply::errorString() const2335 {2336 return d_func()->errorString;2337 }2338 2339 QString QHttpNetworkReply::reasonPhrase() const2340 {2341 return d_func()->reasonPhrase;2342 }2343 2344 void QHttpNetworkReply::setErrorString(const QString &error)2345 {2346 Q_D(QHttpNetworkReply);2347 d->errorString = error;2348 }2349 2350 int QHttpNetworkReply::majorVersion() const2351 {2352 return d_func()->majorVersion;2353 }2354 2355 int QHttpNetworkReply::minorVersion() const2356 {2357 return d_func()->minorVersion;2358 }2359 2360 qint64 QHttpNetworkReply::bytesAvailable() const2361 {2362 Q_D(const QHttpNetworkReply);2363 if (d->connection)2364 return d->connection->d_func()->bytesAvailable(*this);2365 else2366 return -1;2367 }2368 2369 QByteArray QHttpNetworkReply::read(qint64 maxSize)2370 {2371 Q_D(QHttpNetworkReply);2372 QByteArray data;2373 if (d->connection)2374 d->connection->d_func()->read(*this, data, maxSize, false);2375 return data;2376 }2377 2378 bool QHttpNetworkReply::isFinished() const2379 {2380 return d_func()->state == QHttpNetworkReplyPrivate::AllDoneState;2381 }2382 832 2383 833 // SSL support below 2384 834 #ifndef QT_NO_OPENSSL 2385 void QHttpNetworkConnectionPrivate::_q_encrypted()2386 {2387 Q_Q(QHttpNetworkConnection);2388 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());2389 if (!socket)2390 return; // ### error2391 channels[indexOf(socket)].state = IdleState;2392 sendRequest(socket);2393 }2394 2395 void QHttpNetworkConnectionPrivate::_q_sslErrors(const QList<QSslError> &errors)2396 {2397 Q_Q(QHttpNetworkConnection);2398 QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());2399 if (!socket)2400 return;2401 //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;2402 emit q->sslErrors(errors);2403 }2404 2405 835 QSslConfiguration QHttpNetworkConnectionPrivate::sslConfiguration(const QHttpNetworkReply &reply) const 2406 836 { 837 if (!encrypt) 838 return QSslConfiguration(); 839 2407 840 for (int i = 0; i < channelCount; ++i) 2408 841 if (channels[i].reply == &reply) … … 2414 847 { 2415 848 Q_D(QHttpNetworkConnection); 849 if (!d->encrypt) 850 return; 851 2416 852 // set the config on all channels 2417 853 for (int i = 0; i < d->channelCount; ++i) … … 2422 858 { 2423 859 Q_D(QHttpNetworkConnection); 860 if (!d->encrypt) 861 return; 862 2424 863 if (channel == -1) { // ignore for all channels 2425 864 for (int i = 0; i < d->channelCount; ++i) { 2426 865 static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(); 2427 d->channels[i].ignore SSLErrors = true;866 d->channels[i].ignoreAllSslErrors = true; 2428 867 } 2429 868 2430 869 } else { 2431 870 static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(); 2432 d->channels[channel].ignoreSSLErrors = true; 2433 } 2434 } 2435 2436 QSslConfiguration QHttpNetworkReply::sslConfiguration() const 2437 { 2438 Q_D(const QHttpNetworkReply); 2439 if (d->connection) 2440 return d->connection->d_func()->sslConfiguration(*this); 2441 return QSslConfiguration(); 2442 } 2443 2444 void QHttpNetworkReply::setSslConfiguration(const QSslConfiguration &config) 2445 { 2446 Q_D(QHttpNetworkReply); 2447 if (d->connection) 2448 d->connection->setSslConfiguration(config); 2449 } 2450 2451 void QHttpNetworkReply::ignoreSslErrors() 2452 { 2453 Q_D(QHttpNetworkReply); 2454 if (d->connection) 2455 d->connection->ignoreSslErrors(); 2456 } 871 d->channels[channel].ignoreAllSslErrors = true; 872 } 873 } 874 875 void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int channel) 876 { 877 Q_D(QHttpNetworkConnection); 878 if (!d->encrypt) 879 return; 880 881 if (channel == -1) { // ignore for all channels 882 for (int i = 0; i < d->channelCount; ++i) { 883 static_cast<QSslSocket *>(d->channels[i].socket)->ignoreSslErrors(errors); 884 d->channels[i].ignoreSslErrorsList = errors; 885 } 886 887 } else { 888 static_cast<QSslSocket *>(d->channels[channel].socket)->ignoreSslErrors(errors); 889 d->channels[channel].ignoreSslErrorsList = errors; 890 } 891 } 892 2457 893 #endif //QT_NO_OPENSSL 2458 894 895 #ifndef QT_NO_NETWORKPROXY 896 // only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not 897 // from QHttpNetworkConnectionChannel::handleAuthenticationChallenge 898 // e.g. it is for SOCKS proxies which require authentication. 899 void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth) 900 { 901 Q_Q(QHttpNetworkConnection); 902 emit q->proxyAuthenticationRequired(proxy, auth, q); 903 int i = indexOf(chan->socket); 904 copyCredentials(i, auth, true); 905 } 906 #endif 907 2459 908 2460 909 QT_END_NAMESPACE -
trunk/src/network/access/qhttpnetworkconnection_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 56 56 #include <QtNetwork/qnetworkreply.h> 57 57 #include <QtNetwork/qabstractsocket.h> 58 59 #include <private/qobject_p.h> 60 #include <qauthenticator.h> 61 #include <qnetworkproxy.h> 62 #include <qbuffer.h> 63 64 #include <private/qhttpnetworkheader_p.h> 65 #include <private/qhttpnetworkrequest_p.h> 66 #include <private/qhttpnetworkreply_p.h> 67 68 #include <private/qhttpnetworkconnectionchannel_p.h> 58 69 59 70 #ifndef QT_NO_HTTP … … 70 81 class QHttpNetworkRequest; 71 82 class QHttpNetworkReply; 83 class QByteArray; 72 84 73 85 class QHttpNetworkConnectionPrivate; … … 78 90 79 91 QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); 92 QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); 80 93 ~QHttpNetworkConnection(); 81 94 … … 107 120 void setSslConfiguration(const QSslConfiguration &config); 108 121 void ignoreSslErrors(int channel = -1); 122 void ignoreSslErrors(const QList<QSslError> &errors, int channel = -1); 109 123 110 124 Q_SIGNALS: … … 126 140 Q_DISABLE_COPY(QHttpNetworkConnection) 127 141 friend class QHttpNetworkReply; 128 129 Q_PRIVATE_SLOT(d_func(), void _q_bytesWritten(qint64)) 130 Q_PRIVATE_SLOT(d_func(), void _q_readyRead()) 131 Q_PRIVATE_SLOT(d_func(), void _q_disconnected()) 142 friend class QHttpNetworkConnectionChannel; 143 132 144 Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest()) 133 Q_PRIVATE_SLOT(d_func(), void _q_restartPendingRequest()) 134 Q_PRIVATE_SLOT(d_func(), void _q_connected()) 135 Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError)) 145 Q_PRIVATE_SLOT(d_func(), void _q_restartAuthPendingRequests()) 146 }; 147 148 149 // private classes 150 typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair; 151 152 153 class QHttpNetworkConnectionPrivate : public QObjectPrivate 154 { 155 Q_DECLARE_PUBLIC(QHttpNetworkConnection) 156 public: 157 static const int defaultChannelCount; 158 static const int defaultPipelineLength; 159 160 QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt); 161 QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt); 162 ~QHttpNetworkConnectionPrivate(); 163 void init(); 164 165 enum { ChunkSize = 4096 }; 166 167 int indexOf(QAbstractSocket *socket) const; 168 169 QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request); 170 void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke 171 void dequeueAndSendRequest(QAbstractSocket *socket); 172 void prepareRequest(HttpMessagePair &request); 173 174 void fillPipeline(QAbstractSocket *socket); 175 bool fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel); 176 177 void copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy); 178 179 // private slots 180 void _q_startNextRequest(); // send the next request from the queue 181 void _q_restartAuthPendingRequests(); // send the currently blocked request 182 183 void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request); 184 185 QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket); 186 187 #ifndef QT_NO_COMPRESS 188 bool expand(QAbstractSocket *socket, QHttpNetworkReply *reply, bool dataComplete); 189 #endif 190 void removeReply(QHttpNetworkReply *reply); 191 192 QString hostName; 193 quint16 port; 194 bool encrypt; 195 196 const int channelCount; 197 QHttpNetworkConnectionChannel *channels; // parallel connections to the server 198 199 bool pendingAuthSignal; // there is an incomplete authentication signal 200 bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal 201 202 qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const; 203 qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const; 204 205 206 void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode); 207 bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend); 208 209 210 #ifndef QT_NO_OPENSSL 211 QSslConfiguration sslConfiguration(const QHttpNetworkReply &reply) const; 212 #endif 213 136 214 #ifndef QT_NO_NETWORKPROXY 137 Q _PRIVATE_SLOT(d_func(), void _q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))138 #endif 139 Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadBuffer()) 140 Q_PRIVATE_SLOT(d_func(), void _q_dataReadyReadNoBuffer()) 141 142 #ifndef QT_NO_OPENSSL 143 Q _PRIVATE_SLOT(d_func(), void _q_encrypted())144 Q_PRIVATE_SLOT(d_func(), void _q_sslErrors(const QList<QSslError>&)) 145 #endif 215 QNetworkProxy networkProxy; 216 void emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth); 217 #endif 218 219 //The request queues 220 QList<HttpMessagePair> highPriorityQueue; 221 QList<HttpMessagePair> lowPriorityQueue; 222 223 friend class QHttpNetworkConnectionChannel; 146 224 }; 147 225 148 class Q_AUTOTEST_EXPORT QHttpNetworkHeader 149 { 150 public: 151 virtual ~QHttpNetworkHeader() {}; 152 virtual QUrl url() const = 0; 153 virtual void setUrl(const QUrl &url) = 0; 154 155 virtual int majorVersion() const = 0; 156 virtual int minorVersion() const = 0; 157 158 virtual qint64 contentLength() const = 0; 159 virtual void setContentLength(qint64 length) = 0; 160 161 virtual QList<QPair<QByteArray, QByteArray> > header() const = 0; 162 virtual QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const = 0; 163 virtual void setHeaderField(const QByteArray &name, const QByteArray &data) = 0; 164 }; 165 166 class QHttpNetworkRequestPrivate; 167 class Q_AUTOTEST_EXPORT QHttpNetworkRequest: public QHttpNetworkHeader 168 { 169 public: 170 enum Operation { 171 Options, 172 Get, 173 Head, 174 Post, 175 Put, 176 Delete, 177 Trace, 178 Connect 179 }; 180 181 enum Priority { 182 HighPriority, 183 NormalPriority, 184 LowPriority 185 }; 186 187 QHttpNetworkRequest(const QUrl &url = QUrl(), Operation operation = Get, Priority priority = NormalPriority); 188 QHttpNetworkRequest(const QHttpNetworkRequest &other); 189 virtual ~QHttpNetworkRequest(); 190 QHttpNetworkRequest &operator=(const QHttpNetworkRequest &other); 191 bool operator==(const QHttpNetworkRequest &other) const; 192 193 QUrl url() const; 194 void setUrl(const QUrl &url); 195 196 int majorVersion() const; 197 int minorVersion() const; 198 199 qint64 contentLength() const; 200 void setContentLength(qint64 length); 201 202 QList<QPair<QByteArray, QByteArray> > header() const; 203 QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const; 204 void setHeaderField(const QByteArray &name, const QByteArray &data); 205 206 Operation operation() const; 207 void setOperation(Operation operation); 208 209 Priority priority() const; 210 void setPriority(Priority priority); 211 212 QIODevice *data() const; 213 void setData(QIODevice *data); 214 215 private: 216 QSharedDataPointer<QHttpNetworkRequestPrivate> d; 217 friend class QHttpNetworkRequestPrivate; 218 friend class QHttpNetworkConnectionPrivate; 219 }; 220 221 class QHttpNetworkReplyPrivate; 222 class Q_AUTOTEST_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkHeader 223 { 224 Q_OBJECT 225 public: 226 227 explicit QHttpNetworkReply(const QUrl &url = QUrl(), QObject *parent = 0); 228 virtual ~QHttpNetworkReply(); 229 230 QUrl url() const; 231 void setUrl(const QUrl &url); 232 233 int majorVersion() const; 234 int minorVersion() const; 235 236 qint64 contentLength() const; 237 void setContentLength(qint64 length); 238 239 QList<QPair<QByteArray, QByteArray> > header() const; 240 QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const; 241 void setHeaderField(const QByteArray &name, const QByteArray &data); 242 void parseHeader(const QByteArray &header); // mainly for testing 243 244 QHttpNetworkRequest request() const; 245 void setRequest(const QHttpNetworkRequest &request); 246 247 int statusCode() const; 248 void setStatusCode(int code); 249 250 QString errorString() const; 251 void setErrorString(const QString &error); 252 253 QString reasonPhrase() const; 254 255 qint64 bytesAvailable() const; 256 QByteArray read(qint64 maxSize = -1); 257 258 bool isFinished() const; 259 260 #ifndef QT_NO_OPENSSL 261 QSslConfiguration sslConfiguration() const; 262 void setSslConfiguration(const QSslConfiguration &config); 263 void ignoreSslErrors(); 264 265 Q_SIGNALS: 266 void sslErrors(const QList<QSslError> &errors); 267 #endif 268 269 Q_SIGNALS: 270 void readyRead(); 271 void finished(); 272 void finishedWithError(QNetworkReply::NetworkError errorCode, const QString &detail = QString()); 273 void headerChanged(); 274 void dataReadProgress(int done, int total); 275 void dataSendProgress(int done, int total); 276 277 private: 278 Q_DECLARE_PRIVATE(QHttpNetworkReply) 279 friend class QHttpNetworkConnection; 280 friend class QHttpNetworkConnectionPrivate; 281 }; 226 282 227 283 228 QT_END_NAMESPACE 284 229 285 Q_DECLARE_METATYPE(QHttpNetworkRequest)286 //Q_DECLARE_METATYPE(QHttpNetworkReply)287 288 230 #endif // QT_NO_HTTP 289 231 -
trunk/src/network/access/qnetworkaccessbackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 51 51 #include "qabstractnetworkcache.h" 52 52 53 #include "private/qnoncontiguousbytedevice_p.h" 54 53 55 QT_BEGIN_NAMESPACE 54 56 … … 91 93 if (mode == QNetworkRequest::AlwaysCache 92 94 && (op == QNetworkAccessManager::GetOperation 93 || op == QNetworkAccessManager::HeadOperation)) 94 return new QNetworkAccessCacheBackend; 95 || op == QNetworkAccessManager::HeadOperation)) { 96 QNetworkAccessBackend *backend = new QNetworkAccessCacheBackend; 97 backend->manager = this; 98 return backend; 99 } 95 100 96 101 if (!factoryDataShutdown) { … … 110 115 } 111 116 117 QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() 118 { 119 QNonContiguousByteDevice* device = 0; 120 121 if (reply->outgoingDataBuffer) 122 device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer); 123 else 124 device = QNonContiguousByteDeviceFactory::create(reply->outgoingData); 125 126 bool bufferDisallowed = 127 reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, 128 QVariant(false)) == QVariant(true); 129 if (bufferDisallowed) 130 device->disableReset(); 131 132 // make sure we delete this later 133 device->setParent(this); 134 135 connect(device, SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64))); 136 137 return device; 138 } 139 140 // need to have this function since the reply is a private member variable 141 // and the special backends need to access this. 142 void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal) 143 { 144 if (reply->isFinished()) 145 return; 146 reply->emitUploadProgress(bytesSent, bytesTotal); 147 } 148 112 149 QNetworkAccessBackend::QNetworkAccessBackend() 150 : manager(0) 151 , reply(0) 113 152 { 114 153 } … … 118 157 } 119 158 120 void QNetworkAccessBackend::upstreamReadyRead()121 {122 // do nothing123 }124 125 159 void QNetworkAccessBackend::downstreamReadyWrite() 126 160 { … … 135 169 void QNetworkAccessBackend::ignoreSslErrors() 136 170 { 171 // do nothing 172 } 173 174 void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors) 175 { 176 Q_UNUSED(errors); 137 177 // do nothing 138 178 } … … 172 212 QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const 173 213 { 174 return reply->networkCache; // should be the same as manager->networkCache 214 if (!manager) 215 return 0; 216 return manager->networkCache; 175 217 } 176 218 … … 185 227 } 186 228 187 qint64 QNetworkAccessBackend::upstreamBytesAvailable() const188 {189 return reply->writeBuffer.size();190 }191 192 void QNetworkAccessBackend::upstreamBytesConsumed(qint64 count)193 {194 // remove count bytes from the write buffer195 reply->consume(count);196 }197 198 QByteArray QNetworkAccessBackend::readUpstream()199 {200 // ### this is expensive. Consider making QRingBuffer::peekAll keep the buffer it returns201 return reply->writeBuffer.peek(upstreamBytesAvailable());202 }203 204 229 qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const 205 230 { … … 207 232 } 208 233 209 qint64 QNetworkAccessBackend::downstreamBytesToConsume() const 210 { 211 return reply->writeBuffer.size(); 212 } 213 214 void QNetworkAccessBackend::writeDownstreamData(const QByteArray &data) 215 { 216 reply->feed(data); 234 void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list) 235 { 236 reply->appendDownstreamData(list); 217 237 } 218 238 219 239 void QNetworkAccessBackend::writeDownstreamData(QIODevice *data) 220 240 { 221 reply-> feed(data);241 reply->appendDownstreamData(data); 222 242 } 223 243 -
trunk/src/network/access/qnetworkaccessbackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 71 71 class QAbstractNetworkCache; 72 72 class QNetworkCacheMetaData; 73 class QNetworkAccessBackendUploadIODevice; 74 class QNonContiguousByteDevice; 73 75 74 76 // Should support direct file upload from disk or download to disk. … … 87 89 // 88 90 // - Upstream: 89 // Upstream is data that is being written into this connection, 90 // from the user. Upstream operates in a "pull" mechanism: the 91 // connection will be notified that there is more data available 92 // by a call to "upstreamReadyRead". The number of bytes 93 // available is given by upstreamBytesAvailable(). A call to 94 // readUpstream() always yields the entire upstream buffer. When 95 // the connection has processed a certain amount of bytes from 96 // that buffer, it should call upstreamBytesConsumed(). 91 // The upstream uses a QNonContiguousByteDevice provided 92 // by the backend. This device emits the usual readyRead() 93 // signal when the backend has data available for the connection 94 // to write. The different backends can listen on this signal 95 // and then pull upload data from the QNonContiguousByteDevice and 96 // deal with it. 97 // 97 98 // 98 99 // - Downstream: … … 112 113 virtual void open() = 0; 113 114 virtual void closeDownstreamChannel() = 0; 114 virtual void closeUpstreamChannel() = 0;115 115 virtual bool waitForDownstreamReadyRead(int msecs) = 0; 116 virtual bool waitForUpstreamBytesWritten(int msecs) = 0;117 116 118 117 // slot-like: 119 virtual void upstreamReadyRead();120 118 virtual void downstreamReadyWrite(); 121 119 virtual void copyFinished(QIODevice *); 122 120 virtual void ignoreSslErrors(); 121 virtual void ignoreSslErrors(const QList<QSslError> &errors); 123 122 124 123 virtual void fetchSslConfiguration(QSslConfiguration &configuration) const; … … 156 155 void setAttribute(QNetworkRequest::Attribute code, const QVariant &value); 157 156 157 // return true if the QNonContiguousByteDevice of the upload 158 // data needs to support reset(). Currently needed for HTTP. 159 // This will possibly enable buffering of the upload data. 160 virtual bool needsResetableUploadData() { return false; } 161 158 162 protected: 159 // these functions control the upstream mechanism 160 // that is, data coming into the backend and out via the connection 161 qint64 upstreamBytesAvailable() const; 162 void upstreamBytesConsumed(qint64 count); 163 QByteArray readUpstream(); 163 // Create the device used for reading the upload data 164 QNonContiguousByteDevice* createUploadByteDevice(); 165 164 166 165 167 // these functions control the downstream mechanism 166 168 // that is, data that has come via the connection and is going out the backend 167 169 qint64 nextDownstreamBlockSize() const; 168 qint64 downstreamBytesToConsume() const; 169 void writeDownstreamData(const QByteArray &data); 170 void writeDownstreamData(QByteDataBuffer &list); 171 172 public slots: 173 // for task 251801, needs to be a slot to be called asynchronously 170 174 void writeDownstreamData(QIODevice *data); 171 175 … … 180 184 void redirectionRequested(const QUrl &destination); 181 185 void sslErrors(const QList<QSslError> &errors); 186 void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); 182 187 183 188 private: 184 189 friend class QNetworkAccessManager; 185 190 friend class QNetworkAccessManagerPrivate; 191 friend class QNetworkAccessBackendUploadIODevice; 186 192 QNetworkAccessManagerPrivate *manager; 187 193 QNetworkReplyImplPrivate *reply; -
trunk/src/network/access/qnetworkaccesscache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qnetworkaccesscache_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 65 65 class QUrl; 66 66 67 // this class is not about caching files but about 68 // caching objects used by QNetworkAccessManager, e.g. existing TCP connections 69 // or credentials. 67 70 class QNetworkAccessCache: public QObject 68 71 { -
trunk/src/network/access/qnetworkaccesscachebackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 53 53 QNetworkAccessCacheBackend::QNetworkAccessCacheBackend() 54 54 : QNetworkAccessBackend() 55 , device(0) 55 56 { 56 57 } … … 86 87 setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute)); 87 88 setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true); 89 90 // set the raw headers 91 QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders(); 92 QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(), 93 end = rawHeaders.constEnd(); 94 for ( ; it != end; ++it) 95 setRawHeader(it->first, it->second); 96 97 // handle a possible redirect 98 QVariant redirectionTarget = attributes.value(QNetworkRequest::RedirectionTargetAttribute); 99 if (redirectionTarget.isValid()) { 100 setAttribute(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); 101 redirectionRequested(redirectionTarget.toUrl()); 102 } 88 103 89 104 // signal we're open -
trunk/src/network/access/qnetworkaccesscachebackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qnetworkaccessdatabackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 118 118 emit metaDataChanged(); 119 119 120 writeDownstreamData(payload); 120 QByteDataBuffer list; 121 list.append(payload); 122 payload.clear(); // important because of implicit sharing! 123 writeDownstreamData(list); 124 121 125 finished(); 122 126 return; -
trunk/src/network/access/qnetworkaccessdatabackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qnetworkaccessdebugpipebackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 42 42 #include "qnetworkaccessdebugpipebackend_p.h" 43 43 #include "QtCore/qdatastream.h" 44 #include <QCoreApplication> 45 #include "private/qnoncontiguousbytedevice_p.h" 44 46 45 47 QT_BEGIN_NAMESPACE … … 50 52 ReadBufferSize = 16384, 51 53 WriteBufferSize = ReadBufferSize 52 };53 54 struct QNetworkAccessDebugPipeBackend::DataPacket55 {56 QList<QPair<QByteArray, QByteArray> > headers;57 QByteArray data;58 54 }; 59 55 … … 80 76 81 77 QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend() 82 : incomingPacketSize(0), bareProtocol(false) 78 : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false), 79 hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0) 83 80 { 84 81 } … … 86 83 QNetworkAccessDebugPipeBackend::~QNetworkAccessDebugPipeBackend() 87 84 { 85 // this is signals disconnect, not network! 88 86 socket.disconnect(this); // we're not interested in the signals at this point 89 87 } … … 93 91 socket.connectToHost(url().host(), url().port(12345)); 94 92 socket.setReadBufferSize(ReadBufferSize); 93 94 // socket ready read -> we can push from socket to downstream 95 95 connect(&socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); 96 connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));97 96 connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError())); 98 97 connect(&socket, SIGNAL(disconnected()), SLOT(socketDisconnected())); 98 connect(&socket, SIGNAL(connected()), SLOT(socketConnected())); 99 // socket bytes written -> we can push more from upstream to socket 100 connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64))); 99 101 100 102 bareProtocol = url().queryItemValue(QLatin1String("bare")) == QLatin1String("1"); 101 103 102 if (!bareProtocol) { 103 // "Handshake": 104 // send outgoing metadata and the URL being requested 105 DataPacket packet; 106 //packet.metaData = request().metaData(); 107 packet.data = url().toEncoded(); 108 send(packet); 109 } 104 if (operation() == QNetworkAccessManager::PutOperation) { 105 uploadByteDevice = createUploadByteDevice(); 106 QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); 107 QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); 108 } 109 } 110 111 void QNetworkAccessDebugPipeBackend::socketReadyRead() 112 { 113 pushFromSocketToDownstream(); 114 } 115 116 void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() 117 { 118 pushFromSocketToDownstream(); 119 } 120 121 void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) 122 { 123 pushFromUpstreamToSocket(); 124 } 125 126 void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot() 127 { 128 pushFromUpstreamToSocket(); 129 } 130 131 void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream() 132 { 133 QByteArray buffer; 134 135 if (socket.state() == QAbstractSocket::ConnectingState) { 136 return; 137 } 138 139 forever { 140 if (hasDownloadFinished) 141 return; 142 143 buffer.resize(ReadBufferSize); 144 qint64 haveRead = socket.read(buffer.data(), ReadBufferSize); 145 146 if (haveRead == -1) { 147 hasDownloadFinished = true; 148 // this ensures a good last downloadProgress is emitted 149 setHeader(QNetworkRequest::ContentLengthHeader, QVariant()); 150 possiblyFinish(); 151 break; 152 } else if (haveRead == 0) { 153 break; 154 } else { 155 // have read something 156 buffer.resize(haveRead); 157 bytesDownloaded += haveRead; 158 159 QByteDataBuffer list; 160 list.append(buffer); 161 buffer.clear(); // important because of implicit sharing! 162 writeDownstreamData(list); 163 } 164 } 165 } 166 167 void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket() 168 { 169 // FIXME 170 if (operation() == QNetworkAccessManager::PutOperation) { 171 if (hasUploadFinished) 172 return; 173 174 forever { 175 if (socket.bytesToWrite() >= WriteBufferSize) 176 return; 177 178 qint64 haveRead; 179 const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead); 180 if (haveRead == -1) { 181 // EOF 182 hasUploadFinished = true; 183 emitReplyUploadProgress(bytesUploaded, bytesUploaded); 184 possiblyFinish(); 185 break; 186 } else if (haveRead == 0 || readPointer == 0) { 187 // nothing to read right now, we will be called again later 188 break; 189 } else { 190 qint64 haveWritten; 191 haveWritten = socket.write(readPointer, haveRead); 192 193 if (haveWritten < 0) { 194 // write error! 195 QString msg = QCoreApplication::translate("QNetworkAccessDebugPipeBackend", "Write error writing to %1: %2") 196 .arg(url().toString(), socket.errorString()); 197 error(QNetworkReply::ProtocolFailure, msg); 198 finished(); 199 return; 200 } else { 201 uploadByteDevice->advanceReadPointer(haveWritten); 202 bytesUploaded += haveWritten; 203 emitReplyUploadProgress(bytesUploaded, -1); 204 } 205 206 //QCoreApplication::processEvents(); 207 208 } 209 } 210 } 211 } 212 213 void QNetworkAccessDebugPipeBackend::possiblyFinish() 214 { 215 if (hasEverythingFinished) 216 return; 217 hasEverythingFinished = true; 218 219 if ((operation() == QNetworkAccessManager::GetOperation) && hasDownloadFinished) { 220 socket.close(); 221 finished(); 222 } else if ((operation() == QNetworkAccessManager::PutOperation) && hasUploadFinished) { 223 socket.close(); 224 finished(); 225 } 226 227 110 228 } 111 229 112 230 void QNetworkAccessDebugPipeBackend::closeDownstreamChannel() 113 231 { 114 if (operation() == QNetworkAccessManager::GetOperation) 115 socket.disconnectFromHost(); 116 } 117 118 void QNetworkAccessDebugPipeBackend::closeUpstreamChannel() 119 { 120 if (operation() == QNetworkAccessManager::PutOperation) 121 socket.disconnectFromHost(); 122 else if (operation() == QNetworkAccessManager::PostOperation) { 123 send(DataPacket()); 124 } 125 } 126 127 bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) 128 { 129 readyReadEmitted = false; 130 if (socket.bytesAvailable()) { 131 socketReadyRead(); 132 if (readyReadEmitted) 133 return true; 134 } 135 socket.waitForReadyRead(ms); 136 return readyReadEmitted; 137 } 138 139 bool QNetworkAccessDebugPipeBackend::waitForUpstreamBytesWritten(int ms) 140 { 141 bytesWrittenEmitted = false; 142 upstreamReadyRead(); 143 if (bytesWrittenEmitted) 144 return true; 145 146 socket.waitForBytesWritten(ms); 147 return bytesWrittenEmitted; 148 } 149 150 void QNetworkAccessDebugPipeBackend::upstreamReadyRead() 151 { 152 int maxWrite = WriteBufferSize - socket.bytesToWrite(); 153 if (maxWrite <= 0) 154 return; // can't write yet, wait for the socket to write 155 156 if (bareProtocol) { 157 QByteArray data = readUpstream(); 158 if (data.isEmpty()) 159 return; 160 161 socket.write(data); 162 upstreamBytesConsumed(data.size()); 163 bytesWrittenEmitted = true; 164 return; 165 } 166 167 DataPacket packet; 168 packet.data = readUpstream(); 169 if (packet.data.isEmpty()) 170 return; // we'll be called again when there's data 171 if (packet.data.size() > maxWrite) 172 packet.data.truncate(maxWrite); 173 174 if (!send(packet)) { 175 QString msg = QObject::tr("Write error writing to %1: %2") 176 .arg(url().toString(), socket.errorString()); 177 error(QNetworkReply::ProtocolFailure, msg); 178 179 finished(); 180 return; 181 } 182 upstreamBytesConsumed(packet.data.size()); 183 bytesWrittenEmitted = true; 184 } 185 186 void QNetworkAccessDebugPipeBackend::downstreamReadyWrite() 187 { 188 socketReadyRead(); 189 } 190 191 void QNetworkAccessDebugPipeBackend::socketReadyRead() 192 { 193 if (bareProtocol) { 194 qint64 bytesToRead = socket.bytesAvailable(); 195 if (bytesToRead) { 196 QByteArray buffer; 197 buffer.resize(bytesToRead); 198 qint64 bytesRead = socket.read(buffer.data(), bytesToRead); 199 if (bytesRead < bytesToRead) 200 buffer.truncate(bytesRead); 201 writeDownstreamData(buffer); 202 readyReadEmitted = true; 203 } 204 return; 205 } 206 207 while (canReceive() && 208 (socket.state() == QAbstractSocket::UnconnectedState || nextDownstreamBlockSize())) { 209 DataPacket packet; 210 if (receive(packet)) { 211 if (!packet.headers.isEmpty()) { 212 QList<QPair<QByteArray, QByteArray> >::ConstIterator 213 it = packet.headers.constBegin(), 214 end = packet.headers.constEnd(); 215 for ( ; it != end; ++it) 216 setRawHeader(it->first, it->second); 217 metaDataChanged(); 218 } 219 220 if (!packet.data.isEmpty()) { 221 writeDownstreamData(packet.data); 222 readyReadEmitted = true; 223 } 224 225 if (packet.headers.isEmpty() && packet.data.isEmpty()) { 226 // it's an eof 227 socket.close(); 228 readyReadEmitted = true; 229 } 230 } else { 231 // got an error 232 QString msg = QObject::tr("Read error reading from %1: %2") 233 .arg(url().toString(), socket.errorString()); 234 error(QNetworkReply::ProtocolFailure, msg); 235 236 finished(); 237 return; 238 } 239 } 240 } 241 242 void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64) 243 { 244 upstreamReadyRead(); 245 } 232 qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());; 233 //if (operation() == QNetworkAccessManager::GetOperation) 234 // socket.disconnectFromHost(); 235 } 236 246 237 247 238 void QNetworkAccessDebugPipeBackend::socketError() 248 239 { 240 qWarning("QNetworkAccessDebugPipeBackend::socketError() %d",socket.error()); 249 241 QNetworkReply::NetworkError code; 250 242 switch (socket.error()) { … … 270 262 void QNetworkAccessDebugPipeBackend::socketDisconnected() 271 263 { 272 socketReadyRead(); 273 if (incomingPacketSize == 0 && socket.bytesToWrite() == 0) { 264 pushFromSocketToDownstream(); 265 266 if (socket.bytesToWrite() == 0) { 274 267 // normal close 275 finished();276 268 } else { 277 269 // abnormal close … … 279 271 .arg(url().toString()); 280 272 error(QNetworkReply::RemoteHostClosedError, msg); 281 282 273 finished(); 283 274 } 284 275 } 285 276 286 bool QNetworkAccessDebugPipeBackend::send(const DataPacket &packet) 287 { 288 QByteArray ba; 289 { 290 QDataStream stream(&ba, QIODevice::WriteOnly); 291 stream.setVersion(QDataStream::Qt_4_4); 292 293 stream << packet.headers << packet.data; 294 } 295 296 qint32 outgoingPacketSize = ba.size(); 297 qint64 written = socket.write((const char*)&outgoingPacketSize, sizeof outgoingPacketSize); 298 written += socket.write(ba); 299 return quint64(written) == (outgoingPacketSize + sizeof outgoingPacketSize); 300 } 301 302 bool QNetworkAccessDebugPipeBackend::receive(DataPacket &packet) 303 { 304 if (!canReceive()) 305 return false; 306 307 // canReceive() does the setting up for us 308 Q_ASSERT(socket.bytesAvailable() >= incomingPacketSize); 309 QByteArray incomingPacket = socket.read(incomingPacketSize); 310 QDataStream stream(&incomingPacket, QIODevice::ReadOnly); 311 stream.setVersion(QDataStream::Qt_4_4); 312 stream >> packet.headers >> packet.data; 313 314 // reset for next packet: 315 incomingPacketSize = 0; 316 socket.setReadBufferSize(ReadBufferSize); 317 return true; 318 } 319 320 bool QNetworkAccessDebugPipeBackend::canReceive() 321 { 322 if (incomingPacketSize == 0) { 323 // read the packet size 324 if (quint64(socket.bytesAvailable()) >= sizeof incomingPacketSize) 325 socket.read((char*)&incomingPacketSize, sizeof incomingPacketSize); 326 else 327 return false; 328 } 329 330 if (incomingPacketSize == 0) { 331 QString msg = QObject::tr("Protocol error: packet of size 0 received"); 332 error(QNetworkReply::ProtocolFailure, msg); 333 finished(); 334 335 socket.blockSignals(true); 336 socket.abort(); 337 socket.blockSignals(false); 338 return false; 339 } 340 341 return socket.bytesAvailable() >= incomingPacketSize; 277 void QNetworkAccessDebugPipeBackend::socketConnected() 278 { 279 } 280 281 bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms) 282 { 283 Q_UNUSED(ms); 284 qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()"); 285 return false; 342 286 } 343 287 -
trunk/src/network/access/qnetworkaccessdebugpipebackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 67 67 Q_OBJECT 68 68 public: 69 struct DataPacket;70 69 QNetworkAccessDebugPipeBackend(); 71 70 virtual ~QNetworkAccessDebugPipeBackend(); … … 73 72 virtual void open(); 74 73 virtual void closeDownstreamChannel(); 75 virtual void closeUpstreamChannel();76 74 virtual bool waitForDownstreamReadyRead(int msecs); 77 virtual bool waitForUpstreamBytesWritten(int msecs);78 75 79 virtual void upstreamReadyRead();80 76 virtual void downstreamReadyWrite(); 81 77 78 protected: 79 void pushFromSocketToDownstream(); 80 void pushFromUpstreamToSocket(); 81 void possiblyFinish(); 82 QNonContiguousByteDevice *uploadByteDevice; 83 82 84 private slots: 85 void uploadReadyReadSlot(); 83 86 void socketReadyRead(); 84 87 void socketBytesWritten(qint64 bytes); 85 88 void socketError(); 86 89 void socketDisconnected(); 90 void socketConnected(); 87 91 88 92 private: 89 93 QTcpSocket socket; 90 qint32 incomingPacketSize;91 bool readyReadEmitted;92 bool bytesWrittenEmitted;93 94 bool bareProtocol; 95 bool hasUploadFinished; 96 bool hasDownloadFinished; 97 bool hasEverythingFinished; 94 98 95 bool send(const DataPacket &packet); 96 bool canReceive(); 97 bool receive(DataPacket &packet); 99 qint64 bytesDownloaded; 100 qint64 bytesUploaded; 98 101 }; 99 102 -
trunk/src/network/access/qnetworkaccessfilebackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 44 44 #include "qurlinfo.h" 45 45 #include "qdir.h" 46 #include "private/qnoncontiguousbytedevice_p.h" 46 47 47 48 #include <QtCore/QCoreApplication> … … 78 79 79 80 QNetworkAccessFileBackend::QNetworkAccessFileBackend() 80 : totalBytes(0)81 : uploadByteDevice(0), totalBytes(0), hasUploadFinished(false) 81 82 { 82 83 } … … 109 110 if (fileName.isEmpty()) { 110 111 if (url.scheme() == QLatin1String("qrc")) 111 fileName = QLatin1 String(":") + url.path();112 fileName = QLatin1Char(':') + url.path(); 112 113 else 113 114 fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery); … … 127 128 case QNetworkAccessManager::PutOperation: 128 129 mode = QIODevice::WriteOnly | QIODevice::Truncate; 130 uploadByteDevice = createUploadByteDevice(); 131 QObject::connect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot())); 132 QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection); 129 133 break; 130 134 default: … … 153 157 } 154 158 159 void QNetworkAccessFileBackend::uploadReadyReadSlot() 160 { 161 if (hasUploadFinished) 162 return; 163 164 forever { 165 qint64 haveRead; 166 const char *readPointer = uploadByteDevice->readPointer(-1, haveRead); 167 if (haveRead == -1) { 168 // EOF 169 hasUploadFinished = true; 170 file.flush(); 171 file.close(); 172 finished(); 173 break; 174 } else if (haveRead == 0 || readPointer == 0) { 175 // nothing to read right now, we will be called again later 176 break; 177 } else { 178 qint64 haveWritten; 179 haveWritten = file.write(readPointer, haveRead); 180 181 if (haveWritten < 0) { 182 // write error! 183 QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2") 184 .arg(url().toString(), file.errorString()); 185 error(QNetworkReply::ProtocolFailure, msg); 186 187 finished(); 188 return; 189 } else { 190 uploadByteDevice->advanceReadPointer(haveWritten); 191 } 192 193 194 file.flush(); 195 } 196 } 197 } 198 155 199 void QNetworkAccessFileBackend::closeDownstreamChannel() 156 200 { 157 201 if (operation() == QNetworkAccessManager::GetOperation) { 158 202 file.close(); 159 //downstreamChannelClosed();160 }161 }162 163 void QNetworkAccessFileBackend::closeUpstreamChannel()164 {165 if (operation() == QNetworkAccessManager::PutOperation) {166 file.close();167 finished();168 203 } 169 204 } … … 173 208 Q_ASSERT(operation() == QNetworkAccessManager::GetOperation); 174 209 return readMoreFromFile(); 175 }176 177 bool QNetworkAccessFileBackend::waitForUpstreamBytesWritten(int)178 {179 Q_ASSERT_X(false, "QNetworkAccessFileBackend::waitForUpstreamBytesWritten",180 "This function should never have been called, since there is never anything "181 "left to be written!");182 return false;183 }184 185 void QNetworkAccessFileBackend::upstreamReadyRead()186 {187 Q_ASSERT_X(operation() == QNetworkAccessManager::PutOperation, "QNetworkAccessFileBackend",188 "We're being told to upload data but operation isn't PUT!");189 190 // there's more data to be written to the file191 while (upstreamBytesAvailable()) {192 // write everything and let QFile handle it193 int written = file.write(readUpstream());194 195 if (written < 0) {196 // write error!197 QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Write error writing to %1: %2")198 .arg(url().toString(), file.errorString());199 error(QNetworkReply::ProtocolFailure, msg);200 201 finished();202 return;203 }204 205 // successful write206 file.flush();207 upstreamBytesConsumed(written);208 }209 210 } 210 211 … … 263 264 data.resize(actuallyRead); 264 265 totalBytes += actuallyRead; 265 writeDownstreamData(data); 266 267 QByteDataBuffer list; 268 list.append(data); 269 data.clear(); // important because of implicit sharing! 270 writeDownstreamData(list); 266 271 } 267 272 return true; -
trunk/src/network/access/qnetworkaccessfilebackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 63 63 class QNetworkAccessFileBackend: public QNetworkAccessBackend 64 64 { 65 Q_OBJECT 65 66 public: 66 67 QNetworkAccessFileBackend(); … … 69 70 virtual void open(); 70 71 virtual void closeDownstreamChannel(); 71 virtual void closeUpstreamChannel();72 72 virtual bool waitForDownstreamReadyRead(int msecs); 73 virtual bool waitForUpstreamBytesWritten(int msecs);74 73 75 virtual void upstreamReadyRead();76 74 virtual void downstreamReadyWrite(); 77 75 76 public slots: 77 void uploadReadyReadSlot(); 78 protected: 79 QNonContiguousByteDevice *uploadByteDevice; 78 80 private: 79 81 QFile file; 80 82 qint64 totalBytes; 83 bool hasUploadFinished; 81 84 82 85 bool loadFileInfo(); -
trunk/src/network/access/qnetworkaccessftpbackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 43 43 #include "qnetworkaccessmanager_p.h" 44 44 #include "QtNetwork/qauthenticator.h" 45 #include "private/qnoncontiguousbytedevice_p.h" 45 46 46 47 #ifndef QT_NO_FTP … … 82 83 } 83 84 84 class QNetworkAccessFtpIODevice: public QIODevice 85 { 86 //Q_OBJECT 87 public: 88 QNetworkAccessFtpBackend *backend; 89 bool eof; 90 91 inline QNetworkAccessFtpIODevice(QNetworkAccessFtpBackend *parent) 92 : QIODevice(parent), backend(parent), eof(false) 93 { open(ReadOnly); } 94 95 bool isSequential() const { return true; } 96 bool atEnd() const { return backend->upstreamBytesAvailable() == 0; } 97 98 qint64 bytesAvailable() const { return backend->upstreamBytesAvailable(); } 99 qint64 bytesToWrite() const { return backend->downstreamBytesToConsume(); } 100 protected: 101 qint64 readData(char *data, qint64 maxlen) 102 { 103 const QByteArray toSend = backend->readUpstream(); 104 maxlen = qMin<qint64>(maxlen, toSend.size()); 105 if (!maxlen) 106 return eof ? -1 : 0; 107 108 backend->upstreamBytesConsumed(maxlen); 109 memcpy(data, toSend.constData(), maxlen); 110 return maxlen; 111 } 112 113 qint64 writeData(const char *, qint64) 114 { return -1; } 115 116 friend class QNetworkAccessFtpBackend; 117 }; 118 119 class QNetworkAccessFtpFtp: public QFtp, public QNetworkAccessCache::CacheableObject 85 class QNetworkAccessCachedFtpConnection: public QFtp, public QNetworkAccessCache::CacheableObject 120 86 { 121 87 // Q_OBJECT 122 88 public: 123 QNetworkAccess FtpFtp()89 QNetworkAccessCachedFtpConnection() 124 90 { 125 91 setExpires(true); … … 183 149 state = LoggingIn; 184 150 185 QNetworkAccessCache* cache = QNetworkAccessManagerPrivate::getCache(this);151 QNetworkAccessCache* objectCache = QNetworkAccessManagerPrivate::getObjectCache(this); 186 152 QByteArray cacheKey = makeCacheKey(url); 187 if (! cache->requestEntry(cacheKey, this,153 if (!objectCache->requestEntry(cacheKey, this, 188 154 SLOT(ftpConnectionReady(QNetworkAccessCache::CacheableObject*)))) { 189 ftp = new QNetworkAccess FtpFtp;155 ftp = new QNetworkAccessCachedFtpConnection; 190 156 #ifndef QT_NO_NETWORKPROXY 191 157 if (proxy.type() == QNetworkProxy::FtpCachingProxy) … … 195 161 ftp->login(url.userName(), url.password()); 196 162 197 cache->addEntry(cacheKey, ftp);163 objectCache->addEntry(cacheKey, ftp); 198 164 ftpConnectionReady(ftp); 199 165 } 200 166 201 uploadDevice = new QNetworkAccessFtpIODevice(this); 167 // Put operation 168 if (operation() == QNetworkAccessManager::PutOperation) { 169 uploadDevice = QNonContiguousByteDeviceFactory::wrap(createUploadByteDevice()); 170 uploadDevice->setParent(this); 171 } 202 172 } 203 173 … … 213 183 } 214 184 215 void QNetworkAccessFtpBackend::closeUpstreamChannel()216 {217 if (operation() == QNetworkAccessManager::PutOperation) {218 Q_ASSERT(uploadDevice);219 uploadDevice->eof = true;220 if (!upstreamBytesAvailable())221 emit uploadDevice->readyRead();222 }223 }224 225 185 bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms) 226 186 { … … 240 200 } 241 201 242 bool QNetworkAccessFtpBackend::waitForUpstreamBytesWritten(int ms)243 {244 Q_UNUSED(ms);245 qCritical("QNetworkAccess: FTP backend does not support waitForBytesWritten()");246 return false;247 }248 249 void QNetworkAccessFtpBackend::upstreamReadyRead()250 {251 // uh... how does QFtp operate?252 }253 254 202 void QNetworkAccessFtpBackend::downstreamReadyWrite() 255 203 { … … 260 208 void QNetworkAccessFtpBackend::ftpConnectionReady(QNetworkAccessCache::CacheableObject *o) 261 209 { 262 ftp = static_cast<QNetworkAccess FtpFtp*>(o);210 ftp = static_cast<QNetworkAccessCachedFtpConnection *>(o); 263 211 connect(ftp, SIGNAL(done(bool)), SLOT(ftpDone())); 264 212 connect(ftp, SIGNAL(rawCommandReply(int,QString)), SLOT(ftpRawCommandReply(int,QString))); … … 280 228 281 229 QByteArray key = makeCacheKey(url()); 282 QNetworkAccessManagerPrivate::get Cache(this)->releaseEntry(key);230 QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key); 283 231 284 232 ftp = 0; … … 331 279 // we're not connected, so remove the cache entry: 332 280 QByteArray key = makeCacheKey(url()); 333 QNetworkAccessManagerPrivate::get Cache(this)->removeEntry(key);281 QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key); 334 282 335 283 disconnect(ftp, 0, this, 0); … … 408 356 void QNetworkAccessFtpBackend::ftpReadyRead() 409 357 { 410 writeDownstreamData(ftp->readAll()); 358 QByteArray data = ftp->readAll(); 359 QByteDataBuffer list; 360 list.append(data); 361 data.clear(); // important because of implicit sharing! 362 writeDownstreamData(list); 411 363 } 412 364 -
trunk/src/network/access/qnetworkaccessftpbackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 67 67 68 68 class QNetworkAccessFtpIODevice; 69 class QNetworkAccess FtpFtp;69 class QNetworkAccessCachedFtpConnection; 70 70 71 71 class QNetworkAccessFtpBackend: public QNetworkAccessBackend … … 88 88 virtual void open(); 89 89 virtual void closeDownstreamChannel(); 90 virtual void closeUpstreamChannel();91 90 virtual bool waitForDownstreamReadyRead(int msecs); 92 virtual bool waitForUpstreamBytesWritten(int msecs);93 91 94 virtual void upstreamReadyRead();95 92 virtual void downstreamReadyWrite(); 96 93 … … 105 102 private: 106 103 friend class QNetworkAccessFtpIODevice; 107 QPointer<QNetworkAccess FtpFtp> ftp;108 Q NetworkAccessFtpIODevice *uploadDevice;104 QPointer<QNetworkAccessCachedFtpConnection> ftp; 105 QIODevice *uploadDevice; 109 106 qint64 totalBytes; 110 107 int helpId, sizeId, mdtmId; -
trunk/src/network/access/qnetworkaccesshttpbackend.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 213 213 case QNetworkAccessManager::HeadOperation: 214 214 case QNetworkAccessManager::PutOperation: 215 case QNetworkAccessManager::DeleteOperation: 215 216 break; 216 217 … … 243 244 case 404: // Not Found 244 245 code = QNetworkReply::ContentNotFoundError; 246 break; 247 248 case 405: // Method Not Allowed 249 code = QNetworkReply::ContentOperationNotPermittedError; 245 250 break; 246 251 … … 266 271 } 267 272 268 class QNetworkAccess HttpBackendCache: public QHttpNetworkConnection,273 class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection, 269 274 public QNetworkAccessCache::CacheableObject 270 275 { 271 276 // Q_OBJECT 272 277 public: 273 QNetworkAccess HttpBackendCache(const QString &hostName, quint16 port, bool encrypt)278 QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt) 274 279 : QHttpNetworkConnection(hostName, port, encrypt) 275 280 { … … 287 292 }; 288 293 289 class QNetworkAccessHttpBackendIODevice: public QIODevice290 {291 // Q_OBJECT292 public:293 bool eof;294 QNetworkAccessHttpBackendIODevice(QNetworkAccessHttpBackend *parent)295 : QIODevice(parent), eof(false)296 {297 setOpenMode(ReadOnly);298 }299 bool isSequential() const { return true; }300 qint64 bytesAvailable() const301 { return static_cast<QNetworkAccessHttpBackend *>(parent())->upstreamBytesAvailable(); }302 303 protected:304 virtual qint64 readData(char *buffer, qint64 maxlen)305 {306 qint64 ret = static_cast<QNetworkAccessHttpBackend *>(parent())->deviceReadData(buffer, maxlen);307 if (!ret && eof)308 return -1;309 return ret;310 }311 312 virtual qint64 writeData(const char *, qint64)313 {314 return -1; // cannot write315 }316 317 friend class QNetworkAccessHttpBackend;318 };319 320 294 QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() 321 295 : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0) 322 296 #ifndef QT_NO_OPENSSL 323 , pendingSslConfiguration(0), pendingIgnore SslErrors(false)297 , pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false) 324 298 #endif 325 299 { … … 338 312 { 339 313 if (http) { 314 // This is abut disconnecting signals, not about disconnecting TCP connections 340 315 disconnect(http, 0, this, 0); 341 QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getCache(this); 316 317 // Get the object cache that stores our QHttpNetworkConnection objects 318 QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this); 342 319 cache->releaseEntry(cacheKey); 343 320 } 344 321 322 // This is abut disconnecting signals, not about disconnecting TCP connections 345 323 if (httpReply) 346 324 disconnect(httpReply, 0, this, 0); … … 508 486 invalidateCache(); 509 487 httpRequest.setOperation(QHttpNetworkRequest::Post); 510 uploadDevice = new QNetworkAccessHttpBackendIODevice(this);488 httpRequest.setUploadByteDevice(createUploadByteDevice()); 511 489 break; 512 490 … … 514 492 invalidateCache(); 515 493 httpRequest.setOperation(QHttpNetworkRequest::Put); 516 uploadDevice = new QNetworkAccessHttpBackendIODevice(this); 494 httpRequest.setUploadByteDevice(createUploadByteDevice()); 495 break; 496 497 case QNetworkAccessManager::DeleteOperation: 498 invalidateCache(); 499 httpRequest.setOperation(QHttpNetworkRequest::Delete); 517 500 break; 518 501 … … 521 504 } 522 505 523 httpRequest.setData(uploadDevice);524 506 httpRequest.setUrl(url()); 525 507 … … 529 511 530 512 if (loadedFromCache) { 531 QNetworkAccessBackend::finished(); 513 // commented this out since it will be called later anyway 514 // by copyFinished() 515 //QNetworkAccessBackend::finished(); 532 516 return; // no need to send the request! :) 533 517 } 518 519 if (request().attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true) 520 httpRequest.setPipeliningAllowed(true); 534 521 535 522 httpReply = http->sendRequest(httpRequest); … … 538 525 if (pendingSslConfiguration) 539 526 httpReply->setSslConfiguration(*pendingSslConfiguration); 540 if (pendingIgnore SslErrors)527 if (pendingIgnoreAllSslErrors) 541 528 httpReply->ignoreSslErrors(); 529 httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList); 542 530 #endif 543 531 … … 603 591 // check if we have an open connection to this host 604 592 cacheKey = makeCacheKey(this, theProxy); 605 QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getCache(this); 606 if ((http = static_cast<QNetworkAccessHttpBackendCache *>(cache->requestEntryNow(cacheKey))) == 0) { 593 QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this); 594 // the http object is actually a QHttpNetworkConnection 595 http = static_cast<QNetworkAccessCachedHttpConnection *>(cache->requestEntryNow(cacheKey)); 596 if (http == 0) { 607 597 // no entry in cache; create an object 608 http = new QNetworkAccessHttpBackendCache(url.host(), url.port(), encrypt); 598 // the http object is actually a QHttpNetworkConnection 599 http = new QNetworkAccessCachedHttpConnection(url.host(), url.port(), encrypt); 609 600 610 601 #ifndef QT_NO_NETWORKPROXY … … 613 604 #endif 614 605 606 // cache the QHttpNetworkConnection corresponding to this cache key 615 607 cache->addEntry(cacheKey, http); 616 608 } … … 623 615 { 624 616 // this indicates that the user closed the stream while the reply isn't finished yet 625 }626 627 void QNetworkAccessHttpBackend::closeUpstreamChannel()628 {629 // this indicates that the user finished uploading the data for POST630 Q_ASSERT(uploadDevice);631 uploadDevice->eof = true;632 emit uploadDevice->readChannelFinished();633 617 } 634 618 … … 652 636 } 653 637 654 bool QNetworkAccessHttpBackend::waitForUpstreamBytesWritten(int msecs)655 {656 657 // ### FIXME: not implemented in QHttpNetworkAccess658 Q_UNUSED(msecs);659 qCritical("QNetworkAccess: HTTP backend does not support waitForBytesWritten()");660 return false;661 }662 663 void QNetworkAccessHttpBackend::upstreamReadyRead()664 {665 // There is more data available from the user to be uploaded666 // QHttpNetworkAccess implements the upload rate control:667 // we simply tell QHttpNetworkAccess that there is more data available668 // it'll pull from us when it can (through uploadDevice)669 670 Q_ASSERT(uploadDevice);671 emit uploadDevice->readyRead();672 }673 674 qint64 QNetworkAccessHttpBackend::deviceReadData(char *buffer, qint64 maxlen)675 {676 QByteArray toBeUploaded = readUpstream();677 if (toBeUploaded.isEmpty())678 return 0; // nothing to be uploaded679 680 maxlen = qMin<qint64>(maxlen, toBeUploaded.length());681 682 memcpy(buffer, toBeUploaded.constData(), maxlen);683 upstreamBytesConsumed(maxlen);684 return maxlen;685 }686 638 687 639 void QNetworkAccessHttpBackend::downstreamReadyWrite() … … 702 654 return; 703 655 704 // We implement the download rate control 705 // Don't read from QHttpNetworkAccess more than QNetworkAccessBackend wants 706 // One of the two functions above will be called when we can read again 707 708 qint64 bytesToRead = qBound<qint64>(0, httpReply->bytesAvailable(), nextDownstreamBlockSize()); 709 if (!bytesToRead) 710 return; 711 712 QByteArray data = httpReply->read(bytesToRead); 713 writeDownstreamData(data); 656 // We read possibly more than nextDownstreamBlockSize(), but 657 // this is not a critical thing since it is already in the 658 // memory anyway 659 660 QByteDataBuffer list; 661 662 while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0 && nextDownstreamBlockSize() > list.byteAmount()) { 663 QByteArray data = httpReply->readAny(); 664 list.append(data); 665 } 666 667 if (!list.isEmpty()) 668 writeDownstreamData(list); 714 669 } 715 670 … … 733 688 // once we call finished(), we won't have access to httpReply anymore 734 689 QSslConfiguration sslConfig = httpReply->sslConfiguration(); 735 if (pendingSslConfiguration) 690 if (pendingSslConfiguration) { 736 691 *pendingSslConfiguration = sslConfig; 737 else if (!sslConfig.isNull()) 738 pendingSslConfiguration = new QSslConfiguration(sslConfig); 692 } else if (!sslConfig.isNull()) { 693 QT_TRY { 694 pendingSslConfiguration = new QSslConfiguration(sslConfig); 695 } QT_CATCH(...) { 696 qWarning("QNetworkAccess: could not allocate a QSslConfiguration object for a SSL connection."); 697 } 698 } 739 699 #endif 740 700 … … 762 722 void QNetworkAccessHttpBackend::replyHeaderChanged() 763 723 { 724 setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, httpReply->isPipeliningUsed()); 725 764 726 // reconstruct the HTTP header 765 727 QList<QPair<QByteArray, QByteArray> > headerMap = httpReply->header(); … … 771 733 QByteArray value = rawHeader(it->first); 772 734 if (!value.isEmpty()) { 773 if ( it->first.toLower() == "set-cookie")735 if (qstricmp(it->first.constData(), "set-cookie") == 0) 774 736 value += "\n"; 775 737 else … … 905 867 checkForRedirect(status); 906 868 907 writeDownstreamData(contents); 869 emit metaDataChanged(); 870 871 // invoke this asynchronously, else Arora/QtDemoBrowser don't like cached downloads 872 // see task 250221 / 251801 873 qRegisterMetaType<QIODevice*>("QIODevice*"); 874 QMetaObject::invokeMethod(this, "writeDownstreamData", Qt::QueuedConnection, Q_ARG(QIODevice*, contents)); 875 876 908 877 #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) 909 878 qDebug() << "Successfully sent cache:" << url() << contents->size() << "bytes"; … … 926 895 httpReply->ignoreSslErrors(); 927 896 else 928 pendingIgnoreSslErrors = true; 897 pendingIgnoreAllSslErrors = true; 898 } 899 900 void QNetworkAccessHttpBackend::ignoreSslErrors(const QList<QSslError> &errors) 901 { 902 if (httpReply) { 903 httpReply->ignoreSslErrors(errors); 904 } else { 905 // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) 906 // is called before QNetworkAccessManager::get() (or post(), etc.) 907 pendingIgnoreSslErrorsList = errors; 908 } 929 909 } 930 910 … … 972 952 continue; 973 953 954 // for 4.6.0, we were planning to not store the date header in the 955 // cached resource; through that we planned to reduce the number 956 // of writes to disk when using a QNetworkDiskCache (i.e. don't 957 // write to disk when only the date changes). 958 // However, without the date we cannot calculate the age of the page 959 // anymore. Consider a proper fix of that problem for 4.6.1. 960 //if (header == "date") 961 //continue; 962 974 963 // Don't store Warning 1xx headers 975 964 if (header == "warning") { … … 1037 1026 metaData.setLastModified(QNetworkHeadersPrivate::fromHttpDate(it->second)); 1038 1027 1039 bool canDiskCache = true; // Everything defaults to being cacheable on disk 1040 1041 // 14.32 1042 // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client 1043 // had sent "Cache-Control: no-cache". 1044 it = cacheHeaders.findRawHeader("pragma"); 1045 if (it != cacheHeaders.rawHeaders.constEnd() 1046 && it->second == "no-cache") 1028 bool canDiskCache; 1029 // only cache GET replies by default, all other replies (POST, PUT, DELETE) 1030 // are not cacheable by default (according to RFC 2616 section 9) 1031 if (httpReply->request().operation() == QHttpNetworkRequest::Get) { 1032 1033 canDiskCache = true; 1034 // 14.32 1035 // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the client 1036 // had sent "Cache-Control: no-cache". 1037 it = cacheHeaders.findRawHeader("pragma"); 1038 if (it != cacheHeaders.rawHeaders.constEnd() 1039 && it->second == "no-cache") 1040 canDiskCache = false; 1041 1042 // HTTP/1.1. Check the Cache-Control header 1043 if (cacheControl.contains("no-cache")) 1044 canDiskCache = false; 1045 else if (cacheControl.contains("no-store")) 1046 canDiskCache = false; 1047 1048 // responses to POST might be cacheable 1049 } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) { 1050 1047 1051 canDiskCache = false; 1048 1049 // HTTP/1.1. Check the Cache-Control header 1050 if (cacheControl.contains("no-cache")) 1052 // some pages contain "expires:" and "cache-control: no-cache" field, 1053 // so we only might cache POST requests if we get "cache-control: max-age ..." 1054 if (cacheControl.contains("max-age")) 1055 canDiskCache = true; 1056 1057 // responses to PUT and DELETE are not cacheable 1058 } else { 1051 1059 canDiskCache = false; 1052 else if (cacheControl.contains("no-store")) 1053 canDiskCache = false; 1060 } 1054 1061 1055 1062 metaData.setSaveToDisk(canDiskCache); -
trunk/src/network/access/qnetworkaccesshttpbackend_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 67 67 QT_BEGIN_NAMESPACE 68 68 69 class QNetworkAccess HttpBackendCache;69 class QNetworkAccessCachedHttpConnection; 70 70 71 71 class QNetworkAccessHttpBackendIODevice; … … 80 80 virtual void open(); 81 81 virtual void closeDownstreamChannel(); 82 virtual void closeUpstreamChannel();83 82 virtual bool waitForDownstreamReadyRead(int msecs); 84 virtual bool waitForUpstreamBytesWritten(int msecs);85 83 86 virtual void upstreamReadyRead();87 84 virtual void downstreamReadyWrite(); 88 85 virtual void copyFinished(QIODevice *); 89 86 #ifndef QT_NO_OPENSSL 90 87 virtual void ignoreSslErrors(); 88 virtual void ignoreSslErrors(const QList<QSslError> &errors); 91 89 92 90 virtual void fetchSslConfiguration(QSslConfiguration &configuration) const; … … 96 94 97 95 qint64 deviceReadData(char *buffer, qint64 maxlen); 96 97 // we return true since HTTP needs to send PUT/POST data again after having authenticated 98 bool needsResetableUploadData() { return true; } 98 99 99 100 private slots: … … 107 108 private: 108 109 QHttpNetworkReply *httpReply; 109 QPointer<QNetworkAccess HttpBackendCache> http;110 QPointer<QNetworkAccessCachedHttpConnection> http; 110 111 QByteArray cacheKey; 111 QNetworkAccessHttpBackendIODevice *uploadDevice; 112 QNetworkAccessBackendUploadIODevice *uploadDevice; 113 112 114 #ifndef QT_NO_OPENSSL 113 115 QSslConfiguration *pendingSslConfiguration; 114 bool pendingIgnoreSslErrors; 116 bool pendingIgnoreAllSslErrors; 117 QList<QSslError> pendingIgnoreSslErrorsList; 115 118 #endif 116 119 … … 123 126 void readFromHttp(); 124 127 void checkForRedirect(const int statusCode); 125 126 friend class QNetworkAccessHttpBackendIODevice;127 128 }; 128 129 -
trunk/src/network/access/qnetworkaccessmanager.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 53 53 #include "qnetworkaccessdatabackend_p.h" 54 54 #include "qnetworkaccessdebugpipebackend_p.h" 55 #include "qfilenetworkreply_p.h" 55 56 56 57 #include "QtCore/qbuffer.h" … … 96 97 \class QNetworkAccessManager 97 98 \brief The QNetworkAccessManager class allows the application to 98 postnetwork requests and receive replies99 send network requests and receive replies 99 100 \since 4.4 100 101 102 \ingroup network 101 103 \inmodule QtNetwork 102 104 \reentrant … … 113 115 QNetworkReply object. The returned object is used to obtain any data 114 116 returned in response to the corresponding request. 115 the reply to is where most of the signals as well116 as the downloaded data are posted.117 117 118 118 A simple download off the network could be accomplished with: … … 123 123 as well as meta-data (headers, etc.). 124 124 125 \note The slot is responsible for deleting the object at that point. 125 \note After the request has finished, it is the responsibility of the user 126 to delete the QNetworkReply object at an appropriate time. Do not directly 127 delete it inside the slot connected to finished(). You can use the 128 deleteLater() function. 126 129 127 130 A more involved example, assuming the manager is already existent, … … 148 151 \value PostOperation send the contents of an HTML form for 149 152 processing via HTTP POST (created with post()) 153 154 \value DeleteOperation delete contents operation (created with 155 deleteResource()) 150 156 151 157 \omitvalue UnknownOperation … … 200 206 See QNetworkReply::finished() for information on the status that 201 207 the object will be in. 208 209 \note Do not delete the \a reply object in the slot connected to this 210 signal. Use deleteLater(). 202 211 203 212 \sa QNetworkReply::finished(), QNetworkReply::error() … … 300 309 case QNetworkProxy::FtpCachingProxy: 301 310 key.setScheme(QLatin1String("proxy-ftp")); 311 break; 302 312 303 313 case QNetworkProxy::DefaultProxy: … … 478 488 delete d->networkCache; 479 489 d->networkCache = cache; 480 d->networkCache->setParent(this); 490 if (d->networkCache) 491 d->networkCache->setParent(this); 481 492 } 482 493 } … … 538 549 539 550 /*! 540 This function is used to post a request to obtain the network541 headers for \a request. It takes its name after the HTTP request542 associated (HEAD). It returns a new QNetworkReply object which 543 will contain such headers.551 Posts a request to obtain the network headers for \a request 552 and returns a new QNetworkReply object which will contain such headers 553 554 The function is named after the HTTP request associated (HEAD). 544 555 */ 545 556 QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request) … … 549 560 550 561 /*! 551 This function is used to post a request to obtain the contents of 552 the target \a request. It will cause the contents to be 553 downloaded, along with the headers associated with it. It returns 554 a new QNetworkReply object opened for reading which emits its 555 QIODevice::readyRead() signal whenever new data arrives. 556 557 \sa post(), put() 562 Posts a request to obtain the contents of the target \a request 563 and returns a new QNetworkReply object opened for reading which emits the 564 \l{QIODevice::readyRead()}{readyRead()} signal whenever new data 565 arrives. 566 567 The contents as well as associated headers will be downloaded. 568 569 \sa post(), put(), deleteResource() 558 570 */ 559 571 QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request) … … 563 575 564 576 /*! 565 This function is used to send an HTTP POST request to the 566 destination specified by \a request. The contents of the \a data 577 Sends an HTTP POST request to the destination specified by \a request 578 and returns a new QNetworkReply object opened for reading that will 579 contain the reply sent by the server. The contents of the \a data 567 580 device will be uploaded to the server. 581 582 \a data must be open for reading and must remain valid until the 583 finished() signal is emitted for this reply. 584 585 \note Sending a POST request on protocols other than HTTP and 586 HTTPS is undefined and will probably fail. 587 588 \sa get(), put(), deleteResource() 589 */ 590 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data) 591 { 592 return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data)); 593 } 594 595 /*! 596 \overload 597 598 Sends the contents of the \a data byte array to the destination 599 specified by \a request. 600 */ 601 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data) 602 { 603 QBuffer *buffer = new QBuffer; 604 buffer->setData(data); 605 buffer->open(QIODevice::ReadOnly); 606 607 QNetworkReply *reply = post(request, buffer); 608 buffer->setParent(reply); 609 return reply; 610 } 611 612 /*! 613 Uploads the contents of \a data to the destination \a request and 614 returnes a new QNetworkReply object that will be open for reply. 568 615 569 616 \a data must be opened for reading when this function is called … … 571 618 this reply. 572 619 573 The returned QNetworkReply object will be open for reading and 574 will contain the reply sent by the server to the POST request. 575 576 Note: sending a POST request on protocols other than HTTP and 577 HTTPS is undefined and will probably fail. 578 579 \sa get(), put() 580 */ 581 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data) 582 { 583 return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data)); 620 Whether anything will be available for reading from the returned 621 object is protocol dependent. For HTTP, the server may send a 622 small HTML page indicating the upload was successful (or not). 623 Other protocols will probably have content in their replies. 624 625 \note For HTTP, this request will send a PUT request, which most servers 626 do not allow. Form upload mechanisms, including that of uploading 627 files through HTML forms, use the POST mechanism. 628 629 \sa get(), post() 630 */ 631 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data) 632 { 633 return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data)); 584 634 } 585 635 586 636 /*! 587 637 \overload 588 This function sends the contents of the \a data byte array to the589 destinationspecified by \a request.590 */ 591 QNetworkReply *QNetworkAccessManager::p ost(const QNetworkRequest &request, const QByteArray &data)638 Sends the contents of the \a data byte array to the destination 639 specified by \a request. 640 */ 641 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data) 592 642 { 593 643 QBuffer *buffer = new QBuffer; … … 595 645 buffer->open(QIODevice::ReadOnly); 596 646 597 QNetworkReply *reply = post(request, buffer);598 buffer->setParent(reply);599 return reply;600 }601 602 /*!603 This function is used to upload the contents of \a data to the604 destination \a request.605 606 \a data must be opened for reading when this function is called607 and must remain valid until the finished() signal is emitted for608 this reply.609 610 The returned QNetworkReply object will be open for reply, but611 whether anything will be available for reading is protocol612 dependent. For HTTP, the server may send a small HTML page613 indicating the upload was successful (or not). Other protocols614 will probably have content in their replies.615 616 For HTTP, this request will send a PUT request, which most servers617 do not allow. Form upload mechanisms, including that of uploading618 files through HTML forms, use the POST mechanism.619 620 \sa get(), post()621 */622 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)623 {624 return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));625 }626 627 /*!628 \overload629 This function sends the contents of the \a data byte array to the630 destination specified by \a request.631 */632 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)633 {634 QBuffer *buffer = new QBuffer;635 buffer->setData(data);636 buffer->open(QIODevice::ReadOnly);637 638 647 QNetworkReply *reply = put(request, buffer); 639 648 buffer->setParent(reply); 640 649 return reply; 650 } 651 652 /*! 653 \since 4.6 654 655 Sends a request to delete the resource identified by the URL of \a request. 656 657 \note This feature is currently available for HTTP only, performing an 658 HTTP DELETE request. 659 660 \sa get(), post(), put() 661 */ 662 QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request) 663 { 664 return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request)); 641 665 } 642 666 … … 659 683 { 660 684 Q_D(QNetworkAccessManager); 685 686 // fast path for GET on file:// URLs 687 // Also if the scheme is empty we consider it a file. 688 // The QNetworkAccessFileBackend will right now only be used 689 // for PUT or qrc:// 690 if (op == QNetworkAccessManager::GetOperation 691 && (req.url().scheme() == QLatin1String("file") 692 || req.url().scheme().isEmpty())) { 693 return new QFileNetworkReply(this, req); 694 } 695 661 696 QNetworkRequest request = req; 662 697 if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() && … … 686 721 } 687 722 688 // third step: setup the reply 723 // third step: find a backend 724 priv->backend = d->findBackend(op, request); 725 726 // fourth step: setup the reply 689 727 priv->setup(op, request, outgoingData); 690 if (request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt() !=691 QNetworkRequest::AlwaysNetwork)692 priv->setNetworkCache(d->networkCache);693 728 #ifndef QT_NO_NETWORKPROXY 694 729 QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url())); 695 730 priv->proxyList = proxyList; 696 731 #endif 697 698 // fourth step: find a backend699 priv->backend = d->findBackend(op, request);700 732 if (priv->backend) { 701 733 priv->backend->setParent(reply); … … 748 780 // keep the ugly hack in here 749 781 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this); 782 that->cookieJar = new QNetworkCookieJar(that->q_func()); 750 783 that->cookieJarCreated = true; 751 that->cookieJar = new QNetworkCookieJar(that->q_func());752 784 } 753 785 } … … 784 816 { 785 817 Q_Q(QNetworkAccessManager); 786 818 // ### FIXME Tracking of successful authentications 819 // This code is a bit broken right now for SOCKS authentication 820 // first request: proxyAuthenticationRequired gets emitted, credentials gets saved 821 // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true, 822 // proxyAuthenticationRequired gets emitted again 823 // possible solution: some tracking inside the authenticator 824 // or a new function proxyAuthenticationSucceeded(true|false) 787 825 if (proxy != backend->reply->lastProxyAuthentication) { 788 826 QNetworkAuthenticationCredential *cred = fetchCachedCredentials(proxy); … … 819 857 QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; 820 858 auth->insert(QString(), authenticator->user(), authenticator->password()); 821 cache.addEntry(cacheKey, auth); // replace the existing one, if there's any859 objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any 822 860 823 861 if (realm.isEmpty()) { … … 853 891 if (cacheKey.isEmpty()) 854 892 return 0; 855 if (! cache.hasEntry(cacheKey))893 if (!objectCache.hasEntry(cacheKey)) 856 894 return 0; 857 895 858 896 QNetworkAuthenticationCache *auth = 859 static_cast<QNetworkAuthenticationCache *>( cache.requestEntryNow(cacheKey));897 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); 860 898 QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString()); 861 cache.releaseEntry(cacheKey);899 objectCache.releaseEntry(cacheKey); 862 900 863 901 // proxy cache credentials always have exactly one item … … 900 938 do { 901 939 QByteArray cacheKey = authenticationKey(copy, realm); 902 if ( cache.hasEntry(cacheKey)) {940 if (objectCache.hasEntry(cacheKey)) { 903 941 QNetworkAuthenticationCache *auth = 904 static_cast<QNetworkAuthenticationCache *>( cache.requestEntryNow(cacheKey));942 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); 905 943 auth->insert(domain, authenticator->user(), authenticator->password()); 906 cache.releaseEntry(cacheKey);944 objectCache.releaseEntry(cacheKey); 907 945 } else { 908 946 QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; 909 947 auth->insert(domain, authenticator->user(), authenticator->password()); 910 cache.addEntry(cacheKey, auth);948 objectCache.addEntry(cacheKey, auth); 911 949 } 912 950 … … 942 980 943 981 QByteArray cacheKey = authenticationKey(url, realm); 944 if (! cache.hasEntry(cacheKey))982 if (!objectCache.hasEntry(cacheKey)) 945 983 return 0; 946 984 947 985 QNetworkAuthenticationCache *auth = 948 static_cast<QNetworkAuthenticationCache *>( cache.requestEntryNow(cacheKey));986 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); 949 987 QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path()); 950 cache.releaseEntry(cacheKey);988 objectCache.releaseEntry(cacheKey); 951 989 return cred; 952 990 } … … 954 992 void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) 955 993 { 956 manager->d_func()->cache.clear(); 994 manager->d_func()->objectCache.clear(); 995 } 996 997 QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() 998 { 957 999 } 958 1000 -
trunk/src/network/access/qnetworkaccessmanager.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 75 75 PutOperation, 76 76 PostOperation, 77 DeleteOperation, 77 78 78 79 UnknownOperation = 0 … … 101 102 QNetworkReply *put(const QNetworkRequest &request, QIODevice *data); 102 103 QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data); 104 QNetworkReply *deleteResource(const QNetworkRequest &request); 103 105 104 106 Q_SIGNALS: -
trunk/src/network/access/qnetworkaccessmanager_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 77 77 cookieJarCreated(false) 78 78 { } 79 ~QNetworkAccessManagerPrivate(); 79 80 80 81 void _q_replyFinished(); … … 99 100 QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request); 100 101 102 // this is the cache for storing downloaded files 101 103 QAbstractNetworkCache *networkCache; 104 102 105 QNetworkCookieJar *cookieJar; 103 106 104 QNetworkAccessCache cache; 107 105 108 #ifndef QT_NO_NETWORKPROXY 106 109 QNetworkProxy proxy; … … 110 113 bool cookieJarCreated; 111 114 112 static inline QNetworkAccessCache *getCache(QNetworkAccessBackend *backend) 113 { return &backend->manager->cache; } 115 116 // this cache can be used by individual backends to cache e.g. their TCP connections to a server 117 // and use the connections for multiple requests. 118 QNetworkAccessCache objectCache; 119 static inline QNetworkAccessCache *getObjectCache(QNetworkAccessBackend *backend) 120 { return &backend->manager->objectCache; } 114 121 Q_AUTOTEST_EXPORT static void clearCache(QNetworkAccessManager *manager); 115 122 -
trunk/src/network/access/qnetworkcookie.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 505 505 if (!d->domain.isEmpty()) { 506 506 result += "; domain="; 507 result += QUrl::toAce(d->domain); 507 QString domainNoDot = d->domain; 508 if (domainNoDot.startsWith(QLatin1Char('.'))) { 509 result += '.'; 510 domainNoDot = domainNoDot.mid(1); 511 } 512 result += QUrl::toAce(domainNoDot); 508 513 } 509 514 if (!d->path.isEmpty()) { … … 914 919 QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString) 915 920 { 921 // cookieString can be a number of set-cookie header strings joined together 922 // by \n, parse each line separately. 923 QList<QNetworkCookie> cookies; 924 QList<QByteArray> list = cookieString.split('\n'); 925 for (int a = 0; a < list.size(); a++) 926 cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(list.at(a)); 927 return cookies; 928 } 929 930 QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString) 931 { 916 932 // According to http://wp.netscape.com/newsref/std/cookie_spec.html,< 917 933 // the Set-Cookie response header is of the format: … … 931 947 QNetworkCookie cookie; 932 948 933 // When there are multiple SetCookie headers they are join with a new line934 // \n will always be the start of a new cookie935 int endOfSetCookie = cookieString.indexOf('\n', position);936 if (endOfSetCookie == -1)937 endOfSetCookie = length;938 939 949 // The first part is always the "NAME=VALUE" part 940 950 QPair<QByteArray,QByteArray> field = nextField(cookieString, position); … … 947 957 position = nextNonWhitespace(cookieString, position); 948 958 bool endOfCookie = false; 949 while (!endOfCookie && position < endOfSetCookie)959 while (!endOfCookie && position < length) { 950 960 switch (cookieString.at(position++)) { 951 961 case ',': … … 970 980 QDateTime dt = parseDateString(dateString.toLower()); 971 981 if (!dt.isValid()) { 972 cookie = QNetworkCookie(); 973 endOfCookie = true; 974 continue; 982 return result; 975 983 } 976 984 cookie.setExpirationDate(dt); … … 989 997 int secs = field.second.toInt(&ok); 990 998 if (!ok) 991 // invalid cookie string 992 return QList<QNetworkCookie>(); 999 return result; 993 1000 cookie.setExpirationDate(now.addSecs(secs)); 994 1001 } else if (field.first == "path") { … … 1004 1011 if (field.second != "1") { 1005 1012 // oops, we don't know how to handle this cookie 1006 cookie = QNetworkCookie(); 1007 endOfCookie = true; 1008 continue; 1013 return result; 1009 1014 } 1010 1015 } else { … … 1014 1019 1015 1020 position = nextNonWhitespace(cookieString, position); 1016 if (position > endOfSetCookie)1017 endOfCookie = true;1018 1021 } 1022 } 1019 1023 1020 1024 if (!cookie.name().isEmpty()) … … 1028 1032 QDebug operator<<(QDebug s, const QNetworkCookie &cookie) 1029 1033 { 1030 s.nospace() << "QNetworkCookie(" << cookie.toRawForm(QNetworkCookie::Full) << ")";1034 s.nospace() << "QNetworkCookie(" << cookie.toRawForm(QNetworkCookie::Full) << ')'; 1031 1035 return s.space(); 1032 1036 } 1033 1037 #endif 1034 1038 1035 1036 1037 class QNetworkCookieJarPrivate: public QObjectPrivate1038 {1039 public:1040 QList<QNetworkCookie> allCookies;1041 1042 Q_DECLARE_PUBLIC(QNetworkCookieJar)1043 };1044 1045 /*!1046 \class QNetworkCookieJar1047 \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects1048 \since 4.41049 1050 Cookies are small bits of information that stateless protocols1051 like HTTP use to maintain some persistent information across1052 requests.1053 1054 A cookie is set by a remote server when it replies to a request1055 and it expects the same cookie to be sent back when further1056 requests are sent.1057 1058 The cookie jar is the object that holds all cookies set in1059 previous requests. Web browsers save their cookie jars to disk in1060 order to conserve permanent cookies across invocations of the1061 application.1062 1063 QNetworkCookieJar does not implement permanent storage: it only1064 keeps the cookies in memory. Once the QNetworkCookieJar object is1065 deleted, all cookies it held will be discarded as well. If you1066 want to save the cookies, you should derive from this class and1067 implement the saving to disk to your own storage format.1068 1069 This class implements only the basic security recommended by the1070 cookie specifications and does not implement any cookie acceptance1071 policy (it accepts all cookies set by any requests). In order to1072 override those rules, you should reimplement the1073 cookiesForUrl() and setCookiesFromUrl() virtual1074 functions. They are called by QNetworkReply and1075 QNetworkAccessManager when they detect new cookies and when they1076 require cookies.1077 1078 \sa QNetworkCookie, QNetworkAccessManager, QNetworkReply,1079 QNetworkRequest, QNetworkAccessManager::setCookieJar()1080 */1081 1082 /*!1083 Creates a QNetworkCookieJar object and sets the parent object to1084 be \a parent.1085 1086 The cookie jar is initialized to empty.1087 */1088 QNetworkCookieJar::QNetworkCookieJar(QObject *parent)1089 : QObject(*new QNetworkCookieJarPrivate, parent)1090 {1091 }1092 1093 /*!1094 Destroys this cookie jar object and discards all cookies stored in1095 it. Cookies are not saved to disk in the QNetworkCookieJar default1096 implementation.1097 1098 If you need to save the cookies to disk, you have to derive from1099 QNetworkCookieJar and save the cookies to disk yourself.1100 */1101 QNetworkCookieJar::~QNetworkCookieJar()1102 {1103 }1104 1105 /*!1106 Returns all cookies stored in this cookie jar. This function is1107 suitable for derived classes to save cookies to disk, as well as1108 to implement cookie expiration and other policies.1109 1110 \sa setAllCookies(), cookiesForUrl()1111 */1112 QList<QNetworkCookie> QNetworkCookieJar::allCookies() const1113 {1114 return d_func()->allCookies;1115 }1116 1117 /*!1118 Sets the internal list of cookies held by this cookie jar to be \a1119 cookieList. This function is suitable for derived classes to1120 implement loading cookies from permanent storage, or their own1121 cookie acceptance policies by reimplementing1122 setCookiesFromUrl().1123 1124 \sa allCookies(), setCookiesFromUrl()1125 */1126 void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)1127 {1128 Q_D(QNetworkCookieJar);1129 d->allCookies = cookieList;1130 }1131 1132 static inline bool isParentPath(QString path, QString reference)1133 {1134 if (!path.endsWith(QLatin1Char('/')))1135 path += QLatin1Char('/');1136 if (!reference.endsWith(QLatin1Char('/')))1137 reference += QLatin1Char('/');1138 return path.startsWith(reference);1139 }1140 1141 static inline bool isParentDomain(QString domain, QString reference)1142 {1143 if (!reference.startsWith(QLatin1Char('.')))1144 return domain == reference;1145 1146 return domain.endsWith(reference) || domain == reference.mid(1);1147 }1148 1149 /*!1150 Adds the cookies in the list \a cookieList to this cookie1151 jar. Default values for path and domain are taken from the \a1152 url object.1153 1154 Returns true if one or more cookes are set for url otherwise false.1155 1156 If a cookie already exists in the cookie jar, it will be1157 overridden by those in \a cookieList.1158 1159 The default QNetworkCookieJar class implements only a very basic1160 security policy (it makes sure that the cookies' domain and path1161 match the reply's). To enhance the security policy with your own1162 algorithms, override setCookiesFromUrl().1163 1164 Also, QNetworkCookieJar does not have a maximum cookie jar1165 size. Reimplement this function to discard older cookies to create1166 room for new ones.1167 1168 \sa cookiesForUrl(), QNetworkAccessManager::setCookieJar()1169 */1170 bool QNetworkCookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList,1171 const QUrl &url)1172 {1173 Q_D(QNetworkCookieJar);1174 QString defaultDomain = url.host();1175 QString pathAndFileName = url.path();1176 QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/'))+1);1177 if (defaultPath.isEmpty())1178 defaultPath = QLatin1Char('/');1179 1180 int added = 0;1181 QDateTime now = QDateTime::currentDateTime();1182 foreach (QNetworkCookie cookie, cookieList) {1183 bool isDeletion = !cookie.isSessionCookie() &&1184 cookie.expirationDate() < now;1185 1186 // validate the cookie & set the defaults if unset1187 // (RFC 2965: "The request-URI MUST path-match the Path attribute of the cookie.")1188 if (cookie.path().isEmpty())1189 cookie.setPath(defaultPath);1190 else if (!isParentPath(pathAndFileName, cookie.path()))1191 continue; // not accepted1192 1193 if (cookie.domain().isEmpty()) {1194 cookie.setDomain(defaultDomain);1195 } else {1196 QString domain = cookie.domain();1197 if (!(isParentDomain(domain, defaultDomain)1198 || isParentDomain(defaultDomain, domain))) {1199 continue; // not accepted1200 }1201 }1202 1203 QList<QNetworkCookie>::Iterator it = d->allCookies.begin(),1204 end = d->allCookies.end();1205 for ( ; it != end; ++it)1206 // does this cookie already exist?1207 if (cookie.name() == it->name() &&1208 cookie.domain() == it->domain() &&1209 cookie.path() == it->path()) {1210 // found a match1211 d->allCookies.erase(it);1212 break;1213 }1214 1215 // did not find a match1216 if (!isDeletion) {1217 d->allCookies += cookie;1218 ++added;1219 }1220 }1221 return (added > 0);1222 }1223 1224 /*!1225 Returns the cookies to be added to when a request is sent to1226 \a url. This function is called by the default1227 QNetworkAccessManager::createRequest(), which adds the1228 cookies returned by this function to the request being sent.1229 1230 If more than one cookie with the same name is found, but with1231 differing paths, the one with longer path is returned before the1232 one with shorter path. In other words, this function returns1233 cookies sorted by path length.1234 1235 The default QNetworkCookieJar class implements only a very basic1236 security policy (it makes sure that the cookies' domain and path1237 match the reply's). To enhance the security policy with your own1238 algorithms, override cookiesForUrl().1239 1240 \sa setCookiesFromUrl(), QNetworkAccessManager::setCookieJar()1241 */1242 QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const1243 {1244 // \b Warning! This is only a dumb implementation!1245 // It does NOT follow all of the recommendations from1246 // http://wp.netscape.com/newsref/std/cookie_spec.html1247 // It does not implement a very good cross-domain verification yet.1248 1249 Q_D(const QNetworkCookieJar);1250 QDateTime now = QDateTime::currentDateTime();1251 QList<QNetworkCookie> result;1252 1253 // scan our cookies for something that matches1254 QList<QNetworkCookie>::ConstIterator it = d->allCookies.constBegin(),1255 end = d->allCookies.constEnd();1256 for ( ; it != end; ++it) {1257 if (!isParentDomain(url.host(), it->domain()))1258 continue;1259 if (!isParentPath(url.path(), it->path()))1260 continue;1261 if (!(*it).isSessionCookie() && (*it).expirationDate() < now)1262 continue;1263 1264 // insert this cookie into result, sorted by path1265 QList<QNetworkCookie>::Iterator insertIt = result.begin();1266 while (insertIt != result.end()) {1267 if (insertIt->path().length() < it->path().length()) {1268 // insert here1269 insertIt = result.insert(insertIt, *it);1270 break;1271 } else {1272 ++insertIt;1273 }1274 }1275 1276 // this is the shortest path yet, just append1277 if (insertIt == result.end())1278 result += *it;1279 }1280 1281 return result;1282 }1283 1284 1039 QT_END_NAMESPACE -
trunk/src/network/access/qnetworkcookie.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 107 107 Q_DECLARE_TYPEINFO(QNetworkCookie, Q_MOVABLE_TYPE); 108 108 109 class QNetworkCookieJarPrivate;110 class Q_NETWORK_EXPORT QNetworkCookieJar: public QObject111 {112 Q_OBJECT113 public:114 QNetworkCookieJar(QObject *parent = 0);115 virtual ~QNetworkCookieJar();116 117 virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;118 virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);119 120 protected:121 QList<QNetworkCookie> allCookies() const;122 void setAllCookies(const QList<QNetworkCookie> &cookieList);123 124 private:125 Q_DECLARE_PRIVATE(QNetworkCookieJar)126 Q_DISABLE_COPY(QNetworkCookieJar)127 };128 129 109 #ifndef QT_NO_DEBUG_STREAM 130 110 class QDebug; … … 134 114 QT_END_NAMESPACE 135 115 116 // ### Qt5 remove this include 117 #include "qnetworkcookiejar.h" 118 136 119 Q_DECLARE_METATYPE(QNetworkCookie) 137 120 Q_DECLARE_METATYPE(QList<QNetworkCookie>) -
trunk/src/network/access/qnetworkcookie_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 62 62 public: 63 63 inline QNetworkCookiePrivate() : secure(false), httpOnly(false) { } 64 static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString); 64 65 65 66 QDateTime expirationDate; -
trunk/src/network/access/qnetworkdiskcache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 41 41 42 42 //#define QNETWORKDISKCACHE_DEBUG 43 44 #ifndef QT_NO_NETWORKDISKCACHE 43 45 44 46 #include "qnetworkdiskcache.h" 45 47 #include "qnetworkdiskcache_p.h" 48 #include "QtCore/qscopedpointer.h" 46 49 47 50 #include <qfile.h> … … 80 83 81 84 Note you have to set the cache directory before it will work. 85 86 A network disk cache can be enabled by: 87 88 \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 0 89 90 When sending requests, to control the preference of when to use the cache 91 and when to use the network, consider the following: 92 93 \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 1 94 95 To check whether the response came from the cache or from the network, the 96 following can be applied: 97 98 \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 2 82 99 */ 83 100 … … 181 198 } 182 199 } 183 184 QCacheItem *cacheItem = new QCacheItem; 200 QScopedPointer<QCacheItem> cacheItem(new QCacheItem); 185 201 cacheItem->metaData = metaData; 186 202 … … 191 207 } else { 192 208 QString templateName = d->tmpCacheFileName(); 193 cacheItem->file = new QTemporaryFile(templateName, &cacheItem->data); 194 cacheItem->file->open(); 209 QT_TRY { 210 cacheItem->file = new QTemporaryFile(templateName, &cacheItem->data); 211 } QT_CATCH(...) { 212 cacheItem->file = 0; 213 } 214 if (!cacheItem->file || !cacheItem->file->open()) { 215 qWarning() << "QNetworkDiskCache::prepare() unable to open temporary file"; 216 cacheItem.reset(); 217 return 0; 218 } 195 219 cacheItem->writeHeader(cacheItem->file); 196 220 device = cacheItem->file; 197 221 } 198 d->inserting[device] = cacheItem ;222 d->inserting[device] = cacheItem.take(); 199 223 return device; 200 224 } … … 230 254 if (QFile::exists(fileName)) { 231 255 if (!QFile::remove(fileName)) { 232 qWarning() << "QNetworkDiskCache: could 't remove the cache file " << fileName;256 qWarning() << "QNetworkDiskCache: couldn't remove the cache file " << fileName; 233 257 return; 234 258 } … … 355 379 #endif 356 380 Q_D(QNetworkDiskCache); 357 Q Buffer *buffer = 0;381 QScopedPointer<QBuffer> buffer; 358 382 if (!url.isValid()) 359 return buffer;383 return 0; 360 384 if (d->lastItem.metaData.url() == url && d->lastItem.data.isOpen()) { 361 buffer = new QBuffer;385 buffer.reset(new QBuffer); 362 386 buffer->setData(d->lastItem.data.data()); 363 387 } else { 364 QFile *file = new QFile(d->cacheFileName(url)); 365 if (!file->open(QFile::ReadOnly | QIODevice::Unbuffered)) { 366 delete file; 388 QScopedPointer<QFile> file(new QFile(d->cacheFileName(url))); 389 if (!file->open(QFile::ReadOnly | QIODevice::Unbuffered)) 367 390 return 0; 368 } 369 if (!d->lastItem.read(file , true)) {391 392 if (!d->lastItem.read(file.data(), true)) { 370 393 file->close(); 371 394 remove(url); 372 delete file;373 395 return 0; 374 396 } 375 397 if (d->lastItem.data.isOpen()) { 376 398 // compressed 377 buffer = new QBuffer;399 buffer.reset(new QBuffer); 378 400 buffer->setData(d->lastItem.data.data()); 379 delete file;380 401 } else { 381 buffer = new QBuffer;402 buffer.reset(new QBuffer); 382 403 // ### verify that QFile uses the fd size and not the file name 383 404 qint64 size = file->size() - file->pos(); … … 387 408 #endif 388 409 if (p) { 389 file->setParent(buffer);390 410 buffer->setData((const char *)p, size); 411 file.take()->setParent(buffer.data()); 391 412 } else { 392 413 buffer->setData(file->readAll()); 393 delete file;394 414 } 395 415 } 396 416 } 397 417 buffer->open(QBuffer::ReadOnly); 398 return buffer ;418 return buffer.take(); 399 419 } 400 420 … … 463 483 Returns the current size of the cache. 464 484 465 When the current size of the cache is greater th en the maximumCacheSize()485 When the current size of the cache is greater than the maximumCacheSize() 466 486 older cache files are removed until the total size is less then 90% of 467 487 maximumCacheSize() starting with the oldest ones first using the file … … 491 511 QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories); 492 512 493 QM ap<QDateTime, QString> cacheItems;513 QMultiMap<QDateTime, QString> cacheItems; 494 514 qint64 totalSize = 0; 495 515 while (it.hasNext()) { … … 498 518 QString fileName = info.fileName(); 499 519 if (fileName.endsWith(CACHE_POSTFIX) && fileName.startsWith(CACHE_PREFIX)) { 500 cacheItems [info.created()] = path;520 cacheItems.insert(info.created(), path); 501 521 totalSize += info.size(); 502 522 } … … 505 525 int removedFiles = 0; 506 526 qint64 goal = (maximumCacheSize() * 9) / 10; 507 QM ap<QDateTime, QString>::const_iterator i = cacheItems.constBegin();527 QMultiMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin(); 508 528 while (i != cacheItems.constEnd()) { 509 529 if (totalSize < goal) … … 666 686 667 687 QT_END_NAMESPACE 688 689 #endif // QT_NO_NETWORKDISKCACHE -
trunk/src/network/access/qnetworkdiskcache.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 50 50 51 51 QT_MODULE(Network) 52 53 #ifndef QT_NO_NETWORKDISKCACHE 52 54 53 55 class QNetworkDiskCachePrivate; … … 87 89 }; 88 90 91 #endif // QT_NO_NETWORKDISKCACHE 92 89 93 QT_END_NAMESPACE 90 94 … … 92 96 93 97 #endif // QNETWORKDISKCACHE_H 94 -
trunk/src/network/access/qnetworkdiskcache_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** -
trunk/src/network/access/qnetworkreply.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 60 60 \since 4.4 61 61 \brief The QNetworkReply class contains the data and headers for a request 62 postedwith QNetworkAccessManager62 sent with QNetworkAccessManager 63 63 64 64 \reentrant 65 \ingroup network 65 66 \inmodule QtNetwork 66 67 … … 88 89 content. 89 90 91 \note Do not delete the object in the slot connected to the 92 error() or finished() signal. Use deleteLater(). 93 90 94 \sa QNetworkRequest, QNetworkAccessManager 91 95 */ … … 152 156 were not accepted (if any) 153 157 158 \value ContentReSendError the request needed to be sent 159 again, but this failed for example because the upload data 160 could not be read a second time. 161 154 162 \value ProtocolUnknownError the Network Access API cannot 155 163 honor the request because the protocol is not known … … 164 172 was detected 165 173 166 \value UnknownContentError an unkno nwn error related to174 \value UnknownContentError an unknown error related to 167 175 the remote content was detected 168 176 … … 229 237 parameter is this object. 230 238 239 \note Do not delete the object in the slot connected to this 240 signal. Use deleteLater(). 241 231 242 \sa QNetworkAccessManager::finished() 232 243 */ … … 242 253 detected. Call errorString() to obtain a textual representation of 243 254 the error condition. 255 256 \note Do not delete the object in the slot connected to this 257 signal. Use deleteLater(). 244 258 245 259 \sa error(), errorString() … … 436 450 { 437 451 return d_func()->errorCode; 452 } 453 454 /*! 455 \since 4.6 456 457 Returns true when the reply has finished or was aborted. 458 459 \sa isRunning() 460 */ 461 bool QNetworkReply::isFinished() const 462 { 463 return d_func()->isFinished(); 464 } 465 466 /*! 467 \since 4.6 468 469 Returns true when the request is still processing and the 470 reply has not finished or was aborted yet. 471 472 \sa isFinished() 473 */ 474 bool QNetworkReply::isRunning() const 475 { 476 return !isFinished(); 438 477 } 439 478 … … 556 595 } 557 596 } 597 598 /*! 599 \overload 600 \since 4.6 601 602 If this function is called, the SSL errors given in \a errors 603 will be ignored. 604 605 Note that you can set the expected certificate in the SSL error: 606 If, for instance, you want to issue a request to a server that uses 607 a self-signed certificate, consider the following snippet: 608 609 \snippet doc/src/snippets/code/src_network_access_qnetworkreply.cpp 0 610 611 Multiple calls to this function will replace the list of errors that 612 were passed in previous calls. 613 You can clear the list of errors you want to ignore by calling this 614 function with an empty list. 615 616 \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() 617 */ 618 void QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) 619 { 620 // do this cryptic trick, because we could not add a virtual method to this class later on 621 // since that breaks binary compatibility 622 int id = metaObject()->indexOfMethod("ignoreSslErrorsImplementation(QList<QSslError>)"); 623 if (id != -1) { 624 QList<QSslError> copy(errors); 625 void *arr[] = { 0, © }; 626 qt_metacall(QMetaObject::InvokeMetaMethod, id, arr); 627 } 628 } 558 629 #endif 559 630 … … 570 641 found. 571 642 572 \sa sslConfiguration(), sslErrors() 643 \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors() 573 644 */ 574 645 void QNetworkReply::ignoreSslErrors() -
trunk/src/network/access/qnetworkreply.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 93 93 ContentNotFoundError, 94 94 AuthenticationRequiredError, 95 ContentReSendError, 95 96 UnknownContentError = 299, 96 97 … … 116 117 QNetworkRequest request() const; 117 118 NetworkError error() const; 119 bool isFinished() const; 120 bool isRunning() const; 118 121 QUrl url() const; 119 122 … … 132 135 QSslConfiguration sslConfiguration() const; 133 136 void setSslConfiguration(const QSslConfiguration &configuration); 137 void ignoreSslErrors(const QList<QSslError> &errors); 134 138 #endif 135 139 -
trunk/src/network/access/qnetworkreply_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 76 76 { reply->d_func()->manager = manager; } 77 77 78 virtual bool isFinished() const { return false; } 79 78 80 Q_DECLARE_PUBLIC(QNetworkReply) 79 81 }; -
trunk/src/network/access/qnetworkreplyimpl.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 47 47 #include "QtCore/qdatetime.h" 48 48 #include "QtNetwork/qsslconfiguration.h" 49 #include "qnetworkaccesshttpbackend_p.h" 49 50 50 51 #include <QtCore/QCoreApplication> … … 53 54 54 55 inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() 55 : copyDevice(0), networkCache(0), 56 : backend(0), outgoingData(0), outgoingDataBuffer(0), 57 copyDevice(0), 56 58 cacheEnabled(false), cacheSaveDevice(0), 59 notificationHandlingPaused(false), 57 60 bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), 61 httpStatusCode(0), 58 62 state(Idle) 59 63 { … … 62 66 void QNetworkReplyImplPrivate::_q_startOperation() 63 67 { 64 // This function is called exactly once 68 // ensure this function is only being called once 69 if (state == Working) { 70 qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); 71 return; 72 } 65 73 state = Working; 74 66 75 if (!backend) { 67 76 error(QNetworkReplyImpl::ProtocolUnknownError, … … 75 84 if (operation == QNetworkAccessManager::GetOperation) 76 85 pendingNotifications.append(NotifyDownstreamReadyWrite); 77 if (outgoingData) {78 _q_sourceReadyRead();79 #if 0 // ### FIXME80 if (outgoingData->atEndOfStream() && writeBuffer.isEmpty())81 // empty upload82 emit q->uploadProgress(0, 0);83 #endif84 }85 86 86 87 handleNotifications(); … … 88 89 } 89 90 90 void QNetworkReplyImplPrivate::_q_sourceReadyRead()91 {92 // read data from the outgoingData QIODevice into our internal buffer93 enum { DesiredBufferSize = 32 * 1024 };94 95 if (writeBuffer.size() >= DesiredBufferSize)96 return; // don't grow the buffer too much97 98 // read as many bytes are available or up until we fill up the buffer99 // but always read at least one byte100 qint64 bytesToRead = qBound<qint64>(1, outgoingData->bytesAvailable(),101 DesiredBufferSize - writeBuffer.size());102 char *ptr = writeBuffer.reserve(bytesToRead);103 qint64 bytesActuallyRead = outgoingData->read(ptr, bytesToRead);104 if (bytesActuallyRead == -1) {105 // EOF106 writeBuffer.chop(bytesToRead);107 backendNotify(NotifyCloseUpstreamChannel);108 return;109 }110 111 if (bytesActuallyRead < bytesToRead)112 writeBuffer.chop(bytesToRead - bytesActuallyRead);113 114 // if we did read anything, let the backend know and handle it115 if (bytesActuallyRead)116 backendNotify(NotifyUpstreamReadyRead);117 118 // check for EOF again119 if (!outgoingData->isSequential() && outgoingData->atEnd())120 backendNotify(NotifyCloseUpstreamChannel);121 }122 123 void QNetworkReplyImplPrivate::_q_sourceReadChannelFinished()124 {125 _q_sourceReadyRead();126 }127 128 91 void QNetworkReplyImplPrivate::_q_copyReadyRead() 129 92 { 130 93 Q_Q(QNetworkReplyImpl); 131 if (!copyDevice && !q->isOpen()) 132 return; 133 134 qint64 bytesToRead = nextDownstreamBlockSize(); 135 if (bytesToRead == 0) 136 // we'll be called again, eventually 137 return; 138 139 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); 140 char *ptr = readBuffer.reserve(bytesToRead); 141 qint64 bytesActuallyRead = copyDevice->read(ptr, bytesToRead); 142 if (bytesActuallyRead == -1) { 143 readBuffer.chop(bytesToRead); 144 backendNotify(NotifyCopyFinished); 145 return; 146 } 147 148 if (bytesActuallyRead != bytesToRead) 149 readBuffer.chop(bytesToRead - bytesActuallyRead); 150 151 if (!copyDevice->isSequential() && copyDevice->atEnd()) 152 backendNotify(NotifyCopyFinished); 153 154 bytesDownloaded += bytesActuallyRead; 94 if (state != Working) 95 return; 96 if (!copyDevice || !q->isOpen()) 97 return; 98 99 forever { 100 qint64 bytesToRead = nextDownstreamBlockSize(); 101 if (bytesToRead == 0) 102 // we'll be called again, eventually 103 break; 104 105 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); 106 QByteArray byteData; 107 byteData.resize(bytesToRead); 108 qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size()); 109 if (bytesActuallyRead == -1) { 110 byteData.clear(); 111 backendNotify(NotifyCopyFinished); 112 break; 113 } 114 115 byteData.resize(bytesActuallyRead); 116 readBuffer.append(byteData); 117 118 if (!copyDevice->isSequential() && copyDevice->atEnd()) { 119 backendNotify(NotifyCopyFinished); 120 bytesDownloaded += bytesActuallyRead; 121 break; 122 } 123 124 bytesDownloaded += bytesActuallyRead; 125 } 126 127 if (bytesDownloaded == lastBytesDownloaded) { 128 // we didn't read anything 129 return; 130 } 131 155 132 lastBytesDownloaded = bytesDownloaded; 156 133 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 134 pauseNotificationHandling(); 157 135 emit q->downloadProgress(bytesDownloaded, 158 136 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 159 137 emit q->readyRead(); 138 resumeNotificationHandling(); 160 139 } 161 140 … … 164 143 _q_copyReadyRead(); 165 144 } 145 146 void QNetworkReplyImplPrivate::_q_bufferOutgoingDataFinished() 147 { 148 Q_Q(QNetworkReplyImpl); 149 150 // make sure this is only called once, ever. 151 //_q_bufferOutgoingData may call it or the readChannelFinished emission 152 if (state != Buffering) 153 return; 154 155 // disconnect signals 156 QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); 157 QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); 158 159 // finally, start the request 160 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 161 } 162 163 void QNetworkReplyImplPrivate::_q_bufferOutgoingData() 164 { 165 Q_Q(QNetworkReplyImpl); 166 167 if (!outgoingDataBuffer) { 168 // first call, create our buffer 169 outgoingDataBuffer = new QRingBuffer(); 170 171 QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); 172 QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); 173 } 174 175 qint64 bytesBuffered = 0; 176 qint64 bytesToBuffer = 0; 177 178 // read data into our buffer 179 forever { 180 bytesToBuffer = outgoingData->bytesAvailable(); 181 // unknown? just try 2 kB, this also ensures we always try to read the EOF 182 if (bytesToBuffer <= 0) 183 bytesToBuffer = 2*1024; 184 185 char *dst = outgoingDataBuffer->reserve(bytesToBuffer); 186 bytesBuffered = outgoingData->read(dst, bytesToBuffer); 187 188 if (bytesBuffered == -1) { 189 // EOF has been reached. 190 outgoingDataBuffer->chop(bytesToBuffer); 191 192 _q_bufferOutgoingDataFinished(); 193 break; 194 } else if (bytesBuffered == 0) { 195 // nothing read right now, just wait until we get called again 196 outgoingDataBuffer->chop(bytesToBuffer); 197 198 break; 199 } else { 200 // don't break, try to read() again 201 outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered); 202 } 203 } 204 } 205 166 206 167 207 void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req, … … 175 215 operation = op; 176 216 177 if (outgoingData) { 178 q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead())); 179 q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished())); 217 if (outgoingData && backend) { 218 // there is data to be uploaded, e.g. HTTP POST. 219 220 if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) { 221 // backend does not need upload buffering or 222 // fixed size non-sequential 223 // just start the operation 224 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 225 } else { 226 bool bufferingDisallowed = 227 req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, 228 false).toBool(); 229 230 if (bufferingDisallowed) { 231 // if a valid content-length header for the request was supplied, we can disable buffering 232 // if not, we will buffer anyway 233 if (req.header(QNetworkRequest::ContentLengthHeader).isValid()) { 234 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 235 } else { 236 state = Buffering; 237 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); 238 } 239 } else { 240 // _q_startOperation will be called when the buffering has finished. 241 state = Buffering; 242 QMetaObject::invokeMethod(q, "_q_bufferOutgoingData", Qt::QueuedConnection); 243 } 244 } 245 } else { 246 // No outgoing data (e.g. HTTP GET request) 247 // or no backend 248 // if no backend, _q_startOperation will handle the error of this 249 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); 180 250 } 181 251 182 252 q->QIODevice::open(QIODevice::ReadOnly); 183 QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);184 }185 186 void QNetworkReplyImplPrivate::setNetworkCache(QAbstractNetworkCache *nc)187 {188 networkCache = nc;189 253 } 190 254 … … 201 265 void QNetworkReplyImplPrivate::handleNotifications() 202 266 { 267 if (notificationHandlingPaused) 268 return; 269 203 270 NotificationQueue current = pendingNotifications; 204 271 pendingNotifications.clear(); … … 207 274 return; 208 275 209 while ( !current.isEmpty()) {276 while (state == Working && !current.isEmpty()) { 210 277 InternalNotifications notification = current.dequeue(); 211 278 switch (notification) { … … 217 284 break; 218 285 219 case NotifyUpstreamReadyRead:220 backend->upstreamReadyRead();221 break;222 223 286 case NotifyCloseDownstreamChannel: 224 287 backend->closeDownstreamChannel(); 225 break;226 227 case NotifyCloseUpstreamChannel:228 backend->closeUpstreamChannel();229 288 break; 230 289 … … 239 298 } 240 299 300 // Do not handle the notifications while we are emitting downloadProgress 301 // or readyRead 302 void QNetworkReplyImplPrivate::pauseNotificationHandling() 303 { 304 notificationHandlingPaused = true; 305 } 306 307 // Resume notification handling 308 void QNetworkReplyImplPrivate::resumeNotificationHandling() 309 { 310 Q_Q(QNetworkReplyImpl); 311 notificationHandlingPaused = false; 312 if (pendingNotifications.size() >= 1) 313 QCoreApplication::postEvent(q, new QEvent(QEvent::NetworkReplyUpdated)); 314 } 315 316 QAbstractNetworkCache *QNetworkReplyImplPrivate::networkCache() const 317 { 318 if (!backend) 319 return 0; 320 return backend->networkCache(); 321 } 322 241 323 void QNetworkReplyImplPrivate::createCache() 242 324 { 243 325 // check if we can save and if we're allowed to 244 if (!networkCache || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool()) 326 if (!networkCache() 327 || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool() 328 || request.attribute(QNetworkRequest::CacheLoadControlAttribute, 329 QNetworkRequest::PreferNetwork).toInt() 330 == QNetworkRequest::AlwaysNetwork) 245 331 return; 246 332 cacheEnabled = true; … … 249 335 bool QNetworkReplyImplPrivate::isCachingEnabled() const 250 336 { 251 return (cacheEnabled && networkCache != 0);337 return (cacheEnabled && networkCache() != 0); 252 338 } 253 339 … … 273 359 "backend %s probably needs to be fixed", 274 360 backend->metaObject()->className()); 275 networkCache ->remove(url);361 networkCache()->remove(url); 276 362 cacheSaveDevice = 0; 277 363 cacheEnabled = false; … … 282 368 { 283 369 if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) { 284 networkCache ->remove(url);370 networkCache()->remove(url); 285 371 } else if (cacheEnabled && cacheSaveDevice) { 286 networkCache ->insert(cacheSaveDevice);372 networkCache()->insert(cacheSaveDevice); 287 373 } 288 374 cacheSaveDevice = 0; … … 290 376 } 291 377 292 void QNetworkReplyImplPrivate::consume(qint64 count) 293 { 294 Q_Q(QNetworkReplyImpl); 295 if (count <= 0) { 296 qWarning("QNetworkConnection: backend signalled that it consumed %ld bytes", long(count)); 297 return; 298 } 299 300 if (outgoingData) 301 // schedule another read from the source 302 QMetaObject::invokeMethod(q_func(), "_q_sourceReadyRead", Qt::QueuedConnection); 303 304 writeBuffer.skip(count); 305 if (bytesUploaded == -1) 306 bytesUploaded = count; 307 else 308 bytesUploaded += count; 309 310 QVariant totalSize = request.header(QNetworkRequest::ContentLengthHeader); 311 emit q->uploadProgress(bytesUploaded, 312 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 313 } 378 void QNetworkReplyImplPrivate::emitUploadProgress(qint64 bytesSent, qint64 bytesTotal) 379 { 380 Q_Q(QNetworkReplyImpl); 381 bytesUploaded = bytesSent; 382 pauseNotificationHandling(); 383 emit q->uploadProgress(bytesSent, bytesTotal); 384 resumeNotificationHandling(); 385 } 386 314 387 315 388 qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const … … 319 392 return DesiredBufferSize; 320 393 321 return qMax<qint64>(0, readBufferMaxSize - readBuffer.size()); 322 } 323 324 void QNetworkReplyImplPrivate::feed(const QByteArray &data) 394 return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount()); 395 } 396 397 // we received downstream data and send this to the cache 398 // and to our readBuffer (which in turn gets read by the user of QNetworkReply) 399 void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) 325 400 { 326 401 Q_Q(QNetworkReplyImpl); 327 402 if (!q->isOpen()) 328 403 return; 329 330 char *ptr = readBuffer.reserve(data.size());331 memcpy(ptr, data.constData(), data.size());332 404 333 405 if (cacheEnabled && !cacheSaveDevice) { … … 336 408 metaData.setUrl(url); 337 409 metaData = backend->fetchCacheMetaData(metaData); 338 cacheSaveDevice = networkCache->prepare(metaData); 410 411 // save the redirect request also in the cache 412 QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute); 413 if (redirectionTarget.isValid()) { 414 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes(); 415 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget); 416 metaData.setAttributes(attributes); 417 } 418 419 cacheSaveDevice = networkCache()->prepare(metaData); 420 339 421 if (!cacheSaveDevice || (cacheSaveDevice && !cacheSaveDevice->isOpen())) { 340 422 if (cacheSaveDevice && !cacheSaveDevice->isOpen()) 341 423 qCritical("QNetworkReplyImpl: network cache returned a device that is not open -- " 342 424 "class %s probably needs to be fixed", 343 networkCache ->metaObject()->className());344 345 networkCache ->remove(url);425 networkCache()->metaObject()->className()); 426 427 networkCache()->remove(url); 346 428 cacheSaveDevice = 0; 347 429 cacheEnabled = false; … … 349 431 } 350 432 351 if (cacheSaveDevice) 352 cacheSaveDevice->write(data); 353 354 bytesDownloaded += data.size(); 433 qint64 bytesWritten = 0; 434 for (int i = 0; i < data.bufferCount(); i++) { 435 QByteArray item = data[i]; 436 437 if (cacheSaveDevice) 438 cacheSaveDevice->write(item.constData(), item.size()); 439 readBuffer.append(item); 440 441 bytesWritten += item.size(); 442 } 443 data.clear(); 444 445 bytesDownloaded += bytesWritten; 355 446 lastBytesDownloaded = bytesDownloaded; 356 447 … … 358 449 359 450 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 451 pauseNotificationHandling(); 360 452 emit q->downloadProgress(bytesDownloaded, 361 453 totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong()); 454 // important: At the point of this readyRead(), the data parameter list must be empty, 455 // else implicit sharing will trigger memcpy when the user is reading data! 362 456 emit q->readyRead(); 363 457 364 458 // hopefully we haven't been deleted here 365 459 if (!qq.isNull()) { 460 resumeNotificationHandling(); 366 461 // do we still have room in the buffer? 367 462 if (nextDownstreamBlockSize() > 0) … … 370 465 } 371 466 372 void QNetworkReplyImplPrivate::feed(QIODevice *data) 373 { 374 Q_Q(QNetworkReplyImpl); 375 Q_ASSERT(q->isOpen()); 467 // this is used when it was fetched from the cache, right? 468 void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data) 469 { 470 Q_Q(QNetworkReplyImpl); 471 if (!q->isOpen()) 472 return; 376 473 377 474 // read until EOF from data … … 393 490 { 394 491 Q_Q(QNetworkReplyImpl); 395 Q_ASSERT_X(state != Finished, "QNetworkReplyImpl",396 "Backend called finished/finishedWithError more than once");492 if (state == Finished || state == Aborted) 493 return; 397 494 398 495 state = Finished; 399 496 pendingNotifications.clear(); 400 497 498 pauseNotificationHandling(); 401 499 QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); 402 if ( bytesDownloaded != lastBytesDownloaded || totalSize.isNull())500 if (totalSize.isNull() || totalSize == -1) { 403 501 emit q->downloadProgress(bytesDownloaded, bytesDownloaded); 404 if (bytesUploaded == -1 && outgoingData) 502 } 503 504 if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer)) 405 505 emit q->uploadProgress(0, 0); 506 resumeNotificationHandling(); 406 507 407 508 completeCacheSave(); … … 410 511 // which would delete the backend too... 411 512 // maybe we should protect the backend 513 pauseNotificationHandling(); 412 514 emit q->readChannelFinished(); 413 515 emit q->finished(); 516 resumeNotificationHandling(); 414 517 } 415 518 … … 456 559 } 457 560 561 bool QNetworkReplyImplPrivate::isFinished() const 562 { 563 return (state == Finished || state == Aborted); 564 } 565 458 566 QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent) 459 567 : QNetworkReply(*new QNetworkReplyImplPrivate, parent) … … 465 573 Q_D(QNetworkReplyImpl); 466 574 if (d->isCachingEnabled()) 467 d->networkCache->remove(url()); 575 d->networkCache()->remove(url()); 576 if (d->outgoingDataBuffer) 577 delete d->outgoingDataBuffer; 468 578 } 469 579 … … 471 581 { 472 582 Q_D(QNetworkReplyImpl); 473 if (d->state == QNetworkReplyImplPrivate:: Aborted)583 if (d->state == QNetworkReplyImplPrivate::Finished || d->state == QNetworkReplyImplPrivate::Aborted) 474 584 return; 475 585 476 586 // stop both upload and download 477 if (d->backend) {478 d->backend->deleteLater();479 d->backend = 0;480 }481 587 if (d->outgoingData) 482 588 disconnect(d->outgoingData, 0, this, 0); … … 492 598 } 493 599 d->state = QNetworkReplyImplPrivate::Aborted; 600 601 // finished may access the backend 602 if (d->backend) { 603 d->backend->deleteLater(); 604 d->backend = 0; 605 } 494 606 } 495 607 … … 521 633 qint64 QNetworkReplyImpl::bytesAvailable() const 522 634 { 523 return QNetworkReply::bytesAvailable() + d_func()->readBuffer. size();635 return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount(); 524 636 } 525 637 … … 528 640 Q_D(QNetworkReplyImpl); 529 641 if (size > d->readBufferMaxSize && 530 size == d->readBuffer.size())642 size > d->readBuffer.byteAmount()) 531 643 d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); 532 644 … … 558 670 } 559 671 672 void QNetworkReplyImpl::ignoreSslErrorsImplementation(const QList<QSslError> &errors) 673 { 674 Q_D(QNetworkReplyImpl); 675 if (d->backend) 676 d->backend->ignoreSslErrors(errors); 677 } 560 678 #endif // QT_NO_OPENSSL 561 679 … … 576 694 } 577 695 578 maxlen = qMin<qint64>(maxlen, d->readBuffer. size());696 maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount()); 579 697 return d->readBuffer.read(data, maxlen); 580 698 } -
trunk/src/network/access/qnetworkreplyimpl_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 60 60 #include "QtCore/qmap.h" 61 61 #include "QtCore/qqueue.h" 62 #include "QtCore/qbuffer.h" 62 63 #include "private/qringbuffer_p.h" 64 #include "private/qbytedata_p.h" 63 65 64 66 QT_BEGIN_NAMESPACE … … 88 90 Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration); 89 91 virtual void ignoreSslErrors(); 92 Q_INVOKABLE virtual void ignoreSslErrorsImplementation(const QList<QSslError> &errors); 90 93 #endif 91 94 92 95 Q_DECLARE_PRIVATE(QNetworkReplyImpl) 93 96 Q_PRIVATE_SLOT(d_func(), void _q_startOperation()) 94 Q_PRIVATE_SLOT(d_func(), void _q_sourceReadyRead())95 Q_PRIVATE_SLOT(d_func(), void _q_sourceReadChannelFinished())96 97 Q_PRIVATE_SLOT(d_func(), void _q_copyReadyRead()) 97 98 Q_PRIVATE_SLOT(d_func(), void _q_copyReadChannelFinished()) 99 Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData()) 100 Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished()) 98 101 }; 99 102 … … 103 106 enum InternalNotifications { 104 107 NotifyDownstreamReadyWrite, 105 NotifyUpstreamReadyRead,106 108 NotifyCloseDownstreamChannel, 107 NotifyCloseUpstreamChannel,108 109 NotifyCopyFinished 109 110 }; … … 111 112 enum State { 112 113 Idle, 113 Opening,114 Buffering, 114 115 Working, 115 116 Finished, … … 126 127 void _q_copyReadyRead(); 127 128 void _q_copyReadChannelFinished(); 129 void _q_bufferOutgoingData(); 130 void _q_bufferOutgoingDataFinished(); 128 131 129 132 void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, 130 133 QIODevice *outgoingData); 131 void setNetworkCache(QAbstractNetworkCache *networkCache); 134 135 void pauseNotificationHandling(); 136 void resumeNotificationHandling(); 132 137 void backendNotify(InternalNotifications notification); 133 138 void handleNotifications(); … … 139 144 bool isCachingEnabled() const; 140 145 void consume(qint64 count); 146 void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal); 141 147 qint64 nextDownstreamBlockSize() const; 142 void feed(const QByteArray&data);143 void feed(QIODevice *data);148 void appendDownstreamData(QByteDataBuffer &data); 149 void appendDownstreamData(QIODevice *data); 144 150 void finished(); 145 151 void error(QNetworkReply::NetworkError code, const QString &errorString); … … 148 154 void sslErrors(const QList<QSslError> &errors); 149 155 156 bool isFinished() const; 157 150 158 QNetworkAccessBackend *backend; 151 159 QIODevice *outgoingData; 160 QRingBuffer *outgoingDataBuffer; 152 161 QIODevice *copyDevice; 153 QAbstractNetworkCache *networkCache ;162 QAbstractNetworkCache *networkCache() const; 154 163 155 164 bool cacheEnabled; … … 157 166 158 167 NotificationQueue pendingNotifications; 168 bool notificationHandlingPaused; 169 159 170 QUrl urlForLastAuthentication; 160 171 #ifndef QT_NO_NETWORKPROXY … … 163 174 #endif 164 175 165 QRingBuffer readBuffer; 166 QRingBuffer writeBuffer; 176 QByteDataBuffer readBuffer; 167 177 qint64 bytesDownloaded; 168 178 qint64 lastBytesDownloaded; -
trunk/src/network/access/qnetworkrequest.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 49 49 #include "QtCore/qdatetime.h" 50 50 51 #include <ctype.h> 52 #ifndef QT_NO_DATESTRING 53 # include <stdio.h> 54 #endif 55 51 56 QT_BEGIN_NAMESPACE 52 57 53 58 /*! 54 59 \class QNetworkRequest 55 \brief The QNetworkRequest class holds one request to be sent with the Network Access API.60 \brief The QNetworkRequest class holds a request to be sent with QNetworkAccessManager. 56 61 \since 4.4 57 62 58 \ingroup io63 \ingroup network 59 64 \inmodule QtNetwork 60 65 … … 154 159 be automatically cached. If true, data may be cached, provided 155 160 it is cacheable (what is cacheable depends on the protocol 156 being used). Note that the default QNetworkAccessManager 157 implementation does not support caching, so it will ignore 158 this attribute. 161 being used). 159 162 160 163 \value SourceIsFromCacheAttribute … … 162 165 Indicates whether the data was obtained from cache 163 166 or not. 167 168 \value DoNotBufferUploadDataAttribute 169 Requests only, type: QVariant::Bool (default: false) 170 Indicates whether the QNetworkAccessManager code is 171 allowed to buffer the upload data, e.g. when doing a HTTP POST. 172 When using this flag with sequential upload data, the ContentLengthHeader 173 header must be set. 174 175 \value HttpPipeliningAllowedAttribute 176 Requests only, type: QVariant::Bool (default: false) 177 Indicates whether the QNetworkAccessManager code is 178 allowed to use HTTP pipelining with this request. 179 180 \value HttpPipeliningWasUsedAttribute 181 Replies only, type: QVariant::Bool 182 Indicates whether the HTTP pipelining was used for receiving 183 this reply. 164 184 165 185 \value User … … 217 237 218 238 #ifndef QT_NO_OPENSSL 239 sslConfiguration = 0; 219 240 if (other.sslConfiguration) 220 241 sslConfiguration = new QSslConfiguration(*other.sslConfiguration); 221 else222 sslConfiguration = 0;223 242 #endif 224 243 } … … 467 486 } 468 487 #endif 488 489 /*! 490 \since 4.6 491 492 Allows setting a reference to the \a object initiating 493 the request. 494 495 For example QtWebKit sets the originating object to the 496 QWebFrame that initiated the request. 497 498 \sa originatingObject() 499 */ 500 void QNetworkRequest::setOriginatingObject(QObject *object) 501 { 502 d->originatingObject = object; 503 } 504 505 /*! 506 \since 4.6 507 508 Returns a reference to the object that initiated this 509 network request; returns 0 if not set or the object has 510 been destroyed. 511 512 \sa setOriginatingObject() 513 */ 514 QObject *QNetworkRequest::originatingObject() const 515 { 516 return d->originatingObject.data(); 517 } 469 518 470 519 static QByteArray headerName(QNetworkRequest::KnownHeaders header) … … 563 612 // headerName is not empty here 564 613 565 QByteArray lower = headerName.toLower(); 566 switch (lower.at(0)) { 614 switch (tolower(headerName.at(0))) { 567 615 case 'c': 568 if ( lower == "content-type")616 if (qstricmp(headerName.constData(), "content-type") == 0) 569 617 return QNetworkRequest::ContentTypeHeader; 570 else if ( lower == "content-length")618 else if (qstricmp(headerName.constData(), "content-length") == 0) 571 619 return QNetworkRequest::ContentLengthHeader; 572 else if ( lower == "cookie")620 else if (qstricmp(headerName.constData(), "cookie") == 0) 573 621 return QNetworkRequest::CookieHeader; 574 622 break; 575 623 576 624 case 'l': 577 if ( lower == "location")625 if (qstricmp(headerName.constData(), "location") == 0) 578 626 return QNetworkRequest::LocationHeader; 579 else if ( lower == "last-modified")627 else if (qstricmp(headerName.constData(), "last-modified") == 0) 580 628 return QNetworkRequest::LastModifiedHeader; 581 629 break; 582 630 583 631 case 's': 584 if ( lower == "set-cookie")632 if (qstricmp(headerName.constData(), "set-cookie") == 0) 585 633 return QNetworkRequest::SetCookieHeader; 586 634 break; … … 654 702 QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const 655 703 { 656 QByteArray lowerKey = key.toLower();657 704 RawHeadersList::ConstIterator it = rawHeaders.constBegin(); 658 705 RawHeadersList::ConstIterator end = rawHeaders.constEnd(); 659 706 for ( ; it != end; ++it) 660 if ( it->first.toLower() == lowerKey)707 if (qstricmp(it->first.constData(), key.constData()) == 0) 661 708 return it; 662 709 … … 732 779 void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value) 733 780 { 734 QByteArray lowerKey = key.toLower();735 781 RawHeadersList::Iterator it = rawHeaders.begin(); 736 782 while (it != rawHeaders.end()) { 737 if ( it->first.toLower() == lowerKey)783 if (qstricmp(it->first.constData(), key.constData()) == 0) 738 784 it = rawHeaders.erase(it); 739 785 else … … 762 808 } 763 809 810 // Fast month string to int conversion. This code 811 // assumes that the Month name is correct and that 812 // the string is at least three chars long. 813 static int name_to_month(const char* month_str) 814 { 815 switch (month_str[0]) { 816 case 'J': 817 switch (month_str[1]) { 818 case 'a': 819 return 1; 820 break; 821 case 'u': 822 switch (month_str[2] ) { 823 case 'n': 824 return 6; 825 break; 826 case 'l': 827 return 7; 828 break; 829 } 830 } 831 break; 832 case 'F': 833 return 2; 834 break; 835 case 'M': 836 switch (month_str[2] ) { 837 case 'r': 838 return 3; 839 break; 840 case 'y': 841 return 5; 842 break; 843 } 844 break; 845 case 'A': 846 switch (month_str[1]) { 847 case 'p': 848 return 4; 849 break; 850 case 'u': 851 return 8; 852 break; 853 } 854 break; 855 case 'O': 856 return 10; 857 break; 858 case 'S': 859 return 9; 860 break; 861 case 'N': 862 return 11; 863 break; 864 case 'D': 865 return 12; 866 break; 867 } 868 869 return 0; 870 } 871 764 872 QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value) 765 873 { … … 777 885 dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate); 778 886 } else { 779 // eat the weekday, the comma and the space following it 780 QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2); 781 782 QLocale c = QLocale::c(); 783 if (pos == 3) 784 // must be RFC 1123 date 785 dt = c.toDateTime(sansWeekday, QLatin1String("dd MMM yyyy hh:mm:ss 'GMT")); 786 else 887 // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the 888 // QtWebKit performance benchmarks to get an idea. 889 if (pos == 3) { 890 char month_name[4]; 891 int day, year, hour, minute, second; 892 if (sscanf(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, &year, &hour, &minute, &second) == 6) 893 dt = QDateTime(QDate(year, name_to_month(month_name), day), QTime(hour, minute, second)); 894 } else { 895 QLocale c = QLocale::c(); 896 // eat the weekday, the comma and the space following it 897 QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2); 787 898 // must be RFC 850 date 788 899 dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'")); 900 } 789 901 } 790 902 #endif // QT_NO_DATESTRING -
trunk/src/network/access/qnetworkrequest.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 76 76 CacheSaveControlAttribute, 77 77 SourceIsFromCacheAttribute, 78 DoNotBufferUploadDataAttribute, 79 HttpPipeliningAllowedAttribute, 80 HttpPipeliningWasUsedAttribute, 78 81 79 82 User = 1000, … … 118 121 #endif 119 122 123 void setOriginatingObject(QObject *object); 124 QObject *originatingObject() const; 125 120 126 private: 121 127 QSharedDataPointer<QNetworkRequestPrivate> d; -
trunk/src/network/access/qnetworkrequest_p.h
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 59 59 #include "QtCore/qhash.h" 60 60 #include "QtCore/qshareddata.h" 61 #include "QtCore/qsharedpointer.h" 61 62 62 63 QT_BEGIN_NAMESPACE … … 74 75 CookedHeadersMap cookedHeaders; 75 76 AttributesMap attributes; 77 QWeakPointer<QObject> originatingObject; 76 78 77 79 RawHeadersList::ConstIterator findRawHeader(const QByteArray &key) const;
Note:
See TracChangeset
for help on using the changeset viewer.