Add blacklisting support to webkit server.

Adds a SetBlacklist command that takes a list of URLs
which will be black listed by the WebKit Server. When
a request is made to one these URLs webkit_server will
intercept the request and return a NoOpReply which contains
no content.
This commit is contained in:
Sean Geoghegan 2012-10-09 14:56:33 +11:00 committed by Joe Ferris
parent 213229d850
commit f755b1f277
11 changed files with 201 additions and 11 deletions

View File

@ -141,6 +141,10 @@ module Capybara::Webkit
command("ClearPromptText")
end
def url_blacklist=(black_list)
command("SetUrlBlacklist", *Array(black_list))
end
def command(name, *args)
@connection.puts name
@connection.puts args.size

View File

@ -1833,6 +1833,73 @@ describe Capybara::Webkit::Driver do
end
end
describe "url blacklisting" do
let(:driver) do
driver_for_app do
get "/" do
<<-HTML
<html>
<body>
<script src="/script"></script>
<iframe src="http://example.com/path" id="frame1"></iframe>
<iframe src="http://example.org/path/to/file" id="frame2"></iframe>
<iframe src="/frame" id="frame3"></iframe>
</body>
</html>
HTML
end
get "/frame" do
<<-HTML
<html>
<body>
<p>Inner</p>
</body>
</html>
HTML
end
get "/script" do
<<-JS
document.write('<p>Script Run</p>')
JS
end
end
end
before do
driver.browser.url_blacklist = ["http://example.org/path/to/file",
"http://example.com",
"#{Capybara.app_host}/script"]
end
it "should not fetch urls blocked by host" do
driver.visit("/")
driver.within_frame('frame1') do
driver.find("//body").first.text.should be_empty
end
end
it "should not fetch urls blocked by path" do
driver.visit('/')
driver.within_frame('frame2') do
driver.find("//body").first.text.should be_empty
end
end
it "should not fetch blocked scripts" do
driver.visit("/")
driver.body.should_not include("Script Run")
end
it "should fetch unblocked urls" do
driver.visit('/')
driver.within_frame('frame3') do
driver.find("//p").first.text.should == "Inner"
end
end
end
describe "timeout for long requests" do
let(:driver) do
driver_for_app do

View File

@ -40,6 +40,7 @@
#include "JavascriptAlertMessages.h"
#include "JavascriptConfirmMessages.h"
#include "JavascriptPromptMessages.h"
#include "SetUrlBlacklist.h"
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
m_manager = manager;

View File

