summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-24 15:47:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-10-25 11:02:41 +0000
commit684cfe05641ba9f3abc7e128d9dab5b331ef0689 (patch)
treeebaa3721e883360c5313a2ba5f1a9232d880ec6e /src
parentd96f8495b59878f50223a81a734ce0983539d8cf (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.cpp62
-rw-r--r--src/core/url_request_custom_job.h4
-rw-r--r--src/core/url_request_custom_job_delegate.cpp11
-rw-r--r--src/core/url_request_custom_job_delegate.h3
-rw-r--r--src/core/url_request_custom_job_proxy.cpp7
-rw-r--r--src/core/url_request_custom_job_proxy.h6
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;