mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
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:
parent
213229d850
commit
f755b1f277
11 changed files with 201 additions and 11 deletions
|
@ -141,6 +141,10 @@ module Capybara::Webkit
|
||||||
command("ClearPromptText")
|
command("ClearPromptText")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def url_blacklist=(black_list)
|
||||||
|
command("SetUrlBlacklist", *Array(black_list))
|
||||||
|
end
|
||||||
|
|
||||||
def command(name, *args)
|
def command(name, *args)
|
||||||
@connection.puts name
|
@connection.puts name
|
||||||
@connection.puts args.size
|
@connection.puts args.size
|
||||||
|
|
|
@ -1833,6 +1833,73 @@ describe Capybara::Webkit::Driver do
|
||||||
end
|
end
|
||||||
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
|
describe "timeout for long requests" do
|
||||||
let(:driver) do
|
let(:driver) do
|
||||||
driver_for_app do
|
driver_for_app do
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "JavascriptAlertMessages.h"
|
#include "JavascriptAlertMessages.h"
|
||||||
#include "JavascriptConfirmMessages.h"
|
#include "JavascriptConfirmMessages.h"
|
||||||
#include "JavascriptPromptMessages.h"
|
#include "JavascriptPromptMessages.h"
|
||||||
|
#include "SetUrlBlacklist.h"
|
||||||
|
|
||||||
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
|
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
|
||||||
m_manager = manager;
|
m_manager = manager;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "WebPage.h"
|
#include "WebPage.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include "NoOpReply.h"
|
||||||
|
|
||||||
NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
|
NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
|
||||||
connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*)));
|
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) {
|
QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
|
||||||
QNetworkRequest new_request(request);
|
QNetworkRequest new_request(request);
|
||||||
QByteArray url = new_request.url().toEncoded();
|
QByteArray url = new_request.url().toEncoded();
|
||||||
if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
|
if (this->isBlacklisted(new_request.url())) {
|
||||||
new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
|
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) {
|
void NetworkAccessManager::finished(QNetworkReply *reply) {
|
||||||
NetworkResponse response;
|
NetworkResponse response;
|
||||||
|
@ -60,3 +65,33 @@ int NetworkAccessManager::statusFor(QUrl url) {
|
||||||
const QList<QNetworkReply::RawHeaderPair> &NetworkAccessManager::headersFor(QUrl url) {
|
const QList<QNetworkReply::RawHeaderPair> &NetworkAccessManager::headersFor(QUrl url) {
|
||||||
return m_responses[url].headers;
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <QtNetwork/QNetworkAccessManager>
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
class NetworkAccessManager : public QNetworkAccessManager {
|
class NetworkAccessManager : public QNetworkAccessManager {
|
||||||
|
|
||||||
|
@ -20,15 +21,20 @@ class NetworkAccessManager : public QNetworkAccessManager {
|
||||||
void setPassword(const QString &password);
|
void setPassword(const QString &password);
|
||||||
int statusFor(QUrl url);
|
int statusFor(QUrl url);
|
||||||
const QList<QNetworkReply::RawHeaderPair> &headersFor(QUrl url);
|
const QList<QNetworkReply::RawHeaderPair> &headersFor(QUrl url);
|
||||||
|
void setUrlBlacklist(QStringList urlBlacklist);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
|
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
|
||||||
QString m_userName;
|
QString m_userName;
|
||||||
QString m_password;
|
QString m_password;
|
||||||
|
QList<QUrl> m_urlBlacklist;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QString, QString> m_headers;
|
QHash<QString, QString> m_headers;
|
||||||
QHash<QUrl, NetworkResponse> m_responses;
|
QHash<QUrl, NetworkResponse> m_responses;
|
||||||
|
bool isBlacklisted(QUrl url);
|
||||||
|
QNetworkReply* noOpRequest();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
|
void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||||
|
|
29
src/NoOpReply.cpp
Normal file
29
src/NoOpReply.cpp
Normal 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
17
src/NoOpReply.h
Normal 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
15
src/SetUrlBlacklist.cpp
Normal 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
11
src/SetUrlBlacklist.h
Normal 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();
|
||||||
|
};
|
||||||
|
|
|
@ -41,4 +41,5 @@ CHECK_COMMAND(JavascriptConfirmMessages)
|
||||||
CHECK_COMMAND(JavascriptPromptMessages)
|
CHECK_COMMAND(JavascriptPromptMessages)
|
||||||
CHECK_COMMAND(GetTimeout)
|
CHECK_COMMAND(GetTimeout)
|
||||||
CHECK_COMMAND(SetTimeout)
|
CHECK_COMMAND(SetTimeout)
|
||||||
|
CHECK_COMMAND(SetUrlBlacklist)
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ HEADERS = \
|
||||||
GetTimeout.h \
|
GetTimeout.h \
|
||||||
SetTimeout.h \
|
SetTimeout.h \
|
||||||
TimeoutCommand.h \
|
TimeoutCommand.h \
|
||||||
|
SetUrlBlacklist.h \
|
||||||
|
NoOpReply.h \
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
EnableLogging.cpp \
|
EnableLogging.cpp \
|
||||||
|
@ -113,6 +115,8 @@ SOURCES = \
|
||||||
GetWindowHandles.cpp \
|
GetWindowHandles.cpp \
|
||||||
GetWindowHandle.cpp \
|
GetWindowHandle.cpp \
|
||||||
TimeoutCommand.cpp \
|
TimeoutCommand.cpp \
|
||||||
|
SetUrlBlacklist.cpp \
|
||||||
|
NoOpReply.cpp \
|
||||||
|
|
||||||
RESOURCES = webkit_server.qrc
|
RESOURCES = webkit_server.qrc
|
||||||
QT += network webkit
|
QT += network webkit
|
||||||
|
|
Loading…
Reference in a new issue