Changeset View
Changeset View
Standalone View
Standalone View
src/widgets/accessmanagerreply_p.cpp
Show All 26 Lines | |||||
27 | #include "job.h" | 27 | #include "job.h" | ||
28 | #include "scheduler.h" | 28 | #include "scheduler.h" | ||
29 | #include "kio_widgets_debug.h" | 29 | #include "kio_widgets_debug.h" | ||
30 | 30 | | |||
31 | #include <kurlauthorized.h> | 31 | #include <kurlauthorized.h> | ||
32 | #include <kprotocolinfo.h> | 32 | #include <kprotocolinfo.h> | ||
33 | #include <qmimedatabase.h> | 33 | #include <qmimedatabase.h> | ||
34 | 34 | | |||
35 | #include <QtMath> | ||||
35 | #include <QSslConfiguration> | 36 | #include <QSslConfiguration> | ||
36 | 37 | | |||
37 | #define QL1S(x) QLatin1String(x) | 38 | #define QL1S(x) QLatin1String(x) | ||
38 | #define QL1C(x) QLatin1Char(x) | 39 | #define QL1C(x) QLatin1Char(x) | ||
39 | 40 | | |||
40 | namespace KDEPrivate | 41 | namespace KDEPrivate | ||
41 | { | 42 | { | ||
42 | 43 | | |||
43 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | 44 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | ||
44 | const QNetworkRequest &request, | 45 | const QNetworkRequest &request, | ||
45 | KIO::SimpleJob *kioJob, | 46 | KIO::SimpleJob *kioJob, | ||
46 | bool emitReadyReadOnMetaDataChange, | 47 | bool emitReadyReadOnMetaDataChange, | ||
47 | QObject *parent) | 48 | QObject *parent) | ||
48 | : QNetworkReply(parent), | 49 | : QNetworkReply(parent), | ||
50 | m_offset(0), | ||||
49 | m_metaDataRead(false), | 51 | m_metaDataRead(false), | ||
50 | m_ignoreContentDisposition(false), | 52 | m_ignoreContentDisposition(false), | ||
51 | m_emitReadyReadOnMetaDataChange(emitReadyReadOnMetaDataChange), | 53 | m_emitReadyReadOnMetaDataChange(emitReadyReadOnMetaDataChange), | ||
52 | m_kioJob(kioJob) | 54 | m_kioJob(kioJob) | ||
53 | 55 | | |||
54 | { | 56 | { | ||
55 | setRequest(request); | 57 | setRequest(request); | ||
56 | setOpenMode(QIODevice::ReadOnly); | 58 | setOpenMode(QIODevice::ReadOnly); | ||
Show All 22 Lines | |||||
79 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | 81 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | ||
80 | const QNetworkRequest &request, | 82 | const QNetworkRequest &request, | ||
81 | const QByteArray &data, | 83 | const QByteArray &data, | ||
82 | const QUrl &url, | 84 | const QUrl &url, | ||
83 | const KIO::MetaData &metaData, | 85 | const KIO::MetaData &metaData, | ||
84 | QObject *parent) | 86 | QObject *parent) | ||
85 | : QNetworkReply(parent), | 87 | : QNetworkReply(parent), | ||
86 | m_data(data), | 88 | m_data(data), | ||
89 | m_offset(0), | ||||
87 | m_ignoreContentDisposition(false), | 90 | m_ignoreContentDisposition(false), | ||
88 | m_emitReadyReadOnMetaDataChange(false) | 91 | m_emitReadyReadOnMetaDataChange(false) | ||
89 | { | 92 | { | ||
90 | setRequest(request); | 93 | setRequest(request); | ||
91 | setOpenMode(QIODevice::ReadOnly); | 94 | setOpenMode(QIODevice::ReadOnly); | ||
92 | setUrl((url.isValid() ? url : request.url())); | 95 | setUrl((url.isValid() ? url : request.url())); | ||
93 | setOperation(op); | 96 | setOperation(op); | ||
94 | setHeaderFromMetaData(metaData); | 97 | setHeaderFromMetaData(metaData); | ||
95 | 98 | | |||
96 | if (!request.sslConfiguration().isNull()) { | 99 | if (!request.sslConfiguration().isNull()) { | ||
97 | setSslConfiguration(request.sslConfiguration()); | 100 | setSslConfiguration(request.sslConfiguration()); | ||
98 | } | 101 | } | ||
99 | 102 | | |||
100 | setError(NoError, QString()); | 103 | setError(NoError, QString()); | ||
101 | emitFinished(true, Qt::QueuedConnection); | 104 | emitFinished(true, Qt::QueuedConnection); | ||
102 | } | 105 | } | ||
103 | 106 | | |||
104 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | 107 | AccessManagerReply::AccessManagerReply(const QNetworkAccessManager::Operation op, | ||
105 | const QNetworkRequest &request, | 108 | const QNetworkRequest &request, | ||
106 | QNetworkReply::NetworkError errorCode, | 109 | QNetworkReply::NetworkError errorCode, | ||
107 | const QString &errorMessage, | 110 | const QString &errorMessage, | ||
108 | QObject *parent) | 111 | QObject *parent) | ||
109 | : QNetworkReply(parent) | 112 | : QNetworkReply(parent), | ||
113 | m_offset(0) | ||||
110 | { | 114 | { | ||
111 | setRequest(request); | 115 | setRequest(request); | ||
112 | setOpenMode(QIODevice::ReadOnly); | 116 | setOpenMode(QIODevice::ReadOnly); | ||
113 | setUrl(request.url()); | 117 | setUrl(request.url()); | ||
114 | setOperation(op); | 118 | setOperation(op); | ||
115 | setError(static_cast<QNetworkReply::NetworkError>(errorCode), errorMessage); | 119 | setError(static_cast<QNetworkReply::NetworkError>(errorCode), errorMessage); | ||
116 | if (error() != QNetworkReply::NoError) { | 120 | if (error() != QNetworkReply::NoError) { | ||
117 | QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, error())); | 121 | QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, error())); | ||
118 | } | 122 | } | ||
119 | 123 | | |||
120 | emitFinished(true, Qt::QueuedConnection); | 124 | emitFinished(true, Qt::QueuedConnection); | ||
121 | } | 125 | } | ||
122 | 126 | | |||
123 | AccessManagerReply::~AccessManagerReply() | 127 | AccessManagerReply::~AccessManagerReply() | ||
124 | { | 128 | { | ||
125 | } | 129 | } | ||
126 | 130 | | |||
127 | void AccessManagerReply::abort() | 131 | void AccessManagerReply::abort() | ||
128 | { | 132 | { | ||
129 | if (m_kioJob) { | 133 | if (m_kioJob) { | ||
130 | m_kioJob.data()->disconnect(this); | 134 | m_kioJob.data()->disconnect(this); | ||
131 | } | 135 | } | ||
132 | m_kioJob.clear(); | 136 | m_kioJob.clear(); | ||
133 | m_data.clear(); | 137 | m_data.clear(); | ||
138 | m_offset = 0; | ||||
134 | m_metaDataRead = false; | 139 | m_metaDataRead = false; | ||
135 | } | 140 | } | ||
136 | 141 | | |||
137 | qint64 AccessManagerReply::bytesAvailable() const | 142 | qint64 AccessManagerReply::bytesAvailable() const | ||
138 | { | 143 | { | ||
139 | return (QNetworkReply::bytesAvailable() + m_data.length()); | 144 | return (QNetworkReply::bytesAvailable() + m_data.length() - m_offset); | ||
140 | } | 145 | } | ||
141 | 146 | | |||
142 | qint64 AccessManagerReply::readData(char *data, qint64 maxSize) | 147 | qint64 AccessManagerReply::readData(char *data, qint64 maxSize) | ||
143 | { | 148 | { | ||
144 | const qint64 length = qMin(qint64(m_data.length()), maxSize); | 149 | const qint64 length = qMin(qint64(m_data.length() - m_offset), maxSize); | ||
150 | | ||||
151 | if (length <= 0) { | ||||
152 | return 0; | ||||
153 | } | ||||
145 | 154 | | |||
146 | if (length) { | 155 | memcpy(data, m_data.constData() + m_offset, length); | ||
147 | memcpy(data, m_data.constData(), length); | 156 | m_offset += length; | ||
148 | m_data.remove(0, length); | 157 | // Remove the stale data before m_offset only if it grows to half | ||
158 | // of the total size, to avoid calling the expensive .remove function. | ||||
159 | // If there's no data left, it's a trivial remove. | ||||
160 | if (m_data.length() == m_offset || m_offset * 2 >= m_data.length()) { | ||||
161 | m_data.remove(0, m_offset); | ||||
162 | m_offset = 0; | ||||
bruns: Wouldn't it be better to trim the buffer in slotData, at least in the non-trivial case? | |||||
For the non-trivial case it shouldn't make a difference really. For the trivial one it does, as otherwise it would never empty m_data. So to avoid code duplication, it's only done here. fvogt: For the non-trivial case it shouldn't make a difference really. For the trivial one it does, as… | |||||
149 | } | 163 | } | ||
150 | 164 | | |||
151 | return length; | 165 | return length; | ||
152 | } | 166 | } | ||
153 | 167 | | |||
154 | bool AccessManagerReply::ignoreContentDisposition(const KIO::MetaData &metaData) | 168 | bool AccessManagerReply::ignoreContentDisposition(const KIO::MetaData &metaData) | ||
155 | { | 169 | { | ||
156 | if (m_ignoreContentDisposition) { | 170 | if (m_ignoreContentDisposition) { | ||
▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Line(s) | 335 | { | |||
390 | } | 404 | } | ||
391 | 405 | | |||
392 | return errCode; | 406 | return errCode; | ||
393 | } | 407 | } | ||
394 | 408 | | |||
395 | void AccessManagerReply::slotData(KIO::Job *kioJob, const QByteArray &data) | 409 | void AccessManagerReply::slotData(KIO::Job *kioJob, const QByteArray &data) | ||
396 | { | 410 | { | ||
397 | Q_UNUSED(kioJob); | 411 | Q_UNUSED(kioJob); | ||
412 | if (data.isEmpty()) { | ||||
413 | return; | ||||
414 | } | ||||
415 | | ||||
416 | qint64 newSizeWithOffset = m_data.size() + data.size(); | ||||
417 | if (newSizeWithOffset <= m_data.capacity()) { | ||||
398 | m_data += data; | 418 | m_data += data; | ||
399 | if (!data.isEmpty()) { | 419 | } else if (newSizeWithOffset - m_offset <= m_data.capacity()) { | ||
400 | emit readyRead(); | 420 | // We get enough space with ::remove. | ||
421 | m_data.remove(0, m_offset); | ||||
422 | m_data += data; | ||||
423 | m_offset = 0; | ||||
424 | } else { | ||||
425 | // We have to resize the array, which implies an expensive memmove. | ||||
426 | // Do it ourselves to save m_offset bytes. | ||||
427 | QByteArray newData; | ||||
428 | // Leave some free space to avoid that every slotData call results in | ||||
429 | // a reallocation. qNextPowerOfTwo is what QByteArray does internally. | ||||
430 | newData.reserve(qNextPowerOfTwo(newSizeWithOffset - m_offset)); | ||||
431 | newData.append(m_data.constData() + m_offset, m_data.size() - m_offset); | ||||
432 | newData.append(data); | ||||
433 | m_data = newData; | ||||
if you swap these two lines (i.e. append to m_data), you have m_data += data in all three branches, and you can move it to the bottom. bruns: if you swap these two lines (i.e. append to m_data), you have `m_data += data` in all three… | |||||
434 | m_offset = 0; | ||||
401 | } | 435 | } | ||
436 | | ||||
437 | emit readyRead(); | ||||
402 | } | 438 | } | ||
403 | 439 | | |||
404 | void AccessManagerReply::slotMimeType(KIO::Job *kioJob, const QString &mimeType) | 440 | void AccessManagerReply::slotMimeType(KIO::Job *kioJob, const QString &mimeType) | ||
405 | { | 441 | { | ||
406 | //qDebug() << kioJob << mimeType; | 442 | //qDebug() << kioJob << mimeType; | ||
407 | setHeader(QNetworkRequest::ContentTypeHeader, mimeType.toUtf8()); | 443 | setHeader(QNetworkRequest::ContentTypeHeader, mimeType.toUtf8()); | ||
408 | readHttpResponseHeaders(kioJob); | 444 | readHttpResponseHeaders(kioJob); | ||
409 | if (m_emitReadyReadOnMetaDataChange) { | 445 | if (m_emitReadyReadOnMetaDataChange) { | ||
▲ Show 20 Lines • Show All 82 Lines • Show Last 20 Lines |
Wouldn't it be better to trim the buffer in slotData, at least in the non-trivial case?