WebPage: network timeout setting.

Fixes issue #11129.

https://github.com/ariya/phantomjs/issues/11129
1.9
Tom Aizenberg 2013-03-12 17:38:37 +01:00 committed by Ariya Hidayat
parent b16a5348a9
commit 52883ced68
7 changed files with 106 additions and 0 deletions

View File

@ -58,6 +58,7 @@
#define PAGE_SETTINGS_USERNAME "userName"
#define PAGE_SETTINGS_PASSWORD "password"
#define PAGE_SETTINGS_MAX_AUTH_ATTEMPTS "maxAuthAttempts"
#define PAGE_SETTINGS_RESOURCE_TIMEOUT "resourceTimeout"
#define PAGE_SETTINGS_WEB_SECURITY_ENABLED "webSecurityEnabled"
#define PAGE_SETTINGS_JS_CAN_OPEN_WINDOWS "javascriptCanOpenWindows"
#define PAGE_SETTINGS_JS_CAN_CLOSE_WINDOWS "javascriptCanCloseWindows"

View File

@ -254,6 +254,8 @@ function decorateNewPage(opts, page) {
definePageSignalHandler(page, handlers, "onResourceError", "resourceError");
definePageSignalHandler(page, handlers, "onResourceTimeout", "resourceTimeout");
definePageSignalHandler(page, handlers, "onAlert", "javaScriptAlertSent");
definePageSignalHandler(page, handlers, "onConsoleMessage", "javaScriptConsoleMessageSent");

View File

@ -67,6 +67,12 @@ static const char *toString(QNetworkAccessManager::Operation op)
return str;
}
TimeoutTimer::TimeoutTimer(QObject* parent)
: QTimer(parent)
{
}
JsNetworkRequest::JsNetworkRequest(QNetworkRequest* request, QObject* parent)
: QObject(parent)
{
@ -97,6 +103,7 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config
, m_idCounter(0)
, m_networkDiskCache(0)
, m_sslConfiguration(QSslConfiguration::defaultConfiguration())
, m_resourceTimeout(0)
{
setCookieJar(CookieJar::instance());
@ -141,6 +148,11 @@ void NetworkAccessManager::setPassword(const QString &password)
m_password = password;
}
void NetworkAccessManager::setResourceTimeout(int resourceTimeout)
{
m_resourceTimeout = resourceTimeout;
}
void NetworkAccessManager::setMaxAuthAttempts(int maxAttempts)
{
m_maxAuthAttempts = maxAttempts;
@ -223,6 +235,19 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
// reparent jsNetworkRequest to make sure that it will be destroyed with QNetworkReply
jsNetworkRequest.setParent(reply);
// If there is a timeout set, create a TimeoutTimer
if(m_resourceTimeout > 0){
TimeoutTimer *nt = new TimeoutTimer(reply);
nt->reply = reply; // We need the reply object in order to abort it later on.
nt->data = data;
nt->setInterval(m_resourceTimeout);
nt->setSingleShot(true);
nt->start();
connect(nt, SIGNAL(timeout()), this, SLOT(handleTimeout()));
}
m_ids[reply] = m_idCounter;
connect(reply, SIGNAL(readyRead()), this, SLOT(handleStarted()));
@ -232,6 +257,22 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
return reply;
}
void NetworkAccessManager::handleTimeout()
{
TimeoutTimer *nt = qobject_cast<TimeoutTimer*>(sender());
if(!nt->reply)
return;
nt->data["errorCode"] = 408;
nt->data["errorString"] = "Network timeout on resource.";
emit resourceTimeout(nt->data);
// Abort the reply that we attached to the Network Timeout
nt->reply->abort();
}
void NetworkAccessManager::handleStarted()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());

View File

