diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-24 15:47:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-10-25 11:02:41 +0000 |
commit | 684cfe05641ba9f3abc7e128d9dab5b331ef0689 (patch) | |
tree | ebaa3721e883360c5313a2ba5f1a9232d880ec6e /src | |
parent | d96f8495b59878f50223a81a734ce0983539d8cf (diff) |
Support streaming QIODevices in custom URL scheme handlers
We didn't handle the case where the QIODevice does not have all the data
available all the time.
Change-Id: I6aea8ed48ba9ed297efb907b8f6e5c5fc2a18abd
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/url_request_custom_job.cpp | 62 | ||||
-rw-r--r-- | src/core/url_request_custom_job.h | 4 | ||||
-rw-r--r-- | src/core/url_request_custom_job_delegate.cpp | 11 | ||||
-rw-r--r-- | src/core/url_request_custom_job_delegate.h | 3 | ||||
-rw-r--r-- | src/core/url_request_custom_job_proxy.cpp | 7 | ||||
-rw-r--r-- | src/core/url_request_custom_job_proxy.h | 6 |
6 files changed, 88 insertions, 5 deletions
diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 47c9b3b4c..b49135f79 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -56,6 +56,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, , m_proxy(new URLRequestCustomJobProxy(this, scheme, adapter)) , m_device(nullptr) , m_error(0) + , m_pendingReadSize(0) + , m_pendingReadPos(0) + , m_pendingReadBuffer(nullptr) { } @@ -83,6 +86,12 @@ void URLRequestCustomJob::Kill() DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (m_device && m_device->isOpen()) m_device->close(); + if (m_pendingReadBuffer) { + m_pendingReadBuffer->Release(); + m_pendingReadBuffer = nullptr; + m_pendingReadSize = 0; + m_pendingReadPos = 0; + } m_device = nullptr; content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&URLRequestCustomJobProxy::release, @@ -127,13 +136,64 @@ int URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize) if (m_error) return m_error; qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1; - if (rv >= 0) { + if (rv > 0) { return static_cast<int>(rv); + } else if (rv == 0) { + // Returning zero is interpreted as EOF by Chromium, so only + // return zero if we are the end of the file. + if (m_device->atEnd()) + return 0; + // Otherwise return IO_PENDING and call ReadRawDataComplete when we have data + // for them. + buf->AddRef(); + m_pendingReadPos = 0; + m_pendingReadSize = bufSize; + m_pendingReadBuffer = buf; + return ERR_IO_PENDING; } else { // QIODevice::read might have called fail on us. if (m_error) return m_error; + if (m_device && m_device->atEnd()) + return 0; return ERR_FAILED; } } + +void URLRequestCustomJob::notifyReadyRead() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!m_device) + return; + if (!m_pendingReadSize) + return; + Q_ASSERT(m_pendingReadBuffer); + if (!m_pendingReadBuffer) + return; + + qint64 rv = m_device->read(m_pendingReadBuffer->data() + m_pendingReadPos, m_pendingReadSize - m_pendingReadPos); + if (rv == 0) + return; + if (rv < 0) { + if (m_error) + rv = m_error; + else if (m_device->atEnd()) + rv = 0; + else + rv = ERR_FAILED; + } else { + m_pendingReadPos += rv; + if (m_pendingReadPos < m_pendingReadSize && !m_device->atEnd()) + return; + rv = m_pendingReadPos; + } + // killJob may be called from ReadRawDataComplete + net::IOBuffer *buf = m_pendingReadBuffer; + m_pendingReadBuffer = nullptr; + m_pendingReadSize = 0; + m_pendingReadPos = 0; + ReadRawDataComplete(rv); + buf->Release(); +} + } // namespace diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h index 68a834d48..021cf3204 100644 --- a/src/core/url_request_custom_job.h +++ b/src/core/url_request_custom_job.h @@ -70,12 +70,16 @@ protected: virtual ~URLRequestCustomJob(); private: + void notifyReadyRead(); scoped_refptr<URLRequestCustomJobProxy> m_proxy; std::string m_mimeType; std::string m_charset; GURL m_redirect; QIODevice *m_device; int m_error; + int m_pendingReadSize; + int m_pendingReadPos; + net::IOBuffer *m_pendingReadBuffer; friend class URLRequestCustomJobProxy; diff --git a/src/core/url_request_custom_job_delegate.cpp b/src/core/url_request_custom_job_delegate.cpp index 14de9a812..6b82cebb5 100644 --- a/src/core/url_request_custom_job_delegate.cpp +++ b/src/core/url_request_custom_job_delegate.cpp @@ -73,16 +73,23 @@ QByteArray URLRequestCustomJobDelegate::method() const void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { + if (device) + QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead); content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobProxy::reply, m_proxy,contentType.toStdString(),device)); } +void URLRequestCustomJobDelegate::slotReadyRead() +{ + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::readyRead, m_proxy)); +} + void URLRequestCustomJobDelegate::abort() { content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::abort, - m_proxy)); + base::Bind(&URLRequestCustomJobProxy::abort, m_proxy)); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) diff --git a/src/core/url_request_custom_job_delegate.h b/src/core/url_request_custom_job_delegate.h index eb99f3576..3f5e6d591 100644 --- a/src/core/url_request_custom_job_delegate.h +++ b/src/core/url_request_custom_job_delegate.h @@ -74,6 +74,9 @@ public: void abort(); void fail(Error); +private Q_SLOTS: + void slotReadyRead(); + private: URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, diff --git a/src/core/url_request_custom_job_proxy.cpp b/src/core/url_request_custom_job_proxy.cpp index d53602c85..832d3d11e 100644 --- a/src/core/url_request_custom_job_proxy.cpp +++ b/src/core/url_request_custom_job_proxy.cpp @@ -144,6 +144,13 @@ void URLRequestCustomJobProxy::fail(int error) // else we fail on the next read, or the read that might already be in progress } +void URLRequestCustomJobProxy::readyRead() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (m_job) + m_job->notifyReadyRead(); +} + void URLRequestCustomJobProxy::initialize(GURL url, std::string method) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); diff --git a/src/core/url_request_custom_job_proxy.h b/src/core/url_request_custom_job_proxy.h index df7171f5e..3ea30a4e1 100644 --- a/src/core/url_request_custom_job_proxy.h +++ b/src/core/url_request_custom_job_proxy.h @@ -63,6 +63,7 @@ public: QWeakPointer<const BrowserContextAdapter> adapter); ~URLRequestCustomJobProxy(); + // Called from URLRequestCustomJobDelegate via post: //void setReplyCharset(const std::string &); void reply(std::string mimeType, QIODevice *device); void redirect(GURL url); @@ -70,12 +71,13 @@ public: void fail(int error); void release(); void initialize(GURL url, std::string method); + void readyRead(); - //IO thread owned + // IO thread owned: URLRequestCustomJob *m_job; bool m_started; - //UI thread owned + // UI thread owned: std::string m_scheme; URLRequestCustomJobDelegate *m_delegate; QWeakPointer<const BrowserContextAdapter> m_adapter; |