1
0
Fork 0
mirror of https://github.com/thoughtbot/capybara-webkit synced 2023-03-27 23:22:28 -04:00

Introduce allowed, blocked URL filters

* Adds `allow_url`, `block_url`, and `block_unknown_url` methods.
* Both allow_url and block_url accept wildcards.
* Any requests to blocked URLs will be blocked immediately.
* Blocked URLs take precedence over allowed URLs.
* By default, any requests to localhost and 127.0.0.1 are allowed.
* By default, any requests to unknown hosts will print a warning.
* `block_unknown_urls` causes unknown hosts to be silently blocked.
* `blacklisted_urls=` is deprecated in favor of `block_url`.
This commit is contained in:
Joe Ferris 2014-11-14 14:55:14 -05:00
parent 82d0d6fcc9
commit 3804dd5406
20 changed files with 341 additions and 36 deletions

View file

@ -195,6 +195,8 @@ module Capybara::Webkit
end
def url_blacklist=(black_list)
warn '[DEPRECATION] Capybara::Webkit::Browser#url_blacklist= ' \
'is deprecated. Please use page.driver.block_url instead.'
command("SetUrlBlacklist", *Array(black_list))
end
@ -263,6 +265,18 @@ module Capybara::Webkit
command("GoForward")
end
def allow_url(url)
command("AllowUrl", url)
end
def block_url(url)
command("BlockUrl", url)
end
def block_unknown_urls
command("SetUnknownUrlMode", "block")
end
private
def check

View file

@ -21,6 +21,18 @@ module Capybara::Webkit
browser.enable_logging
end
def allow_url(url)
browser.allow_url(url)
end
def block_url(url)
browser.block_url(url)
end
def block_unknown_urls
browser.block_unknown_urls
end
def current_url
browser.current_url
end

View file

@ -2568,10 +2568,10 @@ CACHE MANIFEST
end
before do
driver.browser.url_blacklist = ["http://example.org/path/to/file",
"http://example.*/foo/*",
"http://example.com",
"#{AppRunner.app_host}/script"]
driver.block_url "http://example.org/path/to/file"
driver.block_url "http://example.*/foo/*"
driver.block_url "http://example.com"
driver.block_url "#{AppRunner.app_host}/script"
end
it "should not fetch urls blocked by host" do
@ -2615,6 +2615,61 @@ CACHE MANIFEST
end
end
describe "url whitelisting" do
it_behaves_like "output writer" do
let(:driver) do
driver_for_html(<<-HTML, browser)
<<-HTML
<html>
<body>
<iframe src="http://example.com/path" id="frame"></iframe>
<iframe src="http://www.example.com" id="frame2"></iframe>
</body>
</html>
HTML
end
it "prints a warning for remote requests by default" do
visit("/")
expect(stderr).to include("http://example.com/path")
expect(stderr).not_to include(driver.current_url)
end
it "can allow specific hosts" do
driver.allow_url("example.com")
driver.allow_url("www.example.com")
visit("/")
expect(stderr).not_to include("http://example.com/path")
expect(stderr).not_to include(driver.current_url)
driver.within_frame("frame") do
expect(driver.find("//body").first.text).not_to be_empty
end
end
it "can block unknown hosts" do
driver.block_unknown_urls
visit("/")
expect(stderr).not_to include("http://example.com/path")
expect(stderr).not_to include(driver.current_url)
driver.within_frame("frame") do
expect(driver.find("//body").first.text).to be_empty
end
end
it "can allow urls with wildcards" do
driver.allow_url("*/path")
visit("/")
expect(stderr).to include("www.example.com")
expect(stderr).not_to include("example.com/path")
expect(stderr).not_to include(driver.current_url)
end
end
end
describe "timeout for long requests" do
let(:driver) do
driver_for_app do
@ -2688,33 +2743,23 @@ CACHE MANIFEST
end
describe "logger app" do
it "logs nothing before turning on the logger" do
visit("/")
@write.close
log.should_not include logging_message
end
it_behaves_like "output writer" do
let(:driver) do
driver_for_html("<html><body>Hello</body></html>", browser)
end
it "logs its commands after turning on the logger" do
driver.enable_logging
visit("/")
@write.close
log.should include logging_message
end
it "logs nothing before turning on the logger" do
visit("/")
stderr.should_not include logging_message
end
before do
@read, @write = IO.pipe
end
it "logs its commands after turning on the logger" do
driver.enable_logging
visit("/")
stderr.should include logging_message
end
let(:logging_message) { 'Wrote response true' }
let(:driver) do
connection = Capybara::Webkit::Connection.new(:stderr => @write)
browser = Capybara::Webkit::Browser.new(connection)
Capybara::Webkit::Driver.new(AppRunner.app, :browser => browser)
end
def log
@read.read
let(:logging_message) { 'Wrote response true' }
end
end

View file

