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:
parent
82d0d6fcc9
commit
3804dd5406
20 changed files with 341 additions and 36 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
15
spec/support/output_writer.rb
Normal file
15
spec/support/output_writer.rb
Normal 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
16
src/AllowUrl.cpp
Normal 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
10
src/AllowUrl.h
Normal 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();
|
||||
};
|
||||
|
|
@ -46,3 +46,7 @@ bool BlacklistedRequestHandler::isBlacklisted(QUrl url) {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlacklistedRequestHandler::blockUrl(const QString &url) {
|
||||
m_urlBlacklist.append(url);
|
||||
}
|
||||
|
|
|
@ -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
16
src/BlockUrl.cpp
Normal 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
10
src/BlockUrl.h
Normal 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();
|
||||
};
|
||||
|
|
@ -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
27
src/SetUnknownUrlMode.cpp
Normal 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
10
src/SetUnknownUrlMode.h
Normal 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
64
src/UnknownUrlHandler.cpp
Normal 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
27
src/UnknownUrlHandler.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue