diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp index 742bdf527a0de7a4ed46a922ca98fb6a8492e2b3..a071adbd562366205550de7373b8014d417a42de 100644 --- a/src/core/api/qwebengineurlrequestjob.cpp +++ b/src/core/api/qwebengineurlrequestjob.cpp @@ -115,10 +115,16 @@ QByteArray QWebEngineUrlRequestJob::requestMethod() const /*! Replies to the request with \a device and the MIME type \a contentType. + The user has to be aware that \a device will be used on another thread + until the job is deleted. In case simultaneous access from the main thread + is desired, the user is reponsible for making access to \a device thread-safe + for example by using QMutex. Note that the \a device object is not owned by + the web engine. Therefore, the signal QObject::destroyed() of + QWebEngineUrlRequestJob must be monitored. */ void QWebEngineUrlRequestJob::reply(const QByteArray &contentType, QIODevice *device) { - d_ptr->setReply(contentType, device); + d_ptr->reply(contentType, device); } /*! diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 724a879e0a46bd4ad531144f90dd2fedf48a9b28..47c9b3b4c00ddbd983e768751a8a6497ff1b0513 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -53,47 +53,48 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, const std::string &scheme, QWeakPointer<const BrowserContextAdapter> adapter) : URLRequestJob(request, networkDelegate) - , m_scheme(scheme) - , m_adapter(adapter) - , m_proxy(new URLRequestCustomJobProxy(this)) + , m_proxy(new URLRequestCustomJobProxy(this, scheme, adapter)) + , m_device(nullptr) + , m_error(0) { } URLRequestCustomJob::~URLRequestCustomJob() { - if (m_proxy) - m_proxy->killJob(); -} - -static void startAsync(URLRequestCustomJobProxy *proxy) -{ - proxy->startAsync(); + m_proxy->m_job = nullptr; + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::release, + m_proxy)); + if (m_device && m_device->isOpen()) + m_device->close(); + m_device = nullptr; } void URLRequestCustomJob::Start() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&startAsync, m_proxy)); + base::Bind(&URLRequestCustomJobProxy::initialize, + m_proxy, request()->url(), request()->method())); } void URLRequestCustomJob::Kill() { - if (m_proxy) - m_proxy->killJob(); - m_proxy = 0; - + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (m_device && m_device->isOpen()) + m_device->close(); + m_device = nullptr; + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::release, + m_proxy)); URLRequestJob::Kill(); } bool URLRequestCustomJob::GetMimeType(std::string *mimeType) const { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (!m_proxy) - return false; - QMutexLocker lock(&m_proxy->m_mutex); - if (m_proxy->m_mimeType.size() > 0) { - *mimeType = m_proxy->m_mimeType; + if (m_mimeType.size() > 0) { + *mimeType = m_mimeType; return true; } return false; @@ -102,11 +103,8 @@ bool URLRequestCustomJob::GetMimeType(std::string *mimeType) const bool URLRequestCustomJob::GetCharset(std::string* charset) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (!m_proxy) - return false; - QMutexLocker lock(&m_proxy->m_mutex); - if (m_proxy->m_charset.size() > 0) { - *charset = m_proxy->m_charset; + if (m_charset.size() > 0) { + *charset = m_charset; return true; } return false; @@ -115,11 +113,8 @@ bool URLRequestCustomJob::GetCharset(std::string* charset) bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_code) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (!m_proxy) - return false; - QMutexLocker lock(&m_proxy->m_mutex); - if (m_proxy->m_redirect.is_valid()) { - *location = m_proxy->m_redirect; + if (m_redirect.is_valid()) { + *location = m_redirect; *http_status_code = 303; return true; } @@ -129,17 +124,15 @@ bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_co int URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - Q_ASSERT(m_proxy); - QMutexLocker lock(&m_proxy->m_mutex); - if (m_proxy->m_error) - return m_proxy->m_error; - qint64 rv = m_proxy->m_device ? m_proxy->m_device->read(buf->data(), bufSize) : -1; - if (rv >= 0) + if (m_error) + return m_error; + qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1; + if (rv >= 0) { return static_cast<int>(rv); - else { + } else { // QIODevice::read might have called fail on us. - if (m_proxy->m_error) - return m_proxy->m_error; + if (m_error) + return m_error; return ERR_FAILED; } } diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h index 171786c7bc6156f533145dd179375e73b02e6f06..68a834d48b4a5e3f466305cb5256181ed2719554 100644 --- a/src/core/url_request_custom_job.h +++ b/src/core/url_request_custom_job.h @@ -44,6 +44,8 @@ #include "url/gurl.h" #include <QtCore/QWeakPointer> +QT_FORWARD_DECLARE_CLASS(QIODevice) + namespace QtWebEngineCore { class BrowserContextAdapter; @@ -53,7 +55,10 @@ class URLRequestCustomJobProxy; // A request job that handles reading custom URL schemes class URLRequestCustomJob : public net::URLRequestJob { public: - URLRequestCustomJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate, const std::string &scheme, QWeakPointer<const BrowserContextAdapter> adapter); + URLRequestCustomJob(net::URLRequest *request, + net::NetworkDelegate *networkDelegate, + const std::string &scheme, + QWeakPointer<const BrowserContextAdapter> adapter); void Start() override; void Kill() override; int ReadRawData(net::IOBuffer *buf, int buf_size) override; @@ -65,9 +70,12 @@ protected: virtual ~URLRequestCustomJob(); private: - std::string m_scheme; - QWeakPointer<const BrowserContextAdapter> m_adapter; - URLRequestCustomJobProxy *m_proxy; + scoped_refptr<URLRequestCustomJobProxy> m_proxy; + std::string m_mimeType; + std::string m_charset; + GURL m_redirect; + QIODevice *m_device; + int m_error; friend class URLRequestCustomJobProxy; diff --git a/src/core/url_request_custom_job_delegate.cpp b/src/core/url_request_custom_job_delegate.cpp index 83a6353dc93a78f82e7248b8934a0dc0b358bce6..14de9a812d02e6bd1a3bd54ea1b1cd91755bf196 100644 --- a/src/core/url_request_custom_job_delegate.cpp +++ b/src/core/url_request_custom_job_delegate.cpp @@ -42,45 +42,54 @@ #include "type_conversion.h" #include "net/base/net_errors.h" +#include "content/public/browser/browser_thread.h" #include <QByteArray> namespace QtWebEngineCore { -URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy) - : m_proxy(proxy) +URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, + const QUrl &url, + const QByteArray &method) + : m_proxy(proxy), + m_request(url), + m_method(method) { } URLRequestCustomJobDelegate::~URLRequestCustomJobDelegate() { - m_proxy->unsetJobDelegate(); } QUrl URLRequestCustomJobDelegate::url() const { - return toQt(m_proxy->requestUrl()); + return m_request; } QByteArray URLRequestCustomJobDelegate::method() const { - return QByteArray::fromStdString(m_proxy->requestMethod()); + return m_method; } -void URLRequestCustomJobDelegate::setReply(const QByteArray &contentType, QIODevice *device) +void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { - m_proxy->setReplyMimeType(contentType.toStdString()); - m_proxy->setReplyDevice(device); + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::reply, + m_proxy,contentType.toStdString(),device)); } void URLRequestCustomJobDelegate::abort() { - m_proxy->abort(); + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::abort, + m_proxy)); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) { - m_proxy->redirect(toGurl(url)); + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::redirect, + m_proxy, toGurl(url))); } void URLRequestCustomJobDelegate::fail(Error error) @@ -105,8 +114,11 @@ void URLRequestCustomJobDelegate::fail(Error error) net_error = net::ERR_FAILED; break; } - if (net_error) - m_proxy->fail(net_error); + if (net_error) { + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestCustomJobProxy::fail, + m_proxy, net_error)); + } } } // namespace diff --git a/src/core/url_request_custom_job_delegate.h b/src/core/url_request_custom_job_delegate.h index 732ff8d7ab369fde97e21b7d2f3629270c060cd7..eb99f3576d5af0b8d6eb4dda3ec13e2189c2f39a 100644 --- a/src/core/url_request_custom_job_delegate.h +++ b/src/core/url_request_custom_job_delegate.h @@ -40,6 +40,7 @@ #ifndef URL_REQUEST_CUSTOM_JOB_DELEGATE_H_ #define URL_REQUEST_CUSTOM_JOB_DELEGATE_H_ +#include "base/memory/ref_counted.h" #include "qtwebenginecoreglobal.h" #include <QObject> @@ -68,17 +69,20 @@ public: QUrl url() const; QByteArray method() const; - void setReply(const QByteArray &contentType, QIODevice *device); + void reply(const QByteArray &contentType, QIODevice *device); void redirect(const QUrl& url); void abort(); - void fail(Error); private: - URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy); + URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, + const QUrl &url, + const QByteArray &method); friend class URLRequestCustomJobProxy; - URLRequestCustomJobProxy *m_proxy; + scoped_refptr<URLRequestCustomJobProxy> m_proxy; + QUrl m_request; + QByteArray m_method; }; } // namespace diff --git a/src/core/url_request_custom_job_proxy.cpp b/src/core/url_request_custom_job_proxy.cpp index c6233709e9ae930beaa8284a0a452445bfec5391..d53602c857762b83b67cf0458a520456ce817db1 100644 --- a/src/core/url_request_custom_job_proxy.cpp +++ b/src/core/url_request_custom_job_proxy.cpp @@ -49,217 +49,115 @@ using namespace net; namespace QtWebEngineCore { -URLRequestCustomJobProxy::URLRequestCustomJobProxy(URLRequestCustomJob *job) - : m_mutex(QMutex::Recursive) - , m_job(job) - , m_delegate(0) - , m_error(0) +URLRequestCustomJobProxy::URLRequestCustomJobProxy(URLRequestCustomJob *job, + const std::string &scheme, + QWeakPointer<const BrowserContextAdapter> adapter) + : m_job(job) , m_started(false) - , m_asyncInitialized(false) - , m_weakFactory(this) + , m_scheme(scheme) + , m_delegate(nullptr) + , m_adapter(adapter) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); } URLRequestCustomJobProxy::~URLRequestCustomJobProxy() { - Q_ASSERT(!m_job); - Q_ASSERT(!m_delegate); } -void URLRequestCustomJobProxy::killJob() +void URLRequestCustomJobProxy::release() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); - m_job = 0; - bool doDelete = false; + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (m_delegate) { m_delegate->deleteLater(); - } else { - // Do not delete yet if startAsync has not yet run. - doDelete = m_asyncInitialized; + m_delegate = nullptr; } - if (m_device && m_device->isOpen()) - m_device->close(); - m_device = 0; - m_weakFactory.InvalidateWeakPtrs(); - lock.unlock(); - if (doDelete) - delete this; -} - -void URLRequestCustomJobProxy::unsetJobDelegate() -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - QMutexLocker lock(&m_mutex); - m_delegate = 0; - bool doDelete = false; - if (m_job) - abort(); - else - doDelete = true; - lock.unlock(); - if (doDelete) - delete this; -} - -void URLRequestCustomJobProxy::setReplyMimeType(const std::string &mimeType) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - QMutexLocker lock(&m_mutex); - m_mimeType = mimeType; } +// Fix me: this is never used +/* void URLRequestCustomJobProxy::setReplyCharset(const std::string &charset) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - QMutexLocker lock(&m_mutex); - m_charset = charset; + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + if (!m_job) + return; + m_job->m_charset = charset; } - -void URLRequestCustomJobProxy::setReplyDevice(QIODevice *device) +*/ +void URLRequestCustomJobProxy::reply(std::string mimeType, QIODevice *device) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - QMutexLocker lock(&m_mutex); + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (!m_job) return; - m_device = device; - if (m_device && !m_device->isReadable()) - m_device->open(QIODevice::ReadOnly); + m_job->m_mimeType = mimeType; + m_job->m_device = device; + if (m_job->m_device && !m_job->m_device->isReadable()) + m_job->m_device->open(QIODevice::ReadOnly); - qint64 size = m_device ? m_device->size() : -1; + qint64 size = m_job->m_device ? m_job->m_device->size() : -1; if (size > 0) m_job->set_expected_content_size(size); - if (m_device && m_device->isReadable()) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::notifyStarted, - m_weakFactory.GetWeakPtr())); + if (m_job->m_device && m_job->m_device->isReadable()) { + m_started = true; + m_job->NotifyHeadersComplete(); } else { fail(ERR_INVALID_URL); } } -void URLRequestCustomJobProxy::redirect(const GURL &url) +void URLRequestCustomJobProxy::redirect(GURL url) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - QMutexLocker lock(&m_mutex); - if (m_device || m_error) - return; + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (!m_job) return; - m_redirect = url; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::notifyStarted, - m_weakFactory.GetWeakPtr())); -} - -void URLRequestCustomJobProxy::abort() -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - QMutexLocker lock(&m_mutex); - if (m_device && m_device->isOpen()) - m_device->close(); - m_device = 0; - if (!m_job) + if (m_job->m_device || m_job->m_error) return; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::notifyCanceled, - m_weakFactory.GetWeakPtr())); + m_job->m_redirect = url; + m_started = true; + m_job->NotifyHeadersComplete(); } -void URLRequestCustomJobProxy::notifyCanceled() +void URLRequestCustomJobProxy::abort() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); if (!m_job) return; + if (m_job->m_device && m_job->m_device->isOpen()) + m_job->m_device->close(); + m_job->m_device = nullptr; if (m_started) m_job->NotifyCanceled(); else m_job->NotifyStartError(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); } -void URLRequestCustomJobProxy::notifyStarted() -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); - if (!m_job) - return; - Q_ASSERT(!m_started); - m_started = true; - m_job->NotifyHeadersComplete(); -} - void URLRequestCustomJobProxy::fail(int error) -{ - QMutexLocker lock(&m_mutex); - m_error = error; - if (content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) - return; - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (!m_job) - return; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::notifyFailure, - m_weakFactory.GetWeakPtr())); -} - -void URLRequestCustomJobProxy::notifyFailure() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); if (!m_job) return; - if (m_device) - m_device->close(); + m_job->m_error = error; + if (m_job->m_device) + m_job->m_device->close(); if (!m_started) - m_job->NotifyStartError(URLRequestStatus::FromError(m_error)); + m_job->NotifyStartError(URLRequestStatus::FromError(error)); // else we fail on the next read, or the read that might already be in progress } -GURL URLRequestCustomJobProxy::requestUrl() -{ - QMutexLocker lock(&m_mutex); - if (!m_job) - return GURL(); - return m_job->request()->url(); -} - -std::string URLRequestCustomJobProxy::requestMethod() -{ - QMutexLocker lock(&m_mutex); - if (!m_job) - return std::string(); - return m_job->request()->method(); -} - -void URLRequestCustomJobProxy::startAsync() +void URLRequestCustomJobProxy::initialize(GURL url, std::string method) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - Q_ASSERT(!m_started); Q_ASSERT(!m_delegate); - QMutexLocker lock(&m_mutex); - if (!m_job) { - lock.unlock(); - delete this; - return; - } QWebEngineUrlSchemeHandler *schemeHandler = 0; - QSharedPointer<const BrowserContextAdapter> browserContext = m_job->m_adapter.toStrongRef(); + QSharedPointer<const BrowserContextAdapter> browserContext = m_adapter.toStrongRef(); if (browserContext) - schemeHandler = browserContext->customUrlSchemeHandlers()[toQByteArray(m_job->m_scheme)]; + schemeHandler = browserContext->customUrlSchemeHandlers()[toQByteArray(m_scheme)]; if (schemeHandler) { - m_delegate = new URLRequestCustomJobDelegate(this); - m_asyncInitialized = true; + m_delegate = new URLRequestCustomJobDelegate(this, toQt(url), + QByteArray::fromStdString(method)); QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); schemeHandler->requestStarted(requestJob); - } else { - lock.unlock(); - abort(); - delete this; - return; } } diff --git a/src/core/url_request_custom_job_proxy.h b/src/core/url_request_custom_job_proxy.h index b8c7b5c67ed33bb00f9a28c1ccbcfbff4369e4b4..df7171f5e7acfb3615a9ffb73ca9e105c2bb9ccf 100644 --- a/src/core/url_request_custom_job_proxy.h +++ b/src/core/url_request_custom_job_proxy.h @@ -40,11 +40,9 @@ #ifndef URL_REQUEST_CUSTOM_JOB_PROXY_H_ #define URL_REQUEST_CUSTOM_JOB_PROXY_H_ -#include "url/gurl.h" #include "base/memory/weak_ptr.h" -#include <QtCore/QMutex> -#include <QtCore/QPointer> - +#include "url/gurl.h" +#include <QtCore/QWeakPointer> QT_FORWARD_DECLARE_CLASS(QIODevice) @@ -52,44 +50,35 @@ namespace QtWebEngineCore { class URLRequestCustomJob; class URLRequestCustomJobDelegate; +class BrowserContextAdapter; // Used to comunicate between URLRequestCustomJob living on the IO thread // and URLRequestCustomJobDelegate living on the UI thread. -class URLRequestCustomJobProxy { +class URLRequestCustomJobProxy + : public base::RefCountedThreadSafe<URLRequestCustomJobProxy> { + public: - URLRequestCustomJobProxy(URLRequestCustomJob *job); + URLRequestCustomJobProxy(URLRequestCustomJob *job, + const std::string &scheme, + QWeakPointer<const BrowserContextAdapter> adapter); ~URLRequestCustomJobProxy(); - void setReplyMimeType(const std::string &); - void setReplyCharset(const std::string &); - void setReplyDevice(QIODevice *); - - void redirect(const GURL &url); - void fail(int); + //void setReplyCharset(const std::string &); + void reply(std::string mimeType, QIODevice *device); + void redirect(GURL url); void abort(); + void fail(int error); + void release(); + void initialize(GURL url, std::string method); - void killJob(); - void unsetJobDelegate(); - - void startAsync(); - void notifyStarted(); - void notifyFailure(); - void notifyCanceled(); - - GURL requestUrl(); - std::string requestMethod(); - - QMutex m_mutex; - QPointer<QIODevice> m_device; + //IO thread owned URLRequestCustomJob *m_job; - URLRequestCustomJobDelegate *m_delegate; - std::string m_mimeType; - std::string m_charset; - int m_error; - GURL m_redirect; bool m_started; - bool m_asyncInitialized; - base::WeakPtrFactory<URLRequestCustomJobProxy> m_weakFactory; + + //UI thread owned + std::string m_scheme; + URLRequestCustomJobDelegate *m_delegate; + QWeakPointer<const BrowserContextAdapter> m_adapter; }; } // namespace QtWebEngineCore