@ -31,9 +31,9 @@ module AppRunner
build_driver
end
def driver_for_html(html)
def driver_for_html(html, *driver_args)
run_application_for_html html
build_driver
build_driver(*driver_args)
end
def session_for_app(&body)
@ -50,8 +50,8 @@ module AppRunner
private
def build_driver
Capybara::Webkit::Driver.new(AppRunner.app, :browser => $webkit_browser)
def build_driver(browser = $webkit_browser)
Capybara::Webkit::Driver.new(AppRunner.app, :browser => browser)
end
def self.included(example_group)

View file

@ -0,0 +1,15 @@
shared_examples_for "output writer" do
before do
@read, @write = IO.pipe
end
let(:browser) do
connection = Capybara::Webkit::Connection.new(:stderr => @write)
Capybara::Webkit::Browser.new(connection)
end
let(:stderr) do
@write.close
@read.read
end
end

16
src/AllowUrl.cpp Normal file
View file

@ -0,0 +1,16 @@
#include "AllowUrl.h"
#include "SocketCommand.h"
#include "WebPage.h"
#include "WebPageManager.h"
AllowUrl::AllowUrl(
WebPageManager *manager,
QStringList &arguments,
QObject *parent
) : SocketCommand(manager, arguments, parent) {
}
void AllowUrl::start() {
manager()->allowUrl(arguments()[0]);
finish(true);
}

10
src/AllowUrl.h Normal file
View file

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

View file

@ -46,3 +46,7 @@ bool BlacklistedRequestHandler::isBlacklisted(QUrl url) {
return false;
}
void BlacklistedRequestHandler::blockUrl(const QString &url) {
m_urlBlacklist.append(url);
}

View file

@ -12,6 +12,7 @@ class BlacklistedRequestHandler : public RequestHandler {
QIODevice *
);
void setUrlBlacklist(QStringList urlBlacklist);
void blockUrl(const QString &);
private:
RequestHandler *m_next;

16
src/BlockUrl.cpp Normal file
View file

@ -0,0 +1,16 @@
#include "BlockUrl.h"
#include "SocketCommand.h"
#include "WebPage.h"
#include "WebPageManager.h"
BlockUrl::BlockUrl(
WebPageManager *manager,
QStringList &arguments,
QObject *parent
) : SocketCommand(manager, arguments, parent) {
}
void BlockUrl::start() {
manager()->blockUrl(arguments()[0]);
finish(true);
}

10
src/BlockUrl.h Normal file
View file

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

View file

@ -48,6 +48,9 @@
#include "GoForward.h"
#include "AcceptAlert.h"
#include "FindModal.h"
#include "SetUnknownUrlMode.h"
#include "AllowUrl.h"
#include "BlockUrl.h"
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
m_manager = manager;

27
src/SetUnknownUrlMode.cpp Normal file
View file

@ -0,0 +1,27 @@
#include "SetUnknownUrlMode.h"
#include "WebPage.h"
#include "WebPageManager.h"
#include "ErrorMessage.h"
SetUnknownUrlMode::SetUnknownUrlMode(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
}
void SetUnknownUrlMode::start() {
QString modeString = arguments()[0];
QStringList modes;
modes << "warn" << "block";
switch(modes.indexOf(modeString)) {
case 0:
manager()->setUnknownUrlMode(UnknownUrlHandler::WARN);
finish(true);
break;
case 1:
manager()->setUnknownUrlMode(UnknownUrlHandler::BLOCK);
finish(true);
break;
default:
QString error = QString("Invalid mode string:") + modeString;
finish(false, new ErrorMessage(error));
}
}

10
src/SetUnknownUrlMode.h Normal file
View file

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

64
src/UnknownUrlHandler.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "UnknownUrlHandler.h"
#include "NetworkReplyProxy.h"
#include "NoOpReply.h"
UnknownUrlHandler::UnknownUrlHandler(
RequestHandler *next,
QObject *parent
) : RequestHandler(parent) {
m_next = next;
m_allowedUrls.append(QString("127.0.0.1"));
m_allowedUrls.append(QString("localhost"));
m_mode = WARN;
}
QNetworkReply* UnknownUrlHandler::handleRequest(
NetworkAccessManager *manager,
QNetworkAccessManager::Operation operation,
QNetworkRequest &request,
QIODevice *outgoingData
) {
QUrl url(request.url());
if (this->isUnknown(url)) {
switch(m_mode) {
case WARN:
QTextStream(stderr) <<
"Unexpected request: " << url.toString() << endl <<
"To block unknown requests:" << endl <<
" page.driver.block_unknown_requests" << endl <<
"To allow just this request:" << endl <<
" page.driver.allow_url(\"" << url.toString() << "\")" << endl <<
"To allow allow requests from this host:" << endl <<
" page.driver.allow_url(\"" << url.host() << "\")" << endl;
break;
case BLOCK:
return new NetworkReplyProxy(new NoOpReply(request), this);
}
}
return m_next->handleRequest(manager, operation, request, outgoingData);
}
void UnknownUrlHandler::allowUrl(const QString &url) {
m_allowedUrls << url;
}
void UnknownUrlHandler::setMode(Mode mode) {
m_mode = mode;
}
bool UnknownUrlHandler::isUnknown(QUrl url) {
QStringListIterator iterator(m_allowedUrls);
QString urlString = url.toString();
while (iterator.hasNext()) {
QRegExp allowedUrl = QRegExp(iterator.next());
allowedUrl.setPatternSyntax(QRegExp::Wildcard);
if(urlString.contains(allowedUrl)) {
return false;
}
}
return true;
}