@ -37,11 +37,22 @@
#include <QNetworkReply>
#include <QSet>
#include <QSslConfiguration>
#include <QTimer>
class Config;
class QNetworkDiskCache;
class QSslConfiguration;
class TimeoutTimer : public QTimer
{
Q_OBJECT
public:
TimeoutTimer(QObject *parent = 0);
QNetworkReply *reply;
QVariantMap data;
};
class JsNetworkRequest : public QObject
{
Q_OBJECT
@ -62,6 +73,7 @@ public:
void setUserName(const QString &userName);
void setPassword(const QString &password);
void setMaxAuthAttempts(int maxAttempts);
void setResourceTimeout(int resourceTimeout);
void setCustomHeaders(const QVariantMap &headers);
QVariantMap customHeaders() const;
@ -71,6 +83,7 @@ protected:
bool m_ignoreSslErrors;
int m_authAttempts;
int m_maxAuthAttempts;
int m_resourceTimeout;
QString m_userName;
QString m_password;
QNetworkReply *createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0);
@ -80,6 +93,7 @@ signals:
void resourceRequested(const QVariant& data, QObject *);
void resourceReceived(const QVariant& data);
void resourceError(const QVariant& data);
void resourceTimeout(const QVariant& data);
private slots:
void handleStarted();
@ -87,6 +101,7 @@ private slots:
void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
void handleSslErrors(const QList<QSslError> &errors);
void handleNetworkError();
void handleTimeout();
private:
QHash<QNetworkReply*, int> m_ids;

View File

@ -386,6 +386,8 @@ WebPage::WebPage(QObject *parent, const QUrl &baseUrl)
SIGNAL(resourceReceived(QVariant)));
connect(m_networkAccessManager, SIGNAL(resourceError(QVariant)),
SIGNAL(resourceError(QVariant)));
connect(m_networkAccessManager, SIGNAL(resourceTimeout(QVariant)),
SIGNAL(resourceTimeout(QVariant)));
m_customWebPage->setViewportSize(QSize(400, 300));
}
@ -583,6 +585,10 @@ void WebPage::applySettings(const QVariantMap &def)
if (def.contains(PAGE_SETTINGS_MAX_AUTH_ATTEMPTS))
m_networkAccessManager->setMaxAuthAttempts(def[PAGE_SETTINGS_MAX_AUTH_ATTEMPTS].toInt());
if (def.contains(PAGE_SETTINGS_RESOURCE_TIMEOUT))
m_networkAccessManager->setResourceTimeout(def[PAGE_SETTINGS_RESOURCE_TIMEOUT].toInt());
}
QString WebPage::userAgent() const

View File

@ -469,6 +469,7 @@ signals:
void resourceRequested(const QVariant &requestData, QObject *request);
void resourceReceived(const QVariant &resource);
void resourceError(const QVariant &errorData);
void resourceTimeout(const QVariant &errorData);
void urlChanged(const QUrl &url);
void navigationRequested(const QUrl &url, const QString &navigationType, bool navigationLocked, bool isMainFrame);
void rawPageCreated(QObject *page);

View File

@ -1280,6 +1280,18 @@ describe("WebPage construction with options", function () {
checkScrollPosition(new WebPage(opts), opts.scrollPosition);
});
describe("specifying timeout", function () {
var opts = {
settings: {
timeout: 100 // time in ms
}
};
var page = new WebPage(opts);
it("should have timeout as "+opts.settings.timeout,function () {
expect(page.settings.timeout).toEqual(opts.settings.timeout);
});
});
describe("specifying userAgent", function () {
var opts = {
settings: {
@ -1584,6 +1596,34 @@ describe("WebPage opening and closing of windows/child-pages", function(){
});
});
describe("WebPage timeout handling", function(){
it("should call 'onResourceTimeout' on timeout", function(){
var p = require("webpage").create(),
spy;
// assume that requesting a web page will take longer than a millisecond
p.settings.resourceTimeout = 1;
spy = jasmine.createSpy("onResourceTimeout spy");
p.onResourceTimeout = spy;
expect(spy.calls.length).toEqual(0);
p.open("http://www.google.com:81/");
waitsFor(function() {
return spy.calls.length==1;
}, "after 1+ milliseconds 'onResourceTimeout' should have been invoked", 10);
runs(function() {
expect(spy).toHaveBeenCalled(); //< called
expect(spy.calls.length).toEqual(1); //< only once
expect(1).toEqual(1);
});
});
});
describe("WebPage closing notification/alerting", function(){
it("should call 'onClosing' when 'page.close()' is called", function(){
var p = require("webpage").create(),