2011-04-09 21:34:04 +04:00
|
|
|
/*
|
|
|
|
This file is part of the PhantomJS project from Ofi Labs.
|
|
|
|
|
|
|
|
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
2011-04-10 09:37:06 +04:00
|
|
|
Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>
|
2011-04-09 21:34:04 +04:00
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the <organization> nor the
|
|
|
|
names of its contributors may be used to endorse or promote products
|
|
|
|
derived from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2011-05-25 21:46:51 +04:00
|
|
|
#include "phantom.h"
|
|
|
|
|
|
|
|
#include <QtGui>
|
|
|
|
#include <QtWebKit>
|
2011-06-08 02:22:41 +04:00
|
|
|
#include <QDir>
|
|
|
|
#include <QFileInfo>
|
2011-06-14 14:28:51 +04:00
|
|
|
#include <QFile>
|
2010-12-27 07:04:53 +03:00
|
|
|
|
2011-04-08 17:30:50 +04:00
|
|
|
#include "consts.h"
|
|
|
|
#include "utils.h"
|
2011-05-25 21:46:51 +04:00
|
|
|
#include "webpage.h"
|
2011-01-01 19:28:38 +03:00
|
|
|
|
2011-08-16 22:15:02 +04:00
|
|
|
#include "registry.h"
|
|
|
|
|
2011-06-14 14:28:51 +04:00
|
|
|
// public:
|
2010-12-27 07:04:53 +03:00
|
|
|
Phantom::Phantom(QObject *parent)
|
|
|
|
: QObject(parent)
|
2011-05-29 11:20:56 +04:00
|
|
|
, m_terminated(false)
|
2010-12-27 07:04:53 +03:00
|
|
|
, m_returnValue(0)
|
2011-03-02 11:41:23 +03:00
|
|
|
, m_converter(0)
|
2011-04-08 20:55:10 +04:00
|
|
|
, m_netAccessMan(0)
|
2010-12-27 07:04:53 +03:00
|
|
|
{
|
2011-05-26 01:00:20 +04:00
|
|
|
m_page = new WebPage(this);
|
2011-06-29 02:27:26 +04:00
|
|
|
m_pages.append(m_page);
|
2010-12-27 07:04:53 +03:00
|
|
|
|
2011-05-25 21:46:51 +04:00
|
|
|
QString proxyHost;
|
2011-07-19 21:32:42 +04:00
|
|
|
QString cookieFile;
|
2011-05-25 21:46:51 +04:00
|
|
|
int proxyPort = 1080;
|
2011-02-14 08:29:58 +03:00
|
|
|
bool autoLoadImages = true;
|
2011-03-01 02:17:59 +03:00
|
|
|
bool pluginsEnabled = false;
|
2011-04-12 18:21:09 +04:00
|
|
|
bool diskCacheEnabled = false;
|
2011-04-29 12:24:35 +04:00
|
|
|
bool ignoreSslErrors = false;
|
2011-06-24 18:57:55 +04:00
|
|
|
bool localAccessRemote = false;
|
2011-02-14 08:29:58 +03:00
|
|
|
|
2010-12-27 07:04:53 +03:00
|
|
|
// second argument: script name
|
2011-02-14 07:41:59 +03:00
|
|
|
QStringList args = QApplication::arguments();
|
2011-02-13 22:38:09 +03:00
|
|
|
|
2011-02-14 07:41:59 +03:00
|
|
|
// Skip the first argument, i.e. the application executable (phantomjs).
|
|
|
|
args.removeFirst();
|
|
|
|
|
|
|
|
// Handle all command-line options.
|
|
|
|
QStringListIterator argIterator(args);
|
2011-02-06 21:55:04 +03:00
|
|
|
while (argIterator.hasNext()) {
|
|
|
|
const QString &arg = argIterator.next();
|
2011-06-06 11:36:31 +04:00
|
|
|
if (arg == "--version") {
|
|
|
|
m_terminated = true;
|
2011-08-16 22:15:02 +04:00
|
|
|
Registry::terminal().cout(QString("%1 (development)").arg(PHANTOMJS_VERSION_STRING));
|
2011-06-06 11:36:31 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-02-14 08:29:58 +03:00
|
|
|
if (arg == "--load-images=yes") {
|
|
|
|
autoLoadImages = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (arg == "--load-images=no") {
|
|
|
|
autoLoadImages = false;
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-14 09:44:00 +03:00
|
|
|
if (arg == "--load-plugins=yes") {
|
|
|
|
pluginsEnabled = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (arg == "--load-plugins=no") {
|
|
|
|
pluginsEnabled = false;
|
|
|
|
continue;
|
|
|
|
}
|
2011-04-12 18:21:09 +04:00
|
|
|
if (arg == "--disk-cache=yes") {
|
|
|
|
diskCacheEnabled = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (arg == "--disk-cache=no") {
|
|
|
|
diskCacheEnabled = false;
|
|
|
|
continue;
|
|
|
|
}
|
2011-04-29 12:24:35 +04:00
|
|
|
if (arg == "--ignore-ssl-errors=yes") {
|
|
|
|
ignoreSslErrors = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (arg == "--ignore-ssl-errors=no") {
|
|
|
|
ignoreSslErrors = false;
|
|
|
|
continue;
|
|
|
|
}
|
2011-06-24 18:57:55 +04:00
|
|
|
if (arg == "--local-access-remote=no") {
|
|
|
|
localAccessRemote = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (arg == "--local-access-remote=yes") {
|
|
|
|
localAccessRemote = true;
|
|
|
|
continue;
|
|
|
|
}
|
2011-03-14 07:35:05 +03:00
|
|
|
if (arg.startsWith("--proxy=")) {
|
2011-05-25 21:46:51 +04:00
|
|
|
proxyHost = arg.mid(8).trimmed();
|
|
|
|
if (proxyHost.lastIndexOf(':') > 0) {
|
2011-03-14 07:35:05 +03:00
|
|
|
bool ok = true;
|
2011-05-25 21:46:51 +04:00
|
|
|
int port = proxyHost.mid(proxyHost.lastIndexOf(':') + 1).toInt(&ok);
|
2011-03-14 07:35:05 +03:00
|
|
|
if (ok) {
|
2011-05-25 21:46:51 +04:00
|
|
|
proxyHost = proxyHost.left(proxyHost.lastIndexOf(':')).trimmed();
|
|
|
|
proxyPort = port;
|
2011-03-14 07:35:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2011-07-19 21:32:42 +04:00
|
|
|
if (arg.startsWith("--cookies=")) {
|
|
|
|
cookieFile = arg.mid(10).trimmed();
|
|
|
|
continue;
|
|
|
|
}
|
2011-08-16 22:49:12 +04:00
|
|
|
if (arg.startsWith("--output-encoding=")) {
|
|
|
|
Registry::terminal().setEncoding(arg.mid(18).trimmed());
|
|
|
|
continue;
|
|
|
|
}
|
2011-08-16 22:53:56 +04:00
|
|
|
if (arg.startsWith("--script-encoding=")) {
|
|
|
|
m_scriptFileEnc.setEncoding(arg.mid(18).trimmed());
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-14 07:41:59 +03:00
|
|
|
if (arg.startsWith("--")) {
|
2011-08-16 22:15:02 +04:00
|
|
|
Registry::terminal().cerr(QString("Unknown option '%1'").arg(arg));
|
2011-06-18 05:37:01 +04:00
|
|
|
m_terminated = true;
|
2011-02-14 07:41:59 +03:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
m_scriptFile = arg;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_scriptFile.isEmpty()) {
|
2011-04-08 17:30:50 +04:00
|
|
|
Utils::showUsage();
|
2011-02-14 07:41:59 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-25 21:46:51 +04:00
|
|
|
if (proxyHost.isEmpty()) {
|
2011-03-14 07:35:05 +03:00
|
|
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
|
|
|
} else {
|
2011-05-25 21:46:51 +04:00
|
|
|
QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyHost, proxyPort);
|
2011-03-14 07:35:05 +03:00
|
|
|
QNetworkProxy::setApplicationProxy(proxy);
|
|
|
|
}
|
|
|
|
|
2011-02-14 08:29:58 +03:00
|
|
|
// The remaining arguments are available for the script.
|
2011-02-14 07:41:59 +03:00
|
|
|
while (argIterator.hasNext()) {
|
|
|
|
const QString &arg = argIterator.next();
|
|
|
|
m_args += arg;
|
2011-02-06 21:55:04 +03:00
|
|
|
}
|
2010-12-27 07:04:53 +03:00
|
|
|
|
2011-04-08 20:55:10 +04:00
|
|
|
// Provide WebPage with a non-standard Network Access Manager
|
2011-07-19 21:32:42 +04:00
|
|
|
m_netAccessMan = new NetworkAccessManager(this, diskCacheEnabled, cookieFile, ignoreSslErrors);
|
2011-05-26 01:00:20 +04:00
|
|
|
m_page->setNetworkAccessManager(m_netAccessMan);
|
2011-04-08 20:55:10 +04:00
|
|
|
|
2011-06-20 08:06:27 +04:00
|
|
|
connect(m_page, SIGNAL(javaScriptConsoleMessageSent(QString, int, QString)),
|
|
|
|
SLOT(printConsoleMessage(QString, int, QString)));
|
2011-05-29 08:16:18 +04:00
|
|
|
|
2011-06-24 18:57:55 +04:00
|
|
|
m_defaultPageSettings[PAGE_SETTINGS_LOAD_IMAGES] = QVariant::fromValue(autoLoadImages);
|
|
|
|
m_defaultPageSettings[PAGE_SETTINGS_LOAD_PLUGINS] = QVariant::fromValue(pluginsEnabled);
|
|
|
|
m_defaultPageSettings[PAGE_SETTINGS_USER_AGENT] = QVariant::fromValue(m_page->userAgent());
|
|
|
|
m_defaultPageSettings[PAGE_SETTINGS_LOCAL_ACCESS_REMOTE] = QVariant::fromValue(localAccessRemote);
|
2011-05-28 09:36:34 +04:00
|
|
|
m_page->applySettings(m_defaultPageSettings);
|
2011-01-28 02:53:51 +03:00
|
|
|
|
2011-06-18 07:17:58 +04:00
|
|
|
setLibraryPath(QFileInfo(m_scriptFile).dir().absolutePath());
|
2011-06-13 01:38:34 +04:00
|
|
|
|
2011-05-26 01:00:20 +04:00
|
|
|
m_page->mainFrame()->addToJavaScriptWindowObject("phantom", this);
|
2011-06-29 00:02:48 +04:00
|
|
|
m_page->mainFrame()->addToJavaScriptWindowObject("fs", &m_filesystem);
|
2011-05-26 13:18:09 +04:00
|
|
|
|
|
|
|
QFile file(":/bootstrap.js");
|
|
|
|
if (!file.open(QFile::ReadOnly)) {
|
2011-08-16 22:15:02 +04:00
|
|
|
Registry::terminal().cerr("Can not bootstrap!");
|
2011-05-26 13:18:09 +04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
QString bootstrapper = QString::fromUtf8(file.readAll());
|
|
|
|
file.close();
|
|
|
|
if (bootstrapper.isEmpty()) {
|
2011-08-16 22:15:02 +04:00
|
|
|
Registry::terminal().cerr("Can not bootstrap!");
|
2011-05-26 13:18:09 +04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
m_page->mainFrame()->evaluateJavaScript(bootstrapper);
|
2010-12-27 07:04:53 +03:00
|
|
|
}
|
|
|
|
|
2011-05-25 21:46:51 +04:00
|
|
|
QStringList Phantom::args() const
|
2010-12-27 07:04:53 +03:00
|
|
|
{
|
2011-05-25 21:46:51 +04:00
|
|
|
return m_args;
|
2010-12-27 07:04:53 +03:00
|
|
|
}
|
|
|
|
|
2011-05-28 09:36:34 +04:00
|
|
|
QVariantMap Phantom::defaultPageSettings() const
|
|
|
|
{
|
|
|
|
return m_defaultPageSettings;
|
|
|
|
}
|
|
|
|
|
2011-08-16 23:17:42 +04:00
|
|
|
QString Phantom::outputEncoding() const
|
2011-08-16 22:18:52 +04:00
|
|
|
{
|
|
|
|
return Registry::terminal().getEncoding();
|
|
|
|
}
|
|
|
|
|
2011-08-16 23:17:42 +04:00
|
|
|
void Phantom::setOutputEncoding(const QString &encoding)
|
2011-08-16 22:18:52 +04:00
|
|
|
{
|
|
|
|
Registry::terminal().setEncoding(encoding);
|
|
|
|
}
|
|
|
|
|
2011-02-14 07:41:59 +03:00
|
|
|
bool Phantom::execute()
|
2010-12-27 07:04:53 +03:00
|
|
|
{
|
2011-06-18 05:04:20 +04:00
|
|
|
if (m_terminated)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_scriptFile.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
2011-08-16 22:53:56 +04:00
|
|
|
if (!Utils::injectJsInFrame(m_scriptFile, m_scriptFileEnc, QDir::currentPath(), m_page->mainFrame(), true)) {
|
2011-06-18 05:04:20 +04:00
|
|
|
m_returnValue = -1;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-06-18 07:52:13 +04:00
|
|
|
return !m_terminated;
|
2010-12-27 07:04:53 +03:00
|
|
|
}
|
|
|
|
|
2011-04-08 17:30:50 +04:00
|
|
|
int Phantom::returnValue() const
|
2010-12-27 07:04:53 +03:00
|
|
|
{
|
2011-04-08 17:30:50 +04:00
|
|
|
return m_returnValue;
|
2010-12-27 07:04:53 +03:00
|
|
|
}
|
|
|
|
|
2011-06-14 14:28:51 +04:00
|
|
|
QString Phantom::libraryPath() const
|
|
|
|
{
|
|
|
|
return m_page->libraryPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Phantom::setLibraryPath(const QString &libraryPath)
|
|
|
|
{
|
|
|
|
m_page->setLibraryPath(libraryPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Phantom::scriptName() const
|
|
|
|
{
|
|
|
|
return QFileInfo(m_scriptFile).fileName();
|
|
|
|
}
|
|
|
|
|
2011-04-08 17:30:50 +04:00
|
|
|
QVariantMap Phantom::version() const
|
|
|
|
{
|
|
|
|
QVariantMap result;
|
|
|
|
result["major"] = PHANTOMJS_VERSION_MAJOR;
|
|
|
|
result["minor"] = PHANTOMJS_VERSION_MINOR;
|
|
|
|
result["patch"] = PHANTOMJS_VERSION_PATCH;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-06-14 14:28:51 +04:00
|
|
|
// public slots:
|
2011-05-25 21:46:51 +04:00
|
|
|
QObject *Phantom::createWebPage()
|
2011-04-08 17:30:50 +04:00
|
|
|
{
|
2011-05-26 12:56:43 +04:00
|
|
|
WebPage *page = new WebPage(this);
|
2011-06-29 02:27:26 +04:00
|
|
|
m_pages.append(page);
|
2011-05-28 09:36:34 +04:00
|
|
|
page->applySettings(m_defaultPageSettings);
|
2011-05-26 12:56:43 +04:00
|
|
|
page->setNetworkAccessManager(m_netAccessMan);
|
2011-06-18 07:17:58 +04:00
|
|
|
page->setLibraryPath(QFileInfo(m_scriptFile).dir().absolutePath());
|
2011-05-26 12:56:43 +04:00
|
|
|
return page;
|
2011-04-08 17:30:50 +04:00
|
|
|
}
|
|
|
|
|
2011-06-14 14:28:51 +04:00
|
|
|
bool Phantom::injectJs(const QString &jsFilePath) {
|
|
|
|
return Utils::injectJsInFrame(jsFilePath, libraryPath(), m_page->mainFrame());
|
|
|
|
}
|
|
|
|
|
2011-06-20 21:14:08 +04:00
|
|
|
void Phantom::exit(int code)
|
2011-04-08 17:30:50 +04:00
|
|
|
{
|
2011-05-29 11:20:56 +04:00
|
|
|
m_terminated = true;
|
2011-04-08 17:30:50 +04:00
|
|
|
m_returnValue = code;
|
2011-06-29 02:27:26 +04:00
|
|
|
qDeleteAll(m_pages);
|
|
|
|
m_pages.clear();
|
2011-06-21 10:24:51 +04:00
|
|
|
m_page = 0;
|
2011-05-29 11:20:56 +04:00
|
|
|
QApplication::instance()->exit(code);
|
2010-12-27 07:04:53 +03:00
|
|
|
}
|
2011-05-29 08:16:18 +04:00
|
|
|
|
2011-07-03 04:08:06 +04:00
|
|
|
void Phantom::_destroy(QObject *page) {
|
|
|
|
m_pages.removeOne((WebPage*)page);
|
|
|
|
delete page;
|
|
|
|
}
|
|
|
|
|
2011-06-14 14:28:51 +04:00
|
|
|
// private slots:
|
2011-06-20 08:06:27 +04:00
|
|
|
void Phantom::printConsoleMessage(const QString &message, int lineNumber, const QString &source)
|
2011-05-29 08:16:18 +04:00
|
|
|
{
|
2011-06-20 08:06:27 +04:00
|
|
|
QString msg = message;
|
|
|
|
if (!source.isEmpty())
|
|
|
|
msg = source + ":" + QString::number(lineNumber) + " " + msg;
|
2011-08-16 22:15:02 +04:00
|
|
|
Registry::terminal().cout(msg);
|
2011-05-29 08:16:18 +04:00
|
|
|
}
|