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', "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-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-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', "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', "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 },
|
{ 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;
|
m_ignoreSslErrors = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Config::localUrlAccessEnabled() const
|
||||||
|
{
|
||||||
|
return m_localUrlAccessEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::setLocalUrlAccessEnabled(const bool value)
|
||||||
|
{
|
||||||
|
m_localUrlAccessEnabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
bool Config::localToRemoteUrlAccessEnabled() const
|
bool Config::localToRemoteUrlAccessEnabled() const
|
||||||
{
|
{
|
||||||
return m_localToRemoteUrlAccessEnabled;
|
return m_localToRemoteUrlAccessEnabled;
|
||||||
|
@ -535,6 +546,7 @@ void Config::resetToDefaults()
|
||||||
m_diskCacheEnabled = false;
|
m_diskCacheEnabled = false;
|
||||||
m_maxDiskCacheSize = -1;
|
m_maxDiskCacheSize = -1;
|
||||||
m_ignoreSslErrors = false;
|
m_ignoreSslErrors = false;
|
||||||
|
m_localUrlAccessEnabled = true;
|
||||||
m_localToRemoteUrlAccessEnabled = false;
|
m_localToRemoteUrlAccessEnabled = false;
|
||||||
m_outputEncoding = "UTF-8";
|
m_outputEncoding = "UTF-8";
|
||||||
m_proxyType = "http";
|
m_proxyType = "http";
|
||||||
|
@ -643,6 +655,7 @@ void Config::handleOption(const QString &option, const QVariant &value)
|
||||||
booleanFlags << "disk-cache";
|
booleanFlags << "disk-cache";
|
||||||
booleanFlags << "ignore-ssl-errors";
|
booleanFlags << "ignore-ssl-errors";
|
||||||
booleanFlags << "load-images";
|
booleanFlags << "load-images";
|
||||||
|
booleanFlags << "local-url-access";
|
||||||
booleanFlags << "local-to-remote-url-access";
|
booleanFlags << "local-to-remote-url-access";
|
||||||
booleanFlags << "remote-debugger-autorun";
|
booleanFlags << "remote-debugger-autorun";
|
||||||
booleanFlags << "web-security";
|
booleanFlags << "web-security";
|
||||||
|
@ -686,6 +699,10 @@ void Config::handleOption(const QString &option, const QVariant &value)
|
||||||
setOfflineStorageDefaultQuota(value.toInt());
|
setOfflineStorageDefaultQuota(value.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option == "local-url-access") {
|
||||||
|
setLocalUrlAccessEnabled(boolValue);
|
||||||
|
}
|
||||||
|
|
||||||
if (option == "local-to-remote-url-access") {
|
if (option == "local-to-remote-url-access") {
|
||||||
setLocalToRemoteUrlAccessEnabled(boolValue);
|
setLocalToRemoteUrlAccessEnabled(boolValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ class Config: public QObject
|
||||||
Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled)
|
Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled)
|
||||||
Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize)
|
Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize)
|
||||||
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors)
|
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(bool localToRemoteUrlAccessEnabled READ localToRemoteUrlAccessEnabled WRITE setLocalToRemoteUrlAccessEnabled)
|
||||||
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
|
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
|
||||||
Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType)
|
Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType)
|
||||||
|
@ -95,6 +96,9 @@ public:
|
||||||
bool ignoreSslErrors() const;
|
bool ignoreSslErrors() const;
|
||||||
void setIgnoreSslErrors(const bool value);
|
void setIgnoreSslErrors(const bool value);
|
||||||
|
|
||||||
|
bool localUrlAccessEnabled() const;
|
||||||
|
void setLocalUrlAccessEnabled(const bool value);
|
||||||
|
|
||||||
bool localToRemoteUrlAccessEnabled() const;
|
bool localToRemoteUrlAccessEnabled() const;
|
||||||
void setLocalToRemoteUrlAccessEnabled(const bool value);
|
void setLocalToRemoteUrlAccessEnabled(const bool value);
|
||||||
|
|
||||||
|
@ -201,6 +205,7 @@ private:
|
||||||
bool m_diskCacheEnabled;
|
bool m_diskCacheEnabled;
|
||||||
int m_maxDiskCacheSize;
|
int m_maxDiskCacheSize;
|
||||||
bool m_ignoreSslErrors;
|
bool m_ignoreSslErrors;
|
||||||
|
bool m_localUrlAccessEnabled;
|
||||||
bool m_localToRemoteUrlAccessEnabled;
|
bool m_localToRemoteUrlAccessEnabled;
|
||||||
QString m_outputEncoding;
|
QString m_outputEncoding;
|
||||||
QString m_proxyType;
|
QString m_proxyType;
|
||||||
|
|
|
@ -73,6 +73,30 @@ static const char *toString(QNetworkAccessManager::Operation op)
|
||||||
return str;
|
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)
|
TimeoutTimer::TimeoutTimer(QObject* parent)
|
||||||
: QTimer(parent)
|
: QTimer(parent)
|
||||||
{
|
{
|
||||||
|
@ -129,6 +153,7 @@ const ssl_protocol_option ssl_protocol_options[] = {
|
||||||
NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config)
|
NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config)
|
||||||
: QNetworkAccessManager(parent)
|
: QNetworkAccessManager(parent)
|
||||||
, m_ignoreSslErrors(config->ignoreSslErrors())
|
, m_ignoreSslErrors(config->ignoreSslErrors())
|
||||||
|
, m_localUrlAccessEnabled(config->localUrlAccessEnabled())
|
||||||
, m_authAttempts(0)
|
, m_authAttempts(0)
|
||||||
, m_maxAuthAttempts(3)
|
, m_maxAuthAttempts(3)
|
||||||
, m_resourceTimeout(0)
|
, m_resourceTimeout(0)
|
||||||
|
@ -238,10 +263,12 @@ void NetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
|
||||||
QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest & request, QIODevice * outgoingData)
|
QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest & request, QIODevice * outgoingData)
|
||||||
{
|
{
|
||||||
QNetworkRequest req(request);
|
QNetworkRequest req(request);
|
||||||
|
QString scheme = req.url().scheme().toLower();
|
||||||
|
bool isLocalFile = req.url().isLocalFile();
|
||||||
|
|
||||||
if (!QSslSocket::supportsSsl()) {
|
if (!QSslSocket::supportsSsl()) {
|
||||||
if (req.url().scheme().toLower() == QLatin1String("https"))
|
if (scheme == QLatin1String("https"))
|
||||||
qWarning() << "Request using https scheme without SSL support";
|
qWarning() << "Request using https scheme without SSL support";
|
||||||
} else {
|
} else {
|
||||||
req.setSslConfiguration(m_sslConfiguration);
|
req.setSslConfiguration(m_sslConfiguration);
|
||||||
}
|
}
|
||||||
|
@ -288,8 +315,15 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
|
||||||
JsNetworkRequest jsNetworkRequest(&req, this);
|
JsNetworkRequest jsNetworkRequest(&req, this);
|
||||||
emit resourceRequested(data, &jsNetworkRequest);
|
emit resourceRequested(data, &jsNetworkRequest);
|
||||||
|
|
||||||
// Pass duty to the superclass - Nothing special to do here (yet?)
|
// Pass duty to the superclass - special case: file:/// may be disabled.
|
||||||
QNetworkReply *reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
|
// 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
|
// reparent jsNetworkRequest to make sure that it will be destroyed with QNetworkReply
|
||||||
jsNetworkRequest.setParent(reply);
|
jsNetworkRequest.setParent(reply);
|
||||||
|
|
|
@ -67,6 +67,18 @@ private:
|
||||||
QNetworkRequest* m_networkRequest;
|
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
|
class NetworkAccessManager : public QNetworkAccessManager
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -83,6 +95,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_ignoreSslErrors;
|
bool m_ignoreSslErrors;
|
||||||
|
bool m_localUrlAccessEnabled;
|
||||||
int m_authAttempts;
|
int m_authAttempts;
|
||||||
int m_maxAuthAttempts;
|
int m_maxAuthAttempts;
|
||||||
int m_resourceTimeout;
|
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 optparse
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
|
import shlex
|
||||||
import SimpleHTTPServer
|
import SimpleHTTPServer
|
||||||
import SocketServer
|
import SocketServer
|
||||||
import socket
|
import socket
|
||||||
|
@ -216,10 +217,12 @@ def init():
|
||||||
print 'Checking PhantomJS version %s' % version
|
print 'Checking PhantomJS version %s' % version
|
||||||
|
|
||||||
|
|
||||||
def run_phantomjs(script, args=[]):
|
def run_phantomjs(script, script_args=[], pjs_args=[]):
|
||||||
output = []
|
output = []
|
||||||
command = [phantomjs_exe, script]
|
command = [phantomjs_exe]
|
||||||
command.extend(args)
|
command.extend(pjs_args)
|
||||||
|
command.append(script)
|
||||||
|
command.extend(script_args)
|
||||||
process = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
|
||||||
|
|
||||||
def runner():
|
def runner():
|
||||||
|
@ -244,23 +247,34 @@ def run_phantomjs(script, args=[]):
|
||||||
|
|
||||||
|
|
||||||
def run_test(script, name):
|
def run_test(script, name):
|
||||||
args = []
|
script_args = []
|
||||||
|
pjs_args = []
|
||||||
if options.verbose:
|
if options.verbose:
|
||||||
args.append('--verbose')
|
script_args.append('--verbose')
|
||||||
|
|
||||||
result = 0
|
try:
|
||||||
if not os.path.isfile(script):
|
with open(script, "rt") as s:
|
||||||
print 'Could not locate %s' % name
|
p_prefix = "// phantomjs: "
|
||||||
result = 1
|
s_prefix = "// script: "
|
||||||
else:
|
for line in s:
|
||||||
print '%s:' % name
|
if line.startswith(p_prefix):
|
||||||
returncode, output = run_phantomjs(script, args)
|
pjs_args.extend(shlex.split(line[len(p_prefix):]))
|
||||||
if returncode != 0:
|
if line.startswith(s_prefix):
|
||||||
if not options.verbose:
|
script_args.extend(shlex.split(line[len(s_prefix):]))
|
||||||
print '%s' % output
|
if not line.startswith("//"):
|
||||||
result = 1
|
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():
|
def run_tests():
|
||||||
|
|
Loading…
Reference in New Issue