Fix memory leak of response.

Turns Response into a QObject and sets parent to the
command that emits it.

Each Command is also a child of the decorator commands,
Timeout and PageLoading commnds, so that deleting the
top level command will delete all the children.

See discussion in #430.
This commit is contained in:
Sean Geoghegan 2012-12-12 17:17:54 +10:30 committed by Matthew Horan
parent 1cc1428ee4
commit 77811ca9ba
44 changed files with 83 additions and 59 deletions

View File

@ -13,6 +13,6 @@ void Authenticate::start() {
networkAccessManager->setUserName(username);
networkAccessManager->setPassword(password);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -9,5 +9,5 @@ ClearCookies::ClearCookies(WebPageManager *manager, QStringList &arguments, QObj
void ClearCookies::start()
{
manager()->cookieJar()->clearCookies();
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -7,5 +7,5 @@ ClearPromptText::ClearPromptText(WebPageManager *manager, QStringList &arguments
void ClearPromptText::start()
{
page()->setPromptText(QString());
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -6,3 +6,12 @@ Command::Command(QObject *parent) : QObject(parent) {
QString Command::toString() const {
return metaObject()->className();
}
void Command::emitFinished(bool success) {
emit finished(new Response(success, this));
}
void Command::emitFinished(bool success, QString message) {
emit finished(new Response(success, message, this));
}

View File

@ -3,6 +3,7 @@
#include <QObject>
#include "Response.h"
#include <QString>
class Command : public QObject {
Q_OBJECT
@ -12,6 +13,10 @@ class Command : public QObject {
virtual void start() = 0;
virtual QString toString() const;
protected:
void emitFinished(bool success);
void emitFinished(bool success, QString message);
signals:
void finished(Response *response);
};

View File

@ -43,13 +43,15 @@ void Connection::pendingLoadFinished(bool success) {
void Connection::writePageLoadFailure() {
m_pageSuccess = true;
QString message = currentPage()->failureString();
writeResponse(new Response(false, message));
Response *response = new Response(false, message, this);
writeResponse(response);
delete response;
}
void Connection::finishCommand(Response *response) {
m_pageSuccess = true;
sender()->deleteLater();
writeResponse(response);
sender()->deleteLater();
}
void Connection::writeResponse(Response *response) {
@ -64,7 +66,6 @@ void Connection::writeResponse(Response *response) {
QString messageLength = QString::number(messageUtf8.size()) + "\n";
m_socket->write(messageLength.toAscii());
m_socket->write(messageUtf8);
delete response;
}
WebPage *Connection::currentPage() {

View File

@ -6,6 +6,6 @@ ConsoleMessages::ConsoleMessages(WebPageManager *manager, QStringList &arguments
}
void ConsoleMessages::start() {
emit finished(new Response(true, page()->consoleMessages()));
emitFinished(true, page()->consoleMessages());
}

View File

@ -9,6 +9,6 @@ void CurrentUrl::start() {
QStringList arguments;
QVariant result = page()->invokeCapybaraFunction("currentUrl", arguments);
QString url = result.toString();
emit finished(new Response(true, url));
emitFinished(true, url);
}

View File

@ -6,5 +6,5 @@ EnableLogging::EnableLogging(WebPageManager *manager, QStringList &arguments, QO
void EnableLogging::start() {
manager()->enableLogging();
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -10,7 +10,7 @@ Evaluate::Evaluate(WebPageManager *manager, QStringList &arguments, QObject *par
void Evaluate::start() {
QVariant result = page()->currentFrame()->evaluateJavaScript(arguments()[0]);
addVariant(result);
emit finished(new Response(true, m_buffer));
emitFinished(true, m_buffer);
}
void Evaluate::addVariant(QVariant &object) {

View File

@ -9,9 +9,9 @@ void Execute::start() {
QString script = arguments()[0] + QString("; 'success'");
QVariant result = page()->currentFrame()->evaluateJavaScript(script);
if (result.isValid()) {
emit finished(new Response(true));
emitFinished(true);
} else {
emit finished(new Response(false, QString("Javascript failed to execute")));
emitFinished(false, QString("Javascript failed to execute"));
}
}

View File

@ -12,9 +12,9 @@ void Find::start() {
if (result.isValid()) {
message = result.toString();
emit finished(new Response(true, message));
emitFinished(true, message);
} else {
emit finished(new Response(false, QString("Invalid XPath expression")));
emitFinished(false, QString("Invalid XPath expression"));
}
}

View File

@ -51,7 +51,7 @@ void FrameFocus::focusId(QString name) {
void FrameFocus::focusParent() {
if (page()->currentFrame()->parentFrame() == 0) {
emit finished(new Response(false, QString("Already at parent frame.")));
emitFinished(false, QString("Already at parent frame."));
} else {
page()->currentFrame()->parentFrame()->setFocus();
success();
@ -59,9 +59,9 @@ void FrameFocus::focusParent() {
}
void FrameFocus::frameNotFound() {
emit finished(new Response(false, QString("Unable to locate frame. ")));
emitFinished(false, QString("Unable to locate frame. "));
}
void FrameFocus::success() {
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -15,5 +15,5 @@ void GetCookies::start()
m_buffer.append(cookie.toRawForm());
m_buffer.append("\n");
}
emit finished(new Response(true, m_buffer));
emitFinished(true, m_buffer);
}

View File

@ -5,5 +5,5 @@ GetTimeout::GetTimeout(WebPageManager *manager, QStringList &arguments, QObject
}
void GetTimeout::start() {
emit finished(new Response(true, QString::number(manager()->getTimeout())));
emitFinished(true, QString::number(manager()->getTimeout()));
}

View File

@ -7,5 +7,5 @@ GetWindowHandle::GetWindowHandle(WebPageManager *manager, QStringList &arguments
}
void GetWindowHandle::start() {
emit finished(new Response(true, page()->uuid()));
emitFinished(true, page()->uuid());
}

View File

@ -16,5 +16,5 @@ void GetWindowHandles::start() {
handles += stringList.join(",") + "]";
emit finished(new Response(true, handles));
emitFinished(true, handles);
}

View File

@ -15,5 +15,5 @@ void Header::start() {
} else {
networkAccessManager->addHeader(key, value);
}
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -11,6 +11,6 @@ void Headers::start() {
foreach(QNetworkReply::RawHeaderPair header, page()->pageHeaders())
headers << header.first+": "+header.second;
emit finished(new Response(true, headers.join("\n")));
emitFinished(true, headers.join("\n"));
}

View File

@ -8,6 +8,6 @@ IgnoreSslErrors::IgnoreSslErrors(WebPageManager *manager, QStringList &arguments
void IgnoreSslErrors::start() {
manager()->setIgnoreSslErrors(true);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -6,5 +6,5 @@ JavascriptAlertMessages::JavascriptAlertMessages(WebPageManager *manager, QStrin
void JavascriptAlertMessages::start()
{
emit finished(new Response(true, page()->alertMessages()));
emitFinished(true, page()->alertMessages());
}

View File

@ -6,5 +6,5 @@ JavascriptConfirmMessages::JavascriptConfirmMessages(WebPageManager *manager, QS
void JavascriptConfirmMessages::start()
{
emit finished(new Response(true, page()->confirmMessages()));
emitFinished(true, page()->confirmMessages());
}

View File

@ -6,5 +6,5 @@ JavascriptPromptMessages::JavascriptPromptMessages(WebPageManager *manager, QStr
void JavascriptPromptMessages::start()
{
emit finished(new Response(true, page()->promptMessages()));
emitFinished(true, page()->promptMessages());
}

View File

@ -10,7 +10,7 @@ void Node::start() {
QString functionName = functionArguments.takeFirst();
QVariant result = page()->invokeCapybaraFunction(functionName, functionArguments);
QString attributeValue = result.toString();
emit finished(new Response(true, attributeValue));
emitFinished(true, attributeValue);
}
QString Node::toString() const {

View File

@ -8,6 +8,6 @@ NullCommand::NullCommand(QString name, QObject *parent) : Command(parent) {
void NullCommand::start() {
QString failure = QString("[Capybara WebKit] Unknown command: ") + m_name + "\n";
emit finished(new Response(false, failure));
emitFinished(false, failure);
}

View File

@ -9,6 +9,7 @@ PageLoadingCommand::PageLoadingCommand(Command *command, WebPageManager *manager
m_pageLoadingFromCommand = false;
m_pageSuccess = true;
m_pendingResponse = NULL;
m_command->setParent(this);
}
void PageLoadingCommand::start() {
@ -29,7 +30,7 @@ void PageLoadingCommand::pendingLoadFinished(bool success) {
emit finished(m_pendingResponse);
} else {
QString message = m_manager->currentPage()->failureString();
emit finished(new Response(false, message));
emitFinished(false, message);
}
}
}
@ -43,7 +44,7 @@ void PageLoadingCommand::pageLoadingFromCommand() {
void PageLoadingCommand::commandFinished(Response *response) {
disconnect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
m_manager->logger() << "Finished" << m_command->toString() << "with response" << response->toString();
m_command->deleteLater();
if (m_pageLoadingFromCommand)
m_pendingResponse = response;
else

View File

@ -15,5 +15,5 @@ void Render::start() {
bool result = page()->render( imagePath );
emit finished(new Response(result));
emitFinished(result);
}

View File

@ -10,6 +10,6 @@ void Reset::start() {
manager()->reset();
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -12,6 +12,6 @@ void ResizeWindow::start() {
QSize size(width, height);
page()->setViewportSize(size);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -1,17 +1,17 @@
#include "Response.h"
#include <iostream>
Response::Response(bool success, QString message) {
Response::Response(bool success, QString message, QObject *parent) : QObject(parent) {
m_success = success;
m_message = message.toUtf8();
}
Response::Response(bool success, QByteArray message) {
Response::Response(bool success, QByteArray message, QObject *parent) : QObject(parent) {
m_success = success;
m_message = message;
}
Response::Response(bool success) {
Response::Response(bool success, QObject *parent) : QObject(parent) {
m_success = success;
}

View File

@ -1,11 +1,17 @@
#ifndef RESPONSE_H
#define RESPONSE_H
#include <QObject>
#include <QString>
#include <QByteArray>
class Response {
class Response : public QObject {
Q_OBJECT
public:
Response(bool success, QString message);
Response(bool success, QByteArray message);
Response(bool success);
Response(bool success, QString message, QObject *parent);
Response(bool success, QByteArray message, QObject *parent);
Response(bool success, QObject *parent);
bool isSuccess() const;
QByteArray message() const;
QString toString() const;
@ -14,3 +20,6 @@ class Response {
bool m_success;
QByteArray m_message;
};
#endif

View File

@ -7,5 +7,5 @@ SetConfirmAction::SetConfirmAction(WebPageManager *manager, QStringList &argumen
void SetConfirmAction::start()
{
page()->setConfirmAction(arguments()[0]);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -11,5 +11,5 @@ void SetCookie::start()
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(arguments()[0].toAscii());
NetworkCookieJar *jar = manager()->cookieJar();
jar->overwriteCookies(cookies);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -7,5 +7,5 @@ SetPromptAction::SetPromptAction(WebPageManager *manager, QStringList &arguments
void SetPromptAction::start()
{
page()->setPromptAction(arguments()[0]);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -7,5 +7,5 @@ SetPromptText::SetPromptText(WebPageManager *manager, QStringList &arguments, QO
void SetPromptText::start()
{
page()->setPromptText(arguments()[0]);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -19,5 +19,5 @@ void SetProxy::start()
arguments()[3]);
page()->networkAccessManager()->setProxy(proxy);
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -8,5 +8,5 @@ SetSkipImageLoading::SetSkipImageLoading(WebPageManager *manager, QStringList &a
void SetSkipImageLoading::start() {
page()->setSkipImageLoading(arguments().contains("true"));
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -11,9 +11,9 @@ void SetTimeout::start() {
if (ok) {
manager()->setTimeout(timeout);
emit finished(new Response(true));
emitFinished(true);
} else {
emit finished(new Response(false, QString("Invalid value for timeout")));
emitFinished(false, QString("Invalid value for timeout"));
}
}

View File

@ -10,6 +10,6 @@ SetUrlBlacklist::SetUrlBlacklist(WebPageManager *manager, QStringList &arguments
void SetUrlBlacklist::start() {
NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
networkAccessManager->setUrlBlacklist(arguments());
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -8,6 +8,6 @@ Status::Status(WebPageManager *manager, QStringList &arguments, QObject *parent)
void Status::start() {
int status = page()->getLastStatus();
emit finished(new Response(true, QString::number(status)));
emitFinished(true, QString::number(status));
}

View File

@ -10,6 +10,7 @@ TimeoutCommand::TimeoutCommand(Command *command, WebPageManager *manager, QObjec
m_manager = manager;
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_command->setParent(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
connect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
}
@ -44,7 +45,7 @@ void TimeoutCommand::pendingLoadFinished(bool success) {
disconnect(m_timer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
disconnect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
disconnect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
emit finished(new Response(false, m_manager->currentPage()->failureString()));
emitFinished(false, m_manager->currentPage()->failureString());
}
}
@ -57,15 +58,13 @@ void TimeoutCommand::commandTimeout() {
disconnect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
disconnect(m_command, SIGNAL(finished(Response *)), this, SLOT(commandFinished(Response *)));
m_manager->currentPage()->triggerAction(QWebPage::Stop);
m_command->deleteLater();
emit finished(new Response(false, QString("timeout")));
emit finished(new Response(false, QString("timeout"), this));
}
void TimeoutCommand::commandFinished(Response *response) {
disconnect(m_timer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
disconnect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
disconnect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
m_command->deleteLater();
emit finished(response);
}

View File

@ -9,5 +9,5 @@ Visit::Visit(WebPageManager *manager, QStringList &arguments, QObject *parent) :
void Visit::start() {
QUrl requestedUrl = QUrl::fromEncoded(arguments()[0].toUtf8(), QUrl::StrictMode);
page()->currentFrame()->load(QUrl(requestedUrl));
emit finished(new Response(true));
emitFinished(true);
}

View File

@ -12,12 +12,12 @@ void WindowFocus::start() {
}
void WindowFocus::windowNotFound() {
emit finished(new Response(false, QString("Unable to locate window. ")));
emitFinished(false, QString("Unable to locate window. "));
}
void WindowFocus::success(WebPage *page) {
page->setFocus();
emit finished(new Response(true));
emitFinished(true);
}
void WindowFocus::focusWindow(QString selector) {

View File

@ -12,5 +12,5 @@ void Body::start() {
else
result = page()->currentFrame()->toHtml();
emit finished(new Response(true, result));
emitFinished(true, result);
}