mirror of https://github.com/vitalif/phantomjs
Add a command-line option --local-urls={true,false}
The default is 'true'. When set 'false', file: and qrc: URLs are treated as invalid (unknown scheme) rather than opening local files, as requested in issue #12752. In order to test this, I added a mechanism to test/run-tests.py allowing individual tests to be annotated with command-line options to pass to phantomjs or the script.2.0
parent
a65a487d99
commit
50ae50e871
|
@ -56,6 +56,7 @@ static const struct QCommandLineConfigEntry flags[] =
|
|||
{ QCommandLine::Option, '\0', "load-images", "Loads all inlined images: 'true' (default) or 'false'", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "local-storage-path", "Specifies the location for offline local storage", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "local-storage-quota", "Sets the maximum size of the offline local storage (in KB)", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "local-url-access", "Allows use of 'file:///' URLs: 'true' (default) or 'false'", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "local-to-remote-url-access", "Allows local content to access remote URL: 'true' or 'false' (default)", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "max-disk-cache-size", "Limits the size of the disk cache (in KB)", QCommandLine::Optional },
|
||||
{ QCommandLine::Option, '\0', "output-encoding", "Sets the encoding for the terminal output, default is 'utf8'", QCommandLine::Optional },
|
||||
|
@ -249,6 +250,16 @@ void Config::setIgnoreSslErrors(const bool value)
|
|||
m_ignoreSslErrors = value;
|
||||
}
|
||||
|
||||
bool Config::localUrlAccessEnabled() const
|
||||
{
|
||||
return m_localUrlAccessEnabled;
|
||||
}
|
||||
|
||||
void Config::setLocalUrlAccessEnabled(const bool value)
|
||||
{
|
||||
m_localUrlAccessEnabled = value;
|
||||
}
|
||||
|
||||
bool Config::localToRemoteUrlAccessEnabled() const
|
||||
{
|
||||
return m_localToRemoteUrlAccessEnabled;
|
||||
|
@ -535,6 +546,7 @@ void Config::resetToDefaults()
|
|||
m_diskCacheEnabled = false;
|
||||
m_maxDiskCacheSize = -1;
|
||||
m_ignoreSslErrors = false;
|
||||
m_localUrlAccessEnabled = true;
|
||||
m_localToRemoteUrlAccessEnabled = false;
|
||||
m_outputEncoding = "UTF-8";
|
||||
m_proxyType = "http";
|
||||
|
@ -643,6 +655,7 @@ void Config::handleOption(const QString &option, const QVariant &value)
|
|||
booleanFlags << "disk-cache";
|
||||
booleanFlags << "ignore-ssl-errors";
|
||||
booleanFlags << "load-images";
|
||||
booleanFlags << "local-url-access";
|
||||
booleanFlags << "local-to-remote-url-access";
|
||||
booleanFlags << "remote-debugger-autorun";
|
||||
booleanFlags << "web-security";
|
||||
|
@ -686,6 +699,10 @@ void Config::handleOption(const QString &option, const QVariant &value)
|
|||
setOfflineStorageDefaultQuota(value.toInt());
|
||||
}
|
||||
|
||||
if (option == "local-url-access") {
|
||||
setLocalUrlAccessEnabled(boolValue);
|
||||
}
|
||||
|
||||
if (option == "local-to-remote-url-access") {
|
||||
setLocalToRemoteUrlAccessEnabled(boolValue);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ class Config: public QObject
|
|||
Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled)
|
||||
Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize)
|
||||
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors)
|
||||
Q_PROPERTY(bool localUrlAccessEnabled READ localUrlAccessEnabled WRITE setLocalUrlAccessEnabled)
|
||||
Q_PROPERTY(bool localToRemoteUrlAccessEnabled READ localToRemoteUrlAccessEnabled WRITE setLocalToRemoteUrlAccessEnabled)
|
||||
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
|
||||
Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType)
|
||||
|
@ -95,6 +96,9 @@ public:
|
|||
bool ignoreSslErrors() const;
|
||||
void setIgnoreSslErrors(const bool value);
|
||||
|
||||
bool localUrlAccessEnabled() const;
|
||||
void setLocalUrlAccessEnabled(const bool value);
|
||||
|
||||
bool localToRemoteUrlAccessEnabled() const;
|
||||
void setLocalToRemoteUrlAccessEnabled(const bool value);
|
||||
|
||||
|
@ -201,6 +205,7 @@ private:
|
|||
bool m_diskCacheEnabled;
|
||||
int m_maxDiskCacheSize;
|
||||
bool m_ignoreSslErrors;
|
||||
bool m_localUrlAccessEnabled;
|
||||
bool m_localToRemoteUrlAccessEnabled;
|
||||
QString m_outputEncoding;
|
||||
QString m_proxyType;
|
||||
|
|
|
@ -73,6 +73,30 @@ static const char *toString(QNetworkAccessManager::Operation op)
|
|||
return str;
|
||||
}
|
||||
|
||||
// Stub QNetworkReply used when file:/// URLs are disabled.
|
||||
// Somewhat cargo-culted from QDisabledNetworkReply.
|
||||
|
||||
NoFileAccessReply::NoFileAccessReply(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op)
|
||||
: QNetworkReply(parent)
|
||||
{
|
||||
setRequest(req);
|
||||
setUrl(req.url());
|
||||
setOperation(op);
|
||||
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>();
|
||||
QString msg = (QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown")
|
||||
.arg(req.url().scheme()));
|
||||
setError(ProtocolUnknownError, msg);
|
||||
|
||||
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
|
||||
Q_ARG(QNetworkReply::NetworkError, ProtocolUnknownError));
|
||||
QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
// The destructor must be out-of-line in order to trigger generation of the vtable.
|
||||
NoFileAccessReply::~NoFileAccessReply() {}
|
||||
|
||||
|
||||
TimeoutTimer::TimeoutTimer(QObject* parent)
|
||||
: QTimer(parent)
|
||||
{
|
||||
|
@ -129,6 +153,7 @@ const ssl_protocol_option ssl_protocol_options[] = {
|
|||
NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config)
|
||||
: QNetworkAccessManager(parent)
|
||||
, m_ignoreSslErrors(config->ignoreSslErrors())
|
||||
, m_localUrlAccessEnabled(config->localUrlAccessEnabled())
|
||||
, m_authAttempts(0)
|
||||
, m_maxAuthAttempts(3)
|
||||
, m_resourceTimeout(0)
|
||||
|
@ -238,10 +263,12 @@ void NetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
|
|||
QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest & request, QIODevice * outgoingData)
|
||||
{
|
||||
QNetworkRequest req(request);
|
||||
QString scheme = req.url().scheme().toLower();
|
||||
bool isLocalFile = req.url().isLocalFile();
|
||||
|
||||
if (!QSslSocket::supportsSsl()) {
|
||||
if (req.url().scheme().toLower() == QLatin1String("https"))
|
||||
qWarning() << "Request using https scheme without SSL support";
|
||||
if (scheme == QLatin1String("https"))
|
||||
qWarning() << "Request using https scheme without SSL support";
|
||||
} else {
|
||||
req.setSslConfiguration(m_sslConfiguration);
|
||||
}
|
||||
|
@ -288,8 +315,15 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
|
|||
JsNetworkRequest jsNetworkRequest(&req, this);
|
||||
emit resourceRequested(data, &jsNetworkRequest);
|
||||
|
||||
// Pass duty to the superclass - Nothing special to do here (yet?)
|
||||
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
|
||||
// Pass duty to the superclass - special case: file:/// may be disabled.
|
||||
// This conditional must match QNetworkAccessManager's own idea of what a
|
||||
// local file URL is.
|
||||
QNetworkReply *reply;
|
||||
if (!m_localUrlAccessEnabled && (isLocalFile || scheme == QLatin1String("qrc"))) {
|
||||
reply = new NoFileAccessReply(this, req, op);
|
||||
} else {
|
||||
reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
|
||||
}
|
||||
|
||||
// reparent jsNetworkRequest to make sure that it will be destroyed with QNetworkReply
|
||||
jsNetworkRequest.setParent(reply);
|
||||
|
|
|
@ -67,6 +67,18 @@ private:
|
|||
QNetworkRequest* m_networkRequest;
|
||||
};
|
||||
|
||||
class NoFileAccessReply : public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NoFileAccessReply(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op);
|
||||
~NoFileAccessReply();
|
||||
void abort() {}
|
||||
protected:
|
||||
qint64 readData(char *, qint64) { return -1; }
|
||||
};
|
||||
|
||||
class NetworkAccessManager : public QNetworkAccessManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -83,6 +95,7 @@ public:
|
|||
|
||||
protected:
|
||||
bool m_ignoreSslErrors;
|
||||
bool m_localUrlAccessEnabled;
|
||||
int m_authAttempts;
|
||||
int m_maxAuthAttempts;
|
||||
int m_resourceTimeout;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// phantomjs: --local-url-access=no
|
||||
|
||||
var assert = require("../../assert");
|
||||
var p = require("webpage").create();
|
||||
|
||||
var url = "file:///nonexistent";
|
||||
|
||||
var rsErrorCalled = false;
|
||||
p.onResourceError = function (error) {
|
||||
rsErrorCalled = true;
|
||||
assert.strictEqual(error.url, url);
|
||||
assert.strictEqual(error.errorCode, 301);
|
||||
assert.strictEqual(error.errorString, 'Protocol "file" is unknown');
|
||||
};
|
||||
|
||||
p.open(url, function () {
|
||||
assert(rsErrorCalled);
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
// phantomjs: --local-url-access=yes
|
||||
|
||||
var assert = require("../../assert");
|
||||
var p = require("webpage").create();
|
||||
|
||||
var url = "file:///nonexistent";
|
||||
|
||||
var rsErrorCalled = false;
|
||||
p.onResourceError = function (error) {
|
||||
rsErrorCalled = true;
|
||||
assert.strictEqual(error.url, url);
|
||||
assert.strictEqual(error.errorCode, 203);
|
||||
assert.strictEqual(/^Error opening\b.*?\bnonexistent:/.test(error.errorString),
|
||||
true);
|
||||
};
|
||||
|
||||
p.open(url, function () {
|
||||
assert(rsErrorCalled);
|
||||
});
|
|
@ -6,6 +6,7 @@ import imp
|
|||
import optparse
|
||||
import os
|
||||
import posixpath
|
||||
import shlex
|
||||
import SimpleHTTPServer
|
||||
import SocketServer
|
||||
import socket
|
||||
|
@ -216,10 +217,12 @@ def init():
|
|||
print 'Checking PhantomJS version %s' % version
|
||||
|
||||
|
||||
def run_phantomjs(script, args=[]):
|
||||
def run_phantomjs(script, script_args=[], pjs_args=[]):
|
||||
output = []
|
||||
command = [phantomjs_exe, script]
|
||||
command.extend(args)
|
||||
command = [phantomjs_exe]
|
||||
command.extend(pjs_args)
|
||||
command.append(script)
|
||||
command.extend(script_args)
|
||||
process = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
|
||||
|
||||
def runner():
|
||||
|
@ -244,23 +247,34 @@ def run_phantomjs(script, args=[]):
|
|||
|
||||
|
||||
def run_test(script, name):
|
||||
args = []
|
||||
script_args = []
|
||||
pjs_args = []
|
||||
if options.verbose:
|
||||
args.append('--verbose')
|
||||
script_args.append('--verbose')
|
||||
|
||||
result = 0
|
||||
if not os.path.isfile(script):
|
||||
print 'Could not locate %s' % name
|
||||
result = 1
|
||||
else:
|
||||
print '%s:' % name
|
||||
returncode, output = run_phantomjs(script, args)
|
||||
if returncode != 0:
|
||||
if not options.verbose:
|
||||
print '%s' % output
|
||||
result = 1
|
||||
try:
|
||||
with open(script, "rt") as s:
|
||||
p_prefix = "// phantomjs: "
|
||||
s_prefix = "// script: "
|
||||
for line in s:
|
||||
if line.startswith(p_prefix):
|
||||
pjs_args.extend(shlex.split(line[len(p_prefix):]))
|
||||
if line.startswith(s_prefix):
|
||||
script_args.extend(shlex.split(line[len(s_prefix):]))
|
||||
if not line.startswith("//"):
|
||||
break
|
||||
except OSError as e:
|
||||
print '%s: %s: %s' % (name, e.filename, e.strerror)
|
||||
return 1
|
||||
|
||||
return result
|
||||
print '%s:' % name
|
||||
returncode, output = run_phantomjs(script, script_args, pjs_args)
|
||||
if returncode != 0:
|
||||
if not options.verbose:
|
||||
print '%s' % output
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def run_tests():
|
||||
|
|
Loading…
Reference in New Issue