@ -2,6 +2,7 @@
#include "WebPage.h"
#include <iostream>
#include <fstream>
#include "NoOpReply.h"
NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*)));
@ -11,18 +12,22 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManage
QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
QNetworkRequest new_request(request);
QByteArray url = new_request.url().toEncoded();
if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
if (this->isBlacklisted(new_request.url())) {
return this->noOpRequest();
} else {
if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
}
QHashIterator<QString, QString> item(m_headers);
while (item.hasNext()) {
item.next();
new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
}
QNetworkReply *reply = QNetworkAccessManager::createRequest(operation, new_request, outgoingData);
emit requestCreated(url, reply);
return reply;
}
QHashIterator<QString, QString> item(m_headers);
while (item.hasNext()) {
item.next();
new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
}
QNetworkReply *reply = QNetworkAccessManager::createRequest(operation, new_request, outgoingData);
emit requestCreated(url, reply);
return reply;
}
};
void NetworkAccessManager::finished(QNetworkReply *reply) {
NetworkResponse response;
@ -60,3 +65,33 @@ int NetworkAccessManager::statusFor(QUrl url) {
const QList<QNetworkReply::RawHeaderPair> &NetworkAccessManager::headersFor(QUrl url) {
return m_responses[url].headers;
}
void NetworkAccessManager::setUrlBlacklist(QStringList urlBlacklist) {
m_urlBlacklist.clear();
QStringListIterator iter(urlBlacklist);
while (iter.hasNext()) {
m_urlBlacklist << QUrl(iter.next());
}
};
bool NetworkAccessManager::isBlacklisted(QUrl url) {
QListIterator<QUrl> iter(m_urlBlacklist);
while (iter.hasNext()) {
QUrl blacklisted = iter.next();
if (blacklisted == url) {
return true;
} else if (blacklisted.path().isEmpty() && blacklisted.isParentOf(url)) {
return true;
}
}
return false;
};
QNetworkReply* NetworkAccessManager::noOpRequest() {
return new NoOpReply();
};

View File

@ -1,6 +1,7 @@
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QStringList>
class NetworkAccessManager : public QNetworkAccessManager {
@ -20,15 +21,20 @@ class NetworkAccessManager : public QNetworkAccessManager {
void setPassword(const QString &password);
int statusFor(QUrl url);
const QList<QNetworkReply::RawHeaderPair> &headersFor(QUrl url);
void setUrlBlacklist(QStringList urlBlacklist);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
QString m_userName;
QString m_password;
QList<QUrl> m_urlBlacklist;
private:
QHash<QString, QString> m_headers;
QHash<QUrl, NetworkResponse> m_responses;
bool isBlacklisted(QUrl url);
QNetworkReply* noOpRequest();
private slots:
void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);

29
src/NoOpReply.cpp Normal file
View File

@ -0,0 +1,29 @@
#include <QTimer.h>
#include "NoOpReply.h"
NoOpReply::NoOpReply(QObject *parent) : QNetworkReply(parent) {
open(ReadOnly | Unbuffered);
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
setHeader(QNetworkRequest::ContentLengthHeader, QVariant(0));
setHeader(QNetworkRequest::ContentTypeHeader, QVariant(QString("text/plain")));
QTimer::singleShot( 0, this, SIGNAL(readyRead()) );
QTimer::singleShot( 0, this, SIGNAL(finished()) );
}
void NoOpReply::abort() {
// NO-OP
}
qint64 NoOpReply::bytesAvailable() const {
return 0;
}
bool NoOpReply::isSequential() const {
return true;
}
qint64 NoOpReply::readData(char *data, qint64 maxSize) {
return 0;
}

17
src/NoOpReply.h Normal file
View File

@ -0,0 +1,17 @@
#include <qnetworkreply>
class NoOpReply : public QNetworkReply {
Q_OBJECT
public:
NoOpReply( QObject *parent=0 );
void abort();
qint64 bytesAvailable() const;
bool isSequential() const;
protected:
qint64 readData(char *data, qint64 maxSize);
};

15
src/SetUrlBlacklist.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "SetUrlBlacklist.h"
#include "WebPageManager.h"
#include "WebPage.h"
#include "NetworkAccessManager.h"
SetUrlBlacklist::SetUrlBlacklist(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
}
void SetUrlBlacklist::start() {
NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
networkAccessManager->setUrlBlacklist(arguments());
emit finished(new Response(true));
}

11
src/SetUrlBlacklist.h Normal file
View File

@ -0,0 +1,11 @@
#include "SocketCommand.h"
class SetUrlBlacklist : public SocketCommand {
Q_OBJECT
public:
SetUrlBlacklist(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
virtual void start();
};

View File

@ -41,4 +41,5 @@ CHECK_COMMAND(JavascriptConfirmMessages)
CHECK_COMMAND(JavascriptPromptMessages)
CHECK_COMMAND(GetTimeout)
CHECK_COMMAND(SetTimeout)
CHECK_COMMAND(SetUrlBlacklist)

View File

@ -56,6 +56,8 @@ HEADERS = \
GetTimeout.h \
SetTimeout.h \
TimeoutCommand.h \
SetUrlBlacklist.h \
NoOpReply.h \
SOURCES = \
EnableLogging.cpp \
@ -113,6 +115,8 @@ SOURCES = \
GetWindowHandles.cpp \
GetWindowHandle.cpp \
TimeoutCommand.cpp \
SetUrlBlacklist.cpp \
NoOpReply.cpp \
RESOURCES = webkit_server.qrc
QT += network webkit