27
src/UnknownUrlHandler.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef _REQUESTHANDLER_H
#define _REQUESTHANDLER_H
#include "RequestHandler.h"
class UnknownUrlHandler : public RequestHandler {
public:
enum Mode { WARN, BLOCK };
UnknownUrlHandler(RequestHandler *next, QObject *parent = 0);
virtual QNetworkReply* handleRequest(
NetworkAccessManager *,
QNetworkAccessManager::Operation,
QNetworkRequest &,
QIODevice *
);
void allowUrl(const QString &);
void setMode(Mode);
private:
QStringList m_allowedUrls;
bool isUnknown(QUrl);
Mode m_mode;
RequestHandler *m_next;
};
#endif

View file

@ -5,6 +5,7 @@
#include "BlacklistedRequestHandler.h"
#include "CustomHeadersRequestHandler.h"
#include "MissingContentHeaderRequestHandler.h"
#include "UnknownUrlHandler.h"
#include "NetworkRequestFactory.h"
WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
@ -21,8 +22,10 @@ WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
),
this
);
m_unknownUrlHandler =
new UnknownUrlHandler(m_customHeadersRequestHandler, this);
m_blacklistedRequestHandler =
new BlacklistedRequestHandler(m_customHeadersRequestHandler, this);
new BlacklistedRequestHandler(m_unknownUrlHandler, this);
m_networkAccessManager =
new NetworkAccessManager(m_blacklistedRequestHandler, this);
m_networkAccessManager->setCookieJar(m_cookieJar);
@ -180,3 +183,15 @@ void WebPageManager::setUrlBlacklist(const QStringList &urls) {
void WebPageManager::addHeader(QString key, QString value) {
m_customHeadersRequestHandler->addHeader(key, value);
}
void WebPageManager::setUnknownUrlMode(UnknownUrlHandler::Mode mode) {
m_unknownUrlHandler->setMode(mode);
}
void WebPageManager::allowUrl(const QString &url) {
m_unknownUrlHandler->allowUrl(url);
}
void WebPageManager::blockUrl(const QString &url) {
m_blacklistedRequestHandler->blockUrl(url);
}

View file

@ -7,6 +7,8 @@
#include <QDebug>
#include <QFile>
#include "UnknownUrlHandler.h"
class WebPage;
class NetworkCookieJar;
class NetworkAccessManager;
@ -37,6 +39,9 @@ class WebPageManager : public QObject {
NetworkAccessManager *networkAccessManager();
void setUrlBlacklist(const QStringList &);
void addHeader(QString, QString);
void setUnknownUrlMode(UnknownUrlHandler::Mode);
void allowUrl(const QString &);
void blockUrl(const QString &);
public slots:
void emitLoadStarted();
@ -64,7 +69,7 @@ class WebPageManager : public QObject {
NetworkAccessManager *m_networkAccessManager;
BlacklistedRequestHandler *m_blacklistedRequestHandler;
CustomHeadersRequestHandler *m_customHeadersRequestHandler;
UnknownUrlHandler *m_unknownUrlHandler;
};
#endif // _WEBPAGEMANAGER_H

View file

@ -50,3 +50,6 @@ CHECK_COMMAND(GoBack)
CHECK_COMMAND(GoForward)
CHECK_COMMAND(AcceptAlert)
CHECK_COMMAND(FindModal)
CHECK_COMMAND(SetUnknownUrlMode)
CHECK_COMMAND(AllowUrl)
CHECK_COMMAND(BlockUrl)

View file

@ -7,6 +7,9 @@ PRECOMPILED_DIR = $${BUILD_DIR}
OBJECTS_DIR = $${BUILD_DIR}
MOC_DIR = $${BUILD_DIR}
HEADERS = \
BlockUrl.h \
AllowUrl.h \
SetUnknownUrlMode.h \
FindModal.h \
AcceptAlert.h \
GoForward.h \
@ -83,9 +86,13 @@ HEADERS = \
BlacklistedRequestHandler.h \
MissingContentHeaderRequestHandler.h \
CustomHeadersRequestHandler.h \
NetworkRequestFactory.h
NetworkRequestFactory.h \
UnknownUrlHandler.h
SOURCES = \
BlockUrl.cpp \
AllowUrl.cpp \
SetUnknownUrlMode.cpp \
FindModal.cpp \
AcceptAlert.cpp \
GoForward.cpp \
@ -163,7 +170,8 @@ SOURCES = \
BlacklistedRequestHandler.cpp \
MissingContentHeaderRequestHandler.cpp \
CustomHeadersRequestHandler.cpp \
NetworkRequestFactory.cpp
NetworkRequestFactory.cpp \
UnknownUrlHandler.cpp
RESOURCES = webkit_server.qrc
QT += network