Compare commits

..

16 Commits

Author SHA1 Message Date
Ariya Hidayat cbc9be0a7f Don't create window.WebServer.
It was done for WebPage for backward compatibility and it would be
removed in the future, so don't do it for WebServer.

http://code.google.com/p/phantomjs/issues/detail?id=115
2011-12-22 21:34:47 -08:00
Ariya Hidayat 1ee0a4ce44 Mac build script: x86 only for better compatibility.
http://code.google.com/p/phantomjs/issues/detail?id=142
2011-12-22 21:20:52 -08:00
Ariya Hidayat fa4309e381 Mac build script: Make sure it's executable.
http://code.google.com/p/phantomjs/issues/detail?id=142
2011-12-22 17:33:58 -08:00
Ariya Hidayat 724d28863b Static build: Don't merge Mac and Linux script.
Apparently with Qt 4.8, static build on Linux does not work out of the
box so there is no need to merge the static build scripts.

Also, tweak some configure options.

http://code.google.com/p/phantomjs/issues/detail?id=142
http://code.google.com/p/phantomjs/issues/detail?id=197
2011-12-22 17:30:33 -08:00
Ariya Hidayat bfc16995b4 Linux build script: Keep to 4 parallel jobs at most.
http://code.google.com/p/phantomjs/issues/detail?id=197
2011-12-22 17:28:27 -08:00
Ariya Hidayat 3c13b9dca1 Static build script: Fix the build.
MIT SHM is needed on X11.
Local path is better passed directly to configure.

http://code.google.com/p/phantomjs/issues/detail?id=142
http://code.google.com/p/phantomjs/issues/detail?id=197
2011-12-22 09:32:35 -08:00
Ariya Hidayat c32d78747c Static build script: attempt to unify both Mac and Linux version.
http://code.google.com/p/phantomjs/issues/detail?id=142
http://code.google.com/p/phantomjs/issues/detail?id=197
2011-12-22 08:31:03 -08:00
Ariya Hidayat 62811468e4 Merge branch '1.4' of github.com:ariya/phantomjs into 1.4 2011-12-21 08:40:38 -08:00
Ariya Hidayat eb33e89e7a Merge branch 'master' into 1.4 2011-12-21 08:39:22 -08:00
Ariya Hidayat f4f59b2319 WebServer: make sure status code is used for writeHead() function.
http://code.google.com/p/phantomjs/issues/detail?id=115
2011-12-21 07:56:09 -08:00
Ariya Hidayat 56a5641b0e WebServer: make sure status code is used for writeHead() function. 2011-12-21 07:49:00 -08:00
Ariya Hidayat cd590f2524 Mac build script: update to get Qt 4.8.0.
http://code.google.com/p/phantomjs/issues/detail?id=142
2011-12-20 22:49:34 -08:00
Ariya Hidayat 2e2fef788d Refer to 1.4 in the README. 2011-12-20 08:35:21 -08:00
Ariya Hidayat dea72dcbd3 Remove the complex example for WebServer module.
The simpleserver should be a better starting point to learn the module.

http://code.google.com/p/phantomjs/issues/detail?id=115
2011-12-20 08:35:20 -08:00
Ariya Hidayat ec57f2e2f1 Hide the experimental remote debugger support. 2011-12-20 08:27:13 -08:00
Ariya Hidayat d6219e16d6 Version is now 1.4.0, not 1.4.0 (development). 2011-12-20 08:26:20 -08:00
1988 changed files with 23440 additions and 519203 deletions

58
.gitignore vendored
View File

@ -2,6 +2,7 @@
*.pro.user* *.pro.user*
*.xcodeproj *.xcodeproj
Makefile* Makefile*
bin/phantomjs
*~ *~
*.moc *.moc
moc_* moc_*
@ -9,53 +10,10 @@ qrc_*
*.o *.o
*.swp *.swp
*.pyc *.pyc
*.a debian/*.debhelper
/debian/*.debhelper debian/files
/debian/files debian/*.log
/debian/*.log debian/*.substvars
/debian/*.substvars debian/*/
/debian/*/ python/build/
/deploy/qt-*.tar.gz python/*.egg-info/
/deploy/Qt-*
/symbols
/src/qt/qtc-debugging-helper
/src/phantomjs_plugin_import.cpp
# ignore ctags
/tags
/tools/dump_syms.app/
# Ignore Visual Studio temporary files, build results, etc
*.suo
*.user
*.sln.docstates
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.log
*.sdf
*.vcxproj
*.vcxproj.filters
*.lib
*.prl
*.intermediate.manifest
# Build results
[Dd]ebug*/
[Rr]elease/
bin/
*.class
build/
.gradle/

View File

@ -1,29 +0,0 @@
language: cpp
compiler:
- gcc
cache: apt
before_install:
- sudo apt-get -yqq update #< Suggested by the Travis CI doc
- sudo apt-get -fyq install #< Fixes inconsistency of packages installed previously
install:
- sudo apt-get -yq install build-essential chrpath libssl-dev libfontconfig1-dev sqlite3 libsqlite3-dev ruby gperf bison flex libicu48 libicu-dev #< Build Dependencies
before_script:
- chmod +x ./build.sh
- chmod +x ./test/run-tests.sh
- chmod +x ./test/run-tests-ghostdriver.sh
script:
- ./build.sh --confirm --silent #< Build
- ./test/run-tests.sh #< Test (PhantomJS)
- ./test/run-tests-ghostdriver.sh #< Test (GhostDriver / PhantomJSDriver)
notifications:
irc:
channels:
- "irc.freenode.org#phantomjs"
on_success: always
on_failure: always
use_notice: true

View File

@ -1,88 +0,0 @@
# Contribution Guide
This page describes how to contribute changes to PhantomJS.
Please do **not** create a pull request without reading this guide first. Failure to do so may result in the **rejection** of the pull request.
## For The Impatients
**Work on a feature branch**.
If your changes need to be modified due to some reviews, it is less clutter to tweak an isolated feature branch and push it again.
**Create a ticket in the issue tracker**.
This serves as a placeholder for important feedback, review, or any future updates.
In the commit message:
* **Keep the first line < 72 characters**. Write additional paragraphs
if necessary.
* **Put the link to the issue** (see above). This is important for cross-referencing purposes.
## Communicate
*Second opinion is always important.*
**Bug fixing**. If you have a fix for a bug, please attach your patch in the corresponding issue in the [issue tracker](https://github.com/ariya/phantomjs/issues). If there is no entry for the bug yet, then please create a new one. If you are confident working with Git, see the Get Ready section below on how to submit your change.
**Improvement and feature request**. If you have an improvement idea, please send an email to the [mailing list](http://groups.google.com/group/phantomjs) (rather than contacting the developers directly) so that other people can give their insights and opinions. This is also important to avoid duplicate work.
**Task management**. Once the feature idea is agreed upon and translated into concrete actions and tasks, please use the [issue tracker](https://github.com/ariya/phantomjs/issues) to create an issue for each individual task. Further technical discussion about the task and the implementation details should be carried out in the issue tracker.
**Extending with new API**. Whenever you want to introduce a new API, please send an email to the mailing list along with the link to the issue. Consider good API name for the object or function, read the [API Design Principle](http://developer.qt.nokia.com/wiki/API_Design_Principles) article. It may require few iterations to agree on the final API and hence it is important to engage all interested parties as early as possible.
## Get Ready
For your proposed change, you need to have:
* **an issue** (in the issue tracker) which describe your bug or feature
* **a feature branch** in your git fork
### Refer the Issue
The commit message needs to link to the issue. This cross-reference is [very important](http://ariya.ofilabs.com/2012/01/small-scale-software-craftsmanship.html) for the following reasons.
First, the commit log is frozen and can not be changed. If it contains a mistake or outdated information, the log can not be amended. However, further updates can be still posted to the linked issue, which can be followed from the commit log itself.
Second, it provides a placeholder for code review and other feedback.
An example of a bad commit log:
Fix Mountain Lion
The above log is too short and useless in the long run. A better version (and note the issue link):
Better support for OS X Mountain Lion.
require('system').os.version should give "10.8 (Mountain Lion)".
https://github.com/ariya/phantomjs/issues/10688
### Use Feature Branch
To isolate your change, please avoid working on the master branch. Instead, work on a *feature branch* (often also known as *topic branch*). You can create a new branch (example here crash-fix) off the master branch by using:
git checkout -b crash-fix master
Refer to your favorite Git tutorial/book for further detailed help.
Some good practices for the feature branch:
* Give it a meaningful name instead of, e.g. `prevent-zero-divide` instead of just `fix`
* Make *granular* and *atomic* commits, e.g. do not mix a typo fix with some major refactoring
* Keep one branch for one specific issue. If you need to work on other unrelated issues, create another branch.
## Review and Merge
When your branch is ready, send the pull request.
While it is not always the case, often it is necessary to improve parts of your code in the branch. This is the actual review process.
Here is a check list for the review:
* It does not break the test suite
* There is no typo
* The coding style follows the existing one
* There is a reasonable amount of comment
* The license header is intact
* All examples are still working

245
ChangeLog
View File

@ -1,247 +1,4 @@
Please see also http://phantomjs.org/releases.html. Please see also http://code.google.com/p/phantomjs/wiki/ReleaseNotes.
2015-01-23: Version 2.0.0
New features
* Switched to Qt 5 and updated WebKit (issue 10448)
* Implemented clearing of memory cache (issue 10357)
* Added support for HTTP header change for every request (issue 11299)
Improvements
* Fixed rendering of CJK text by always linking the codecs (issue 10249)
* Ensured onResourceReceived is still fired on an error (issue 11163)
* Fixed possible crash in handling network requests (issue 11252)
* Removed hardcoded GhostDriver launching message (issue 12681)
* Allowed disk cache more than 2 GB (issue 12303)
Examples
* Netsniff example should exit when fails to load (issue 11333)
2014-01-25: Version 1.9.7
* Reverted to GhostDriver 1.1.0 instead of 1.1.1 (issue 11915)
* Fixed another warning of obsolete userSpaceScaleFactor on OS X 10.9 (issue 11612)
2014-01-20: Version 1.9.6
* Updated GhostDriver to version 1.1.1 (issue 11877, 11893)
2014-01-19: Version 1.9.3
* Fixed CoreText performance note on OS X 10.9 (issue 11418)
* Fixed warning of obsolete userSpaceScaleFactor on OS X 10.9 (issue 11612)
2013-09-06: Version 1.9.2
* Fixed graphical artifacts with transparent background on Windows (issue 11276, 11007, 11366)
* Updated GhostDriver to version 1.0.4 (issue 11452)
2013-06-04: Version 1.9.1
Critical bug fixes:
* Fixed problems with specifying proxy server (issue 10811, 11117)
* Fixed UTF-8 encoding with system.stdout and system.stderr (issue 11162)
* Ensured that onResourceReceived will be always invoked (issue 11163)
* Fixed module loading from an absolute path on Windows (issue 11165)
* Fixed typo in the command-line option for setting the cache size (11219)
* Fixed possible crash when handling network requests (issue 11252, 11338)
2013-03-20: Version 1.9.0 "Sakura"
New features
* Added spawn and execFile to execute external programs (issue 10219)
* Added the ability to abort network requests (issue 10230)
* Added system access to stdin, stdout, and stderr (issue 10333)
* Added support for custom CA certificates location (issue 10916)
* Added seek function to the File stream (issue 10937)
* Implemented file read for a specified number of bytes (issue 10938)
* Added a callback to handle network error (issue 10954, 10997)
* Added custom encoding support when opening a page (issue 11043)
* Implemented require.stub() support for a factory function (issue 11044)
* Added page loading indicator and progress (issue 11091)
* Added a timeout option for network requests (issue 11129)
Improvements
* Fixed the build on FreeBSD (issue 10597)
* Ensured a consistent 72 dpi for Linux headless rendering (issue 10659)
* Fixed possible PDF error due to invalid CreationDate field (issue 10663)
* Fixed crash when uploading non existing files (issue 10941)
* Improved the autocomplete internal of the interactive/REPL mode (issue 10943)
* Fixed possible crash when accessing inline frames (issue 10947)
* Changed Linux binary package setup to be built on CentOS 5 (issue 10963)
* Extended SSL ignore setting to synchronous XHR (issue 10985)
* Added convenient constants for modifier keys (issue 11056)
* Fixed incorrect date handling in the cookies (issue 11068)
* Updated GhostDriver to version 1.0.3 (issue 11146)
Examples
* Fixed invalid data URI in the netsniff example (issue 10740)
* Implemented a new weather example (issue 10794)
* Fixed rendering issues in render_multi_url (issue 11021)
* Fixed proper event sequence in page_events example (issue 11028)
* Miscellanous tweaks (issue 11082)
2013-03-02: Version 1.8.2
Critical bug fixes:
* Fixed possible PDF error due to invalid CreationDate field (issue 663)
* Fixed crash when uploading non existing files (issue 941)
* Fixed possible crash when accessing inline frames (issue 947)
* Extended SSL ignore setting to synchronous XHR (issue 985)
* Fixed incorrect date handling in the cookies (issue 1068)
2013-01-06: Version 1.8.1
Critical bug fix:
* Mac OS X: Fix possible crash when using some TrueType fonts (issue 690)
2012-12-21: Version 1.8.0 "Blue Winter Rose"
New features
* Integrated GhostDriver as the WebDriver implementation (issue 49)
* Added an option to specify the SSL protocol (issue 174)
* Added encoding support for WebServer's response (issue 505)
* Added process ID (PID) to the System module (issue 769)
* Added properties to obtain page and frame title (issue 799)
* Added page navigation methods (issue 808)
* Added support for modifier keys in keyboard events (issue 835)
* Added onFilePicker callback for more generic file upload API (issue 843)
* Added the ability to set the page content and location (issue 909)
Improvements
* Fixed date parsing in ISO8601 format (issue 187, 267)
* Fixed window.location (issue 530, 632)
* Deregistered multiple callback handler (issue 807)
* Fixed sending of double-click events (issue 848)
* Increases maximum number of redirects (issue 849)
* Fixed keycodes sent for lowercase characters (issue 852)
* Fixed a regression in table row page break (issue 880)
* Completed the CoffeeScript version of the examples (issue 907)
* Updated Qt to version 4.8.4 (issue 918)
* Fixed potential hang in some example scripts (issue 922)
2012-09-22: Version 1.7.0 "Blazing Star"
New features
* Added a module system modelled after CommonJS/Node.js (issue 47)
* Added support for window pop-up (issue 151)
* Static build on Linux (issue 413)
* Added run-time detection of SSL support (issue 484)
* Added more events support (issue 492, 712)
* Added support for disabling automatic proxy detection (issue 580)
* Provided page closing callback (issue 678)
* Added methods to access URL, frames URL, frame Content (issue 758)
* Added more cookies-related API (issue 761)
Improvements
* Refactored command-line options handling (issue 55)
* Improved the workflow for producing release builds (issue 599)
* Improved cookies API and implementation (issue 603, 761)
* Improved frame switching API (issue 654)
* Fixed iframe handling regression (issue 683)
* Fixed OS version number with Windows 8 and Mountain Lion (issue 684, 688)
* Fixed HAR navigation info in the netsniff example (issue 733)
* Fixed compile warnings with Visual Studio (issue 744)
* Removed hacks for static linking on Windows (issue 753)
* Added ICO image handling on Windows (issue 779)
* Fixed font antialiasing on Windows (issue 785)
* Improved Jasmine test runner for Jasmine 1.2 (issue 792)
2012-07-22: Version 1.6.1
Bug fixes
* Don't build the deploy in debug mode (issue 599)
* Fixed building on Windows (issue 424)
* Fixed remote inspector when building statically (issue 430)
2012-06-20: Version 1.6.0 "Lavender"
New features
* Added support for passing arguments to WebPage's evaluate (issue 132)
* Added callbacks for JavaScript onConfirm and onPrompt (issue 133)
* Added stack trace when error occurs (issue 166)
* Added support for local storage path and quota (issue 300)
* Added initial support for cookies handling (issue 354)
* Added support for header footer when printing the page (issue 410, 512)
* Added headers support in the loading request (issue 452)
* Added support to render the web page as base64-encoded string (issue 547)
* Added hooks for navigation event (issue 562)
* Added command-line option to show debug messages (issue 575)
* Added support for the zoom factor for web page rendering (issue 579)
* Added crash reporter for Mac OS X and Linux, based on Google Breakpad (issue 576)
* Added 'os' object to the system module (issue 585)
* Added support for asynchronous evaluation (issue 593)
Improvements
* Fixed remote debugging to work on Mac OS X and Windows (issue 430)
* Fixed web server getting the dropped connection for empty response (issue 451)
* Fixed text rendered as boxes (squares) on headless Linux (issue 460)
* Updated Qt to version 4.8.2 (issue 495)
* Updated CoffeeScript compiler to version 1.3.3 (issue 496)
* Fixed the build script to detect and use MAKEFLAGS (issue 503)
* Fixed the build script to properly pass Qt config flags (issue 507)
* Changed Info.plist to be embedded in Mac OS X executable (issue 528)
* Fixed wrong module require in the imagebin example (issue 536)
* Fixed example scripts to exit with the right exit code (issue 544)
* Fixed build failure with glib 2.31.0+ (issue 559)
* Fixed error handler failures in some cases (issue 589)
* Fixed Twitter-related examples to work with the new site (issue 609)
2012-03-20: Version 1.5.0 "Ghost Flower"
New features
* Added interactive mode, also known as REPL (issue 252)
* Added setting for web security, to allow cross domain XHR (issue 28)
* Added error handler for WebPage object (issue 166)
* Added support for custom HTTP header in the network request (issue 77)
* Added support for read write encoding in the file system module (issue 367)
* Added remote debugging support on Linux (issue 6)
* Added support for proxy authentication (issue 105)
* Added System module, to retrieve environment variables (issue 271) and arguments (issue 276)
* Added fs.readLink function (issue 329)
* Added support for reading and writing binary data (issue 400)
* Added support to retrieve request data in the WebServer? module (issue 340)
* Added support for individual top/bottom/left/right print margins (issue 388)
* Added command-line option --help (issue 347)
* Added short command-line options -v and -h (issue 408)
* Removed support for Flash and other plugins (issue 418)
Bug fixes
* Fixed multiple console.log arguments (issue 36)
* Fixed file upload (issue 307)
* Fixed the web server instance to be asynchronous (issue 326) and still support Keep Alive (issue 416)
* Workaround Qt 4.8.0 crash due to empty URL scheme (issue 365)
* Fixed a Content-Type problem where POST does not work (issue 337)
* Fixed reading body request in the web server even without specific Content-Type (issue 439)
* Fixed Jasmine test runner with Jasmine 1.1 (issue 402)
* Fixed request URL formatting in the web server (issue 437)
* Don't display debugging and warning messages (issue 323)
2011-12-31: Version 1.4.1
Bug fixes
* Fix setting the proxy type (issue 266)
* Workaround for file upload regression (issue 307)
* Fix extraneous messsages in non-debug mode (issue 323)
2011-12-22: Version 1.4.0 "Glory of the Snow" 2011-12-22: Version 1.4.0 "Glory of the Snow"

View File

@ -1,46 +1,33 @@
# [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit with JavaScript API.
PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript. It is used by hundreds of [developers](http://phantomjs.org/buzz.html) and dozens of [organizations](http://phantomjs.org/users.html) for web-related development workflow. It has **fast** and **native** support for DOM handling, CSS selector, JSON, Canvas, and SVG.
The latest [stable release](http://phantomjs.org/release-2.0.html) is version 2.0. PhantomJS is cross-platform, it can be compiled for Linux, Windows, FreeBSD, and Mac OS X.
Refer to the [build instructions](http://code.google.com/p/phantomjs/wiki/BuildInstructions)
for details.
**Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request. **Note**: If you are on Mac OS X, [read the notice](http://code.google.com/p/phantomjs/wiki/BuildInstructions#Mac_OS_X)
before you start using `brew` or `port` to install Qt and/or PhantomJS.
## Use Cases PhantomJS scripts can be written in JavaScript or [CoffeeScript](http://jashkenas.github.com/coffee-script/).
- **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](http://phantomjs.org/headless-testing.html) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported. See also [quick start guide](http://code.google.com/p/phantomjs/wiki/QuickStart)
- **Page automation**. [Access and manipulate](http://phantomjs.org/page-automation.html) web pages with the standard DOM API, or with usual libraries like jQuery. and more [advanced examples](http://code.google.com/p/phantomjs/wiki/ServiceIntegration)
- **Screen capture**. Programmatically [capture web contents](http://phantomjs.org/screen-capture.html), including CSS, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer. which show various PhantomJS scripts, covering:
- **Network monitoring**. Automate performance analysis, track [page loading](http://phantomjs.org/network-monitoring.html) and export as standard HAR format.
## Features * getting driving direction
* showing weather forecast conditions
* finding pizza in New York
* looking up approximate location based on IP address
* pulling the list of seasonal food
* running regression tests from command line
* producing PDF version of a Wikipedia article
* rasterizing SVG to image
- **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, and other Unices. Do not forget to consult the concise [API Reference](http://code.google.com/p/phantomjs/wiki/Interface).
- **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, and SVG. No emulation!
- **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, and Iron.io.
- **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes.
## Ecosystem PhantomJS is based on [Qt](http://qt.nokia.com). There are two implementations, using C++ and Python.
PhantomJS needs not be used only as a stand-alone tool. Check also some excellent related projects:
- [CasperJS](http://casperjs.org) enables easy navigation scripting and common high-level testing.
- [Poltergeist](https://github.com/jonleighton/poltergeist) allows running Capybara tests headlessly.
- [Guard::Jasmine](https://github.com/netzpirat/guard-jasmine) automatically tests Jasmine specs on Rails when files are modified.
- [GhostDriver](http://github.com/detro/ghostdriver/) complements Selenium tests with a PhantomJS WebDriver implementation.
- [PhantomRobot](https://github.com/datakurre/phantomrobot) runs Robot Framework acceptance tests in the background via PhantomJS.
- [Mocha-PhantomJS](https://github.com/metaskills/mocha-phantomjs) run Mocha tests using PhantomJS.
and many others [related projects](http://phantomjs.org/related-projects.html).
## Questions?
- Explore the complete [documentation](http://phantomjs.org/documentation/).
- Read tons of [user articles](http://phantomjs.org/buzz.html) on using PhantomJS.
- Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans.
PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code.
PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates.
The latest [stable release](http://code.google.com/p/phantomjs/wiki/ReleaseNotes) is version 1.4 ("Glory of the Snow").
If you want to contribute, please read the [Contribution Guide](http://code.google.com/p/phantomjs/wiki/ContributionGuide).

128
build.cmd
View File

@ -1,128 +0,0 @@
@echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
set BUILD_TYPE=release
if /i "%1" == "debug" (
SET BUILD_TYPE=debug
)
set ROOT_DIR=%CD%
set 3RD_PARTY_LIBRARIES_REPO_URL=https://github.com/Vitallium/phantomjs-3rdparty-win
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013
if /i BUILD_TYPE == "debug" (
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013_debug
)
set BUILD_DATESTAMP=%date:~-4,4%%date:~-7,2%%date:~-10,2%
set BUILD_TIMESTAMP=%time:~-11,2%%time:~-8,2%
:: replace leading space with 0
set BUILD_TIMESTAMP=%BUILD_TIMESTAMP: =0%
set QT_LOG_FILE=!ROOT_DIR!\build_qt_!BUILD_DATESTAMP!-!BUILD_TIMESTAMP!.log
set WEBKIT_LOG_FILE=!ROOT_DIR!\build_webkit_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set PHANTOMJS_LOG_FILE=!ROOT_DIR!\build_phantomjs_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set MAKE_TOOL=nmake
echo:
echo Build type: !BUILD_TYPE!
call :build
ENDLOCAL
@exit /B 0
rem ========================================================================================================
:build
SETLOCAL EnableExtensions EnableDelayedExpansion
set _3RDPARTY=!ROOT_DIR!\src\qt\3rdparty
for %%X in (git.exe) do (set GIT_FOUND=%%~$PATH:X)
if defined GIT_FOUND (
echo.
echo GIT found. Getting 3rd party libraries.
if not exist !_3RDPARTY! call git clone -b !3RD_PARTY_LIBRARIES_REPO_BRANCH! !3RD_PARTY_LIBRARIES_REPO_URL! !_3RDPARTY!
) else (
ECHO.
CALL :exitB "Git is missing! Can't proceed. Please install Git."
GOTO :eof
)
:: prepare 3rdparty libraries
:: setup INCLUDE and LIB environment variables
:: OpenSSL
set OPENSSL_DIR=!_3RDPARTY!\openssl
set OPENSSL_LIB=!OPENSSL_DIR!\lib
set OPENSSL_INCLUDE=!OPENSSL_DIR!\include
:: ICU
set ICU_DIR=!_3RDPARTY!\libicu
set ICU_LIB=!ICU_DIR!\lib
set ICU_INCLUDE=!ICU_DIR!\include
:: libxml
set LIBXML_DIR=!_3RDPARTY!\libxml
set LIBXML_LIB=!LIBXML_DIR!\lib
set LIBXML_INCLUDE=!LIBXML_DIR!\include\libxml2
:: sqlite
set SQLITE3SRCDIR=!ROOT_DIR!\src\qt\qtbase\src\3rdparty\sqlite
set LIB=!OPENSSL_LIB!;!ICU_LIB!;!LIBXML_LIB!;%LIB%
set INCLUDE=!OPENSSL_INCLUDE!;!ICU_INCLUDE!;!LIBXML_INCLUDE!;%INCLUDE%
set PATH=!_3RDPARTY!\gnuwin32\bin;%PATH%
echo LIB: %LIB%
echo INCLUDE: %INCLUDE%
for %%X in (jom.exe) do (set JOMFOUND=%%~$PATH:X)
if defined JOMFOUND (
set MAKE_TOOL=jom
) else (
set MAKE_TOOL=nmake
)
pushd !ROOT_DIR!\src\qt
call preconfig.cmd !BUILD_TYPE! 2>&1 >> !QT_LOG_FILE!
popd
set PATH=!ROOT_DIR!\src\qt\qtbase\bin;%PATH%
for %%X in (qmake.exe) do (set QMAKE_FOUND=%%~$PATH:X)
if defined QMAKE_FOUND (
echo.
echo qmake found. Building QtWebkit
) else (
ECHO.
CALL :exitB "qmake.exe is missing! Can't proceed."
GOTO :eof
)
pushd !ROOT_DIR!\src\qt\qtwebkit
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !WEBKIT_LOG_FILE!
popd
pushd !ROOT_DIR!\src
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !PHANTOMJS_LOG_FILE!
popd
if EXIST !ROOT_DIR!\bin\phantomjs.exe (
echo.
echo Build has finished
echo.
) else (
echo:
echo Unable to find phantomjs.exe. Please, check log files:
echo Qt: !QT_LOG_FILE!
echo Webkit: !WEBKIT_LOG_FILE!
echo PhantomJS: !PHANTOMJS_LOG_FILE!
echo:
)
EXIT /b
rem ========================================================================================================
:: %1 an error message
:exitB
echo:
echo Error: %1
echo:
echo Contact vitaliy.slobodin@gmail.com
@exit /B 0

View File

@ -1,82 +0,0 @@
#!/usr/bin/env bash
set -e
COMPILE_JOBS=1
MAKEFLAGS_JOBS=''
if [[ "$MAKEFLAGS" != "" ]]; then
MAKEFLAGS_JOBS=$(echo $MAKEFLAGS | egrep -o '\-j[0-9]+' | egrep -o '[0-9]+')
fi
if [[ "$MAKEFLAGS_JOBS" != "" ]]; then
# user defined number of jobs in MAKEFLAGS, re-use that number
COMPILE_JOBS=$MAKEFLAGS_JOBS
elif [[ $OSTYPE = darwin* ]]; then
# We only support modern Mac machines, they are at least using
# hyperthreaded dual-core CPU.
COMPILE_JOBS=4
elif [[ $OSTYPE == freebsd* ]]; then
COMPILE_JOBS=`sysctl -n hw.ncpu`
else
CPU_CORES=`grep -c ^processor /proc/cpuinfo`
if [[ "$CPU_CORES" -gt 1 ]]; then
COMPILE_JOBS=$CPU_CORES
fi
fi
if [[ "$COMPILE_JOBS" -gt 8 ]]; then
# Safety net.
COMPILE_JOBS=8
fi
SILENT=
until [[ -z "$1" ]]; do
case $1 in
(--qmake-args)
shift
QMAKE_ARGS=$1
shift;;
(--jobs)
shift
COMPILE_JOBS=$1
shift;;
(--silent)
SILENT=silent
shift;;
"--help")
cat <<EOF
Usage: $0 [--jobs NUM]
--silent Produce less verbose output.
--jobs NUM How many parallel compile jobs to use.
Defaults to the number of CPU cores you have,
with a maximum of 8.
EOF
exit 0
;;
*)
echo "Unrecognised option: $1" >&2
exit 1;;
esac
done
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
echo "System architecture... ($UNAME_SYSTEM $UNAME_RELEASE $UNAME_MACHINE)"
export QMAKE=qmake
# some Linux distros (e.g. Debian) allow you to parallel-install
# Qt4 and Qt5, using this environment variable to declare which
# one you want
export QT_SELECT=qt5
echo
echo "Building main PhantomJS application..."
echo
$QMAKE $QMAKE_ARGS
make -j$COMPILE_JOBS

5
debian/changelog vendored Normal file
View File

@ -0,0 +1,5 @@
phantomjs (1.3-1~git20110703) unstable; urgency=low
* Initial release.
-- Dennis Kaarsemaker <dennis@kaarsemaker.net> Sun, 03 Jul 2011 20:45:52 +0200

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
7

24
debian/control vendored Normal file
View File

@ -0,0 +1,24 @@
Source: phantomjs
Section: python
Priority: extra
Maintainer: Dennis Kaarsemaker <dennis@kaarsemaker.net>
Build-Depends: debhelper (>= 7), libqt4-dev (>= 4.6), libqtwebkit-dev, qt4-qmake, python-support (>= 0.6.4), python-all-dev (>= 2.5), python-qt4-dev, python-qt4
Standards-Version: 3.8.4
XS-Python-Version: >= 2.6
Vcs-Git: http://github.com/ariya/phantomjs
Package: phantomjs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: phantomjs - minimalistic headless WebKit-based JavaScript-driven tool
PhantomJS is a minimalistic, headless, WebKit-based, JavaScript-driven tool.
PhantomJs has native support for different web technologies: DOM handling,
CSS selector, JSON, Canvas, SVG, and of course JavaScript.
Package: python-pyphantomjs
Architecture: all
Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, python-qt4, python-argparse
Description: phantomjs - minimalistic headless WebKit-based JavaScript-driven tool
PhantomJS is a minimalistic, headless, WebKit-based, JavaScript-driven tool.
PhantomJs has native support for different web technologies: DOM handling,
CSS selector, JSON, Canvas, SVG, and of course JavaScript.

35
debian/copyright vendored Normal file
View File

@ -0,0 +1,35 @@
Format-Specification: http://anonscm.debian.org/viewvc/dep/web/deps/dep5.mdwn?revision=174&view=co&pathrev=174
Name: phantomjs
Maintainer: Dennis Kaarsemaker <dennis@kaarsemaker.net>
Source: http://github.com/ariya/phantomjs
Copyright: 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
License: BSD-3-clause
Files: debian/*
Copyright: 2011 Dennis Kaarsemaker <dennis@kaarsemaker.net>
License: BSD-3-clause
License: BSD-3-clause
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.

2
debian/phantomjs.docs vendored Normal file
View File

@ -0,0 +1,2 @@
README.md
examples

1
debian/phantomjs.install vendored Normal file
View File

@ -0,0 +1 @@
debian/tmp/usr/bin/phantomjs

1
debian/python-pyphantomjs.docs vendored Normal file
View File

@ -0,0 +1 @@
python/README.md

2
debian/python-pyphantomjs.install vendored Normal file
View File

@ -0,0 +1,2 @@
debian/tmp/usr/bin/pyphantomjs
debian/tmp/usr/lib

19
debian/rules vendored Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_build:
qmake-qt4
$(MAKE)
cd python && python setup.py build
override_dh_auto_install:
$(MAKE) install
mkdir -p debian/tmp/usr/bin
cp bin/* debian/tmp/usr/bin
cd python && python setup.py install --root=../debian/tmp --install-layout=deb
override_dh_auto_clean:
if [ -f Makefile ]; then $(MAKE) distclean; fi
cd python && python setup.py clean

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
1.0

2
deploy/.gitignore vendored
View File

@ -1,2 +0,0 @@
.vagrant
/brandelf

View File

@ -1,60 +0,0 @@
Packaging PhantomJS
===================
This directory contains various scripts to assist with making PhantomJS
packages.
Packaging for Linux
-------------------
Linux building/packaging is best done in a virtual machine to ensure
isolation and clean state. This is also necessary to build for different
architectures.
We use [Vagrant](http://vagrantup.com/) to help with this. Please see
the [Vagrant
documentation](http://vagrantup.com/v1/docs/getting-started/index.html)
for instructions on how to install VirtualBox and Vagrant.
Once you have Vagrant installed, building should be as simple as
running:
$ export PHANTOMJS_VERSION=1.6.0 # change as necessary
$ vagrant up $ARCH
Where $ARCH is either `i686` or `x86_64`.
This runs the `provision_vm.sh` script, which installs the necessary
dependencies, checks out a fresh copy of the PhantomJS repository,
switches to the relevant tag, builds and packages the software and the
associated debugging symbols tarball, and copies the tarballs out of the
VM onto your host machine.
If it runs successfully, you will see the tarballs in this directory,
ready for upload.
If there are any problems, you can re-run the script with:
$ vagrant provision $ARCH
Or SSH into the VM:
$ vagrant ssh $ARCH
Once you're done, you can destroy the VM with:
$ vagrant destroy $ARCH
If you need to build a new version, you should destroy the VM and start
again to ensure a clean state. (Or SSH in and do a git clean.)
Packaging for OS X
------------------
Run `deploy/build-and-package.sh`. That's it.
However, if you have previously built the sources in release mode, you
should clean your tree to make sure all the debugging symbols gets
compiled:
$ make clean && cd src/qt && make clean && cd ../..

42
deploy/Vagrantfile vendored
View File

@ -1,42 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
unless ENV['PHANTOMJS_VERSION']
STDERR.puts 'Please specify PhantomJS version in the PHANTOMJS_VERSION environment variable.'
STDERR.puts '(This can be any git ref, e.g. "1.5.0", "master", "origin/1.5", etc.)'
exit 1
end
Vagrant::Config.run do |config|
config.vm.define :i686 do |c|
c.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-centos-5.8-i386.box"
c.vm.box = "centos_58_32bit"
c.vm.customize ["modifyvm", :id, "--ostype", "RedHat"]
end
config.vm.define :x86_64 do |c|
c.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes/opscode-centos-5.8.box"
c.vm.box = "centos_58_64bit"
c.vm.customize ["modifyvm", :id, "--ostype", "RedHat_64"]
end
config.vm.define :lucid32 do |c|
c.vm.box_url = "http://files.vagrantup.com/lucid32.box"
c.vm.box = "lucid32"
end
config.vm.define :lucid64 do |c|
c.vm.box_url = "http://files.vagrantup.com/lucid64.box"
c.vm.box = "lucid64"
end
config.vm.provision :shell do |s|
s.path = "provision-vm.sh"
s.args = ENV['PHANTOMJS_VERSION']
end
# You may wish to tweak these, but be aware that you need quite a lot of
# memory for the linking stage.
config.vm.customize ["modifyvm", :id, "--memory", 3072]
config.vm.customize ["modifyvm", :id, "--cpus", 2]
end

View File

@ -0,0 +1,16 @@
--- configure 2011-03-29 22:16:21.000000000 -0700
+++ configure.new 2011-08-21 22:11:16.000000000 -0700
@@ -7160,13 +7160,6 @@ if [ "$CFG_GUI" = "no" ]; then
canBuildWebKit="no"
fi
-if [ "$CFG_SHARED" = "no" ]; then
- echo
- echo "WARNING: Using static linking will disable the WebKit module."
- echo
- canBuildWebKit="no"
-fi
-
CFG_CONCURRENT="yes"
if [ "$canBuildQtConcurrent" = "no" ]; then
QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_CONCURRENT"

View File

@ -1,213 +0,0 @@
/*-
* Copyright (c) 2000, 2001 David O'Brien
* Copyright (c) 1996 Søren Schmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
*/
#include <sys/cdefs.h>
//NOTE: commented out to make it compile on linux
// __FBSDID("$FreeBSD: src/usr.bin/brandelf/brandelf.c,v 1.25.22.2 2012/03/16 03:22:37 eadler Exp $");
#include <sys/types.h>
//NOTE: changed path to make it compile on linux
#include <elf.h>
#include <sys/errno.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int elftype(const char *);
static const char *iselftype(int);
static void printelftypes(void);
static void usage(void);
struct ELFtypes {
const char *str;
int value;
};
/* XXX - any more types? */
static struct ELFtypes elftypes[] = {
{ "FreeBSD", ELFOSABI_FREEBSD },
{ "Linux", ELFOSABI_LINUX },
{ "Solaris", ELFOSABI_SOLARIS },
{ "SVR4", ELFOSABI_SYSV }
};
int
main(int argc, char **argv)
{
const char *strtype = "FreeBSD";
int type = ELFOSABI_FREEBSD;
int retval = 0;
int ch, change = 0, force = 0, listed = 0;
while ((ch = getopt(argc, argv, "f:lt:v")) != -1)
switch (ch) {
case 'f':
if (change)
errx(1, "f option incompatible with t option");
force = 1;
type = atoi(optarg);
if (errno == ERANGE || type < 0 || type > 255) {
warnx("invalid argument to option f: %s",
optarg);
usage();
}
break;
case 'l':
printelftypes();
listed = 1;
break;
case 'v':
/* does nothing */
break;
case 't':
if (force)
errx(1, "t option incompatible with f option");
change = 1;
strtype = optarg;
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (!argc) {
if (listed)
exit(0);
else {
warnx("no file(s) specified");
usage();
}
}
if (!force && (type = elftype(strtype)) == -1) {
warnx("invalid ELF type '%s'", strtype);
printelftypes();
usage();
}
while (argc) {
int fd;
char buffer[EI_NIDENT];
if ((fd = open(argv[0], change || force ? O_RDWR : O_RDONLY, 0)) < 0) {
warn("error opening file %s", argv[0]);
retval = 1;
goto fail;
}
if (read(fd, buffer, EI_NIDENT) < EI_NIDENT) {
warnx("file '%s' too short", argv[0]);
retval = 1;
goto fail;
}
if (buffer[0] != ELFMAG0 || buffer[1] != ELFMAG1 ||
buffer[2] != ELFMAG2 || buffer[3] != ELFMAG3) {
warnx("file '%s' is not ELF format", argv[0]);
retval = 1;
goto fail;
}
if (!change && !force) {
fprintf(stdout,
"File '%s' is of brand '%s' (%u).\n",
argv[0], iselftype(buffer[EI_OSABI]),
buffer[EI_OSABI]);
if (!iselftype(type)) {
warnx("ELF ABI Brand '%u' is unknown",
type);
printelftypes();
}
}
else {
buffer[EI_OSABI] = type;
lseek(fd, 0, SEEK_SET);
if (write(fd, buffer, EI_NIDENT) != EI_NIDENT) {
warn("error writing %s %d", argv[0], fd);
retval = 1;
goto fail;
}
}
fail:
close(fd);
argc--;
argv++;
}
return retval;
}
static void
usage(void)
{
(void)fprintf(stderr,
"usage: brandelf [-lv] [-f ELF_ABI_number] [-t string] file ...\n");
exit(1);
}
static const char *
iselftype(int etype)
{
size_t elfwalk;
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
if (etype == elftypes[elfwalk].value)
return elftypes[elfwalk].str;
return 0;
}
static int
elftype(const char *elfstrtype)
{
size_t elfwalk;
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0)
return elftypes[elfwalk].value;
return -1;
}
static void
printelftypes(void)
{
size_t elfwalk;
fprintf(stderr, "known ELF types are: ");
for (elfwalk = 0;
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
elfwalk++)
fprintf(stderr, "%s(%u) ", elftypes[elfwalk].str,
elftypes[elfwalk].value);
fprintf(stderr, "\n");
}

View File

@ -1,69 +0,0 @@
#!/usr/bin/env bash
cd `dirname $0`/..
echo "Building Qt and PhantomJS with debugging symbols. If you have previously" \
"built without debugging symbols, you should run:"
echo
echo " $ git clean -xdff"
echo
# This incantation will cause Qt and WebKit and PhantomJS to all build in "release"
# mode, with compiler optimisations, but also with debug symbols. (We will strip the
# symbols in package.sh.)
CFLAGS=-g CXXFLAGS=-g ./build.sh --confirm --qt-config '-webkit-debug' --qmake-args "QMAKE_CFLAGS=-g QMAKE_CXXFLAGS=-g" || exit 1
# Package the release tarball
rm deploy/*.tar.bz2 2>/dev/null
./deploy/package.sh || exit 1
# Build the dump_syms program for dumping breakpad debugging symbols
if [[ $OSTYPE = darwin* ]]; then
pushd tools
../src/qt/bin/qmake dump-syms-mac.pro && make
popd
else
pushd src/breakpad
./configure && make || exit 1
popd
fi
# Dump and package the breakpad debugging symbols...
./tools/dump-symbols.sh
version=$(bin/phantomjs --version | sed 's/ /-/' | sed 's/[()]//g')
if [[ $OSTYPE = darwin* ]]; then
symbols="phantomjs-$version-macosx-symbols"
else
symbols="phantomjs-$version-linux-$(uname -m)-symbols"
fi
cp -r symbols/ $symbols
# The minidump_stackwalk program is architecture-specific, so copy the
# binary for later use. This means that e.g. a developer on x86_64 can
# analyse a crash dump produced by a i686 user.
#
# We don't yet have a process for building minidump_stackwalk on OS X
if [[ $OSTYPE != darwin* ]]; then
cp src/breakpad/src/processor/minidump_stackwalk $symbols
read -r -d '' README <<EOT
These are symbols files that can be used to analyse a crash dump
produced by the corresponding binary. To generate a crash report,
run:
./minidump_stackwalk /path/to/crash.dmp .
EOT
echo "$README" > $symbols/README
fi
tar -cjf deploy/$symbols.tar.bz2 $symbols
rm -r $symbols
echo "PhantomJS built and packaged:"
echo
cd deploy
ls -1 *.tar.bz2

118
deploy/build-linux.sh Executable file
View File

@ -0,0 +1,118 @@
#!/bin/bash
QT_VERSION=0
QT_FOLDER=""
COMPILE_JOBS=4
if [ "$1" = "--qt-4.8" ]
then
echo "Building Qt 4.8"
QT_VERSION=4.8
QT_FOLDER=Qt-$QT_VERSION
QT_URL=git://gitorious.org/qt/qt.git
echo "Cloning Qt from gitorious into $QT_FOLDER..."
if [ ! -d $QT_FOLDER ]
then
git clone $QT_URL $QT_FOLDER
pushd $QT_FOLDER
git checkout -b 4.8 origin/4.8
else
pushd $QT_FOLDER
git checkout -f
git clean -xdf
git checkout 4.8
fi
popd
else
echo "Building Qt 4.7"
QT_VERSION=4.7.4
QT_FOLDER=Qt-$QT_VERSION
QT_TARBALL=qt-everywhere-opensource-src-$QT_VERSION.tar.gz
# Tip: change this to local/shared mirror
QT_URL=http://get.qt.nokia.com/qt/source/$QT_TARBALL
# Step 1: Download Qt source tarball
# Note: only if it does not exist yet in the current directory
if [ ! -f $QT_TARBALL ]
then
echo "Downloading Qt $QT_VERSION from Nokia. Please wait..."
if ! curl -C - -O -S $QT_URL
then
echo
echo "Fatal error: fail to download from $QT_URL !"
exit 1
fi
fi
# Step 2: Extract Qt source
[ -d $QT_FOLDER ] && rm -rf $QT_FOLDER
echo "Extracting Qt $QT_VERSION source tarball..."
echo
tar xzf $QT_TARBALL
mv qt-everywhere-opensource-src-$QT_VERSION Qt-$QT_VERSION
fi
# Step 3: Build Qt
pushd $QT_FOLDER
EXTRA_FLAGS=""
if [ $QT_VERSION = 4.8 ] ; then
echo "Patching Qt 4.8"
patch -p1 < ../qt48_enable_debugger.patch
patch -p1 < ../qt48_fix_inspector.patch
patch -p1 < ../qt48_headless_and_pdf_fixes.patch
# Build in lighthose mode for an x-less build
if [ "$2" = "--headless" ] ; then
echo "Building 4.8 in qpa headless mode"
EXTRA_FLAGS="-qpa"
fi
else
echo "Patching Qt 4.7"
patch configure ../allow-static-qtwebkit.patch
# Qt 4.8 doesn't allow static builds of QtWebkit-2.2
EXTRA_FLAGS="-static"
fi
patch -p1 < ../qapplication_skip_qtmenu.patch
echo "Building Qt $QT_VERSION. Please wait..."
echo
./configure -opensource -confirm-license -release -webkit -graphicssystem raster -no-exceptions -no-dbus -no-glib -no-gstreamer -no-stl -no-xmlpatterns -no-phonon -no-multimedia -no-qt3support -no-opengl -no-openvg -no-svg -no-declarative -no-gtkstyle -no-xkb -no-xinput -no-xinerama -no-sm -no-cups -qt-libpng -qt-libjpeg -no-libmng -no-libtiff -D QT_NO_STYLE_CDE -D QT_NO_STYLE_CLEANLOOKS -D QT_NO_STYLE_MOTIF -D QT_NO_STYLE_PLASTIQUE -prefix $PWD -nomake demos -nomake examples -nomake tools -nomake docs -nomake translations $EXTRA_FLAGS
make -j$COMPILE_JOBS
popd
if [ $QT_VERSION != 4.8 ] ; then
# Extra step: copy JavaScriptCore/release, needed for jscore static lib
mkdir ../JavaScriptCore
cp -rp $QT_FOLDER/src/3rdparty/webkit/JavaScriptCore/release ../JavaScriptCore/
fi
# Step 4: Build PhantomJS
echo "Building PhantomJS. Please wait..."
echo
cd ..
[ -f Makefile ] && make distclean
deploy/$QT_FOLDER/bin/qmake
make -j$COMPILE_JOBS
# Step 5: Prepare for deployment
echo "Compressing PhantomJS executable..."
echo
strip bin/phantomjs
if [ `command -v upx` ]; then
upx -9 bin/phantomjs
else
echo "You don't have UPX. Consider installing it to reduce the executable size."
fi

133
deploy/build-mac.sh Executable file
View File

@ -0,0 +1,133 @@
#!/bin/bash
QT_VERSION=4.8.0
QT_FOLDER=Qt-$QT_VERSION
QT_TARBALL=qt-everywhere-opensource-src-$QT_VERSION.tar.gz
# Tip: change this to local/shared mirror
QT_URL=http://get.qt.nokia.com/qt/source/$QT_TARBALL
COMPILE_JOBS=4
# Step 1: Download Qt source tarball
# Note: only if it does not exist yet in the current directory
if [ ! -f $QT_TARBALL ]
then
echo "Downloading Qt $QT_VERSION from Nokia. Please wait..."
if ! curl -C - -O -S $QT_URL
then
echo
echo "Fatal error: fail to download from $QT_URL !"
exit 1
fi
fi
# Step 2: Extract Qt source
[ -d $QT_FOLDER ] && rm -rf $QT_FOLDER
echo "Extracting Qt $QT_VERSION source tarball..."
echo
tar xzf $QT_TARBALL
mv qt-everywhere-opensource-src-$QT_VERSION Qt-$QT_VERSION
# Step 3: Apply some patches
cd $QT_FOLDER
patch configure ../allow-static-qtwebkit.patch
patch -p1 < ../qapplication_skip_qtmenu.patch
rm -rf src/3rdparty/webkit/Source/WebKit/qt/tests
# Step 4: Build Qt
echo "Building Qt $QT_VERSION. Please wait..."
echo
CFG=''
CFG+=' -opensource' # Use the open-source license
CFG+=' -confirm-license' # Silently acknowledge the license confirmation
CFG+=' -release' # Build only for release (no debugging support)
CFG+=' -static' # Compile for static libraries
CFG+=' -fast' # Accelerate Makefiles generation
CFG+=' -nomake demos' # Don't build with the demos
CFG+=' -nomake docs' # Don't generate the documentatio
CFG+=' -nomake examples' # Don't build any examples
CFG+=' -nomake translations' # Ignore the translations
CFG+=' -nomake tools' # Don't built the tools
CFG+=' -no-exceptions' # Don't use C++ exception
CFG+=' -no-stl' # No need for STL compatibility
# Irrelevant Qt features
CFG+=' -no-libmng'
CFG+=' -no-libtiff'
# Unnecessary Qt modules
CFG+=' -no-declarative'
CFG+=' -no-multimedia'
CFG+=' -no-opengl'
CFG+=' -no-openvg'
CFG+=' -no-phonon'
CFG+=' -no-qt3support'
CFG+=' -no-script'
CFG+=' -no-scripttools'
CFG+=' -no-svg'
CFG+=' -no-xmlpatterns'
# Sets the default graphics system to the raster engine
CFG+=' -graphicssystem raster'
# Mac
CFG+=' -cocoa' # Cocoa only, ignore Carbon
CFG+=' -no-cups' # Disable CUPS support
CFG+=' -no-dwarf2'
# Unix
CFG+=' -no-dbus' # Disable D-Bus feature
CFG+=' -no-glib' # No need for Glib integration
CFG+=' -no-gstreamer' # Turn off GStreamer support
CFG+=' -no-gtkstyle' # Disable theming integration with Gtk+
CFG+=' -no-sm'
CFG+=' -no-xinerama'
CFG+=' -no-xkb'
# Use the bundled libraries, vs system-installed
CFG+=' -qt-libjpeg'
CFG+=' -qt-libpng'
# Useless styles
CFG+=' -D QT_NO_STYLESHEET'
CFG+=' -D QT_NO_STYLE_CDE'
CFG+=' -D QT_NO_STYLE_CLEANLOOKS'
CFG+=' -D QT_NO_STYLE_MOTIF'
./configure -prefix $PWD $CFG -arch x86
make -j$COMPILE_JOBS
cd ..
# Extra step to ensure the static libraries are found
cp -rp $QT_FOLDER/src/3rdparty/webkit/Source/JavaScriptCore/release/* $QT_FOLDER/lib
cp -rp $QT_FOLDER/src/3rdparty/webkit/Source/WebCore/release/* $QT_FOLDER/lib
# Step 5: Build PhantomJS
echo "Building PhantomJS. Please wait..."
echo
cd ..
[ -f Makefile ] && make distclean
deploy/$QT_FOLDER/bin/qmake
make -j$COMPILE_JOBS
# Step 6: Prepare for deployment
echo "Compressing PhantomJS executable..."
echo
strip bin/phantomjs
if [ `command -v upx` ]; then
upx -9 bin/phantomjs
else
echo "You don't have UPX. Consider installing it to reduce the executable size."
fi

View File

@ -1,120 +0,0 @@
#!/usr/bin/env bash
#
# usage: just run this script (after having run build.sh)
# and deploy the created tarball to your target machine.
#
# It creates a phantomjs-$version folder and copies the binary,
# example, license etc. together with all shared library dependencies
# to that folder. Furthermore brandelf is used to make the lib
# and binary compatible with older unix/linux machines that don't
# know the new Linux ELF ABI.
#
cd $(dirname $0)
if [[ ! -f ../bin/phantomjs ]]; then
echo "phantomjs was not built yet, please run build.sh first"
exit 1
fi
if [[ "$1" = "--bundle-libs" ]]; then
bundle_libs=1
else
bundle_libs=0
fi
version=$(../bin/phantomjs --version | sed 's/ /-/' | sed 's/[()]//g')
src=..
echo "packaging phantomjs $version"
if [[ $OSTYPE = darwin* ]]; then
dest="phantomjs-$version-macosx"
else
dest="phantomjs-$version-linux-$(uname -m)"
fi
rm -Rf $dest{.tar.bz2,} &> /dev/null
mkdir -p $dest/bin
echo
echo -n "copying files..."
cp $src/bin/phantomjs $dest/bin
cp -r $src/{ChangeLog,examples,LICENSE.BSD,third-party.txt,README.md} $dest/
echo "done"
echo
phantomjs=$dest/bin/phantomjs
if [[ "$bundle_libs" = "1" ]]; then
mkdir -p $dest/lib
if [[ ! -f brandelf ]]; then
echo
echo "brandelf executable not found in current dir"
echo -n "compiling it now..."
g++ brandelf.c -o brandelf || exit 1
echo "done"
fi
libs=$(ldd $phantomjs | egrep -o "/[^ ]+ ")
echo -n "copying shared libs..."
libld=
for l in $libs; do
ll=$(basename $l)
cp $l $dest/lib/$ll
if [[ "$bundle_libs" = "1" ]]; then
# ensure OS ABI compatibility
./brandelf -t SVR4 $dest/lib/$ll
if [[ "$l" == *"ld-linux"* ]]; then
libld=$ll
fi
fi
done
echo "done"
echo
echo -n "writing run script..."
mv $phantomjs $phantomjs.bin
phantomjs=$phantomjs.bin
run=$dest/bin/phantomjs
echo '#!/bin/sh' >> $run
echo 'path=$(dirname $(dirname $(readlink -f $0)))' >> $run
echo 'export LD_LIBRARY_PATH=$path/lib' >> $run
echo 'exec $path/lib/'$libld' $phantomjs $@' >> $run
chmod +x $run
echo "done"
echo
fi
echo -n "stripping binary and libs..."
if [[ $OSTYPE = darwin* ]]; then
strip -x $phantomjs
else
strip -s $phantomjs
[[ -d $dest/lib ]] && strip -s $dest/lib/*
fi
echo "done"
echo
echo -n "compressing binary..."
if type upx >/dev/null 2>&1; then
upx -qqq -9 $phantomjs
echo "done"
else
echo "upx not found"
fi
echo
echo -n "creating archive..."
if [[ $OSTYPE = darwin* ]]; then
zip -r $dest.zip $dest
else
tar -cjf $dest{.tar.bz2,}
fi
echo "done"
echo

View File

@ -1,42 +0,0 @@
#!/usr/bin/env bash
export PATH=$HOME/git/bin:$PATH
if type apt-get >/dev/null 2>&1; then
apt-get update
apt-get install -y build-essential git-core libssl-dev libfontconfig1-dev gdb binutils-gold
fi
if type yum >/dev/null 2>&1; then
yum -y update
yum -y install gcc gcc-c++ make openssl-devel freetype-devel fontconfig-devel
if type git >/dev/null 2>&1; then
echo "Git is already available."
else
yum -y install cpio expat-devel gettext-devel zlib-devel
echo "Downloading and building git..."
rm -rf git-*
wget -nv https://git-core.googlecode.com/files/git-1.8.0.3.tar.gz
tar -xzvf git-1.8.0.3.tar.gz
cd git-1.8.0.3
./configure --prefix=$HOME/git && make -j2 && make install
cd ..
sleep 3
fi
fi
if [[ ! -d phantomjs ]]; then
git clone git://github.com/ariya/phantomjs.git
fi
cd phantomjs
git fetch origin
git reset --hard
git checkout $1
cp /vagrant/build-and-package.sh deploy/
cp /vagrant/package.sh deploy/
deploy/build-and-package.sh
cp deploy/*.tar.bz2 /vagrant

View File

@ -0,0 +1,19 @@
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index ed9e9ce..ca35249 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1253,11 +1253,14 @@ void qt_init(QApplicationPrivate *priv, int)
[newDelegate setReflectionDelegate:oldDelegate];
[cocoaApp setDelegate:newDelegate];
+// https://bugreports.qt.nokia.com/browse/QTBUG-5952
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init];
if ([NSBundle loadNibNamed:@"qt_menu" owner:qtMenuLoader] == false) {
+#if 0
qFatal("Qt internal error: qt_menu.nib could not be loaded. The .nib file"
" should be placed in QtGui.framework/Versions/Current/Resources/ "
" or in the resources directory of your application bundle.");
+#endif
}
[cocoaApp setMenu:[qtMenuLoader menu]];

View File

@ -0,0 +1,35 @@
diff --git a/src/3rdparty/webkit/Source/WebCore/inspector/front-end/Settings.js b/src/3rdparty/webkit/Source/WebCore/inspector/front-end/Settings.js
index 62bf84a..e830f85 100644
--- a/src/3rdparty/webkit/Source/WebCore/inspector/front-end/Settings.js
+++ b/src/3rdparty/webkit/Source/WebCore/inspector/front-end/Settings.js
@@ -40,7 +40,7 @@ var Preferences = {
showMissingLocalizedStrings: false,
samplingCPUProfiler: false,
showColorNicknames: true,
- debuggerAlwaysEnabled: false,
+ debuggerAlwaysEnabled: true,
profilerAlwaysEnabled: false,
onlineDetectionEnabled: true,
nativeInstrumentationEnabled: false,
@@ -58,7 +58,7 @@ WebInspector.Settings = function()
{
this.installApplicationSetting("colorFormat", "hex");
this.installApplicationSetting("consoleHistory", []);
- this.installApplicationSetting("debuggerEnabled", false);
+ this.installApplicationSetting("debuggerEnabled", true);
this.installApplicationSetting("domWordWrap", true);
this.installApplicationSetting("profilerEnabled", false);
this.installApplicationSetting("eventListenersFilter", "all");
diff --git a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebinspector.cpp b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebinspector.cpp
index 6706f2a..bec3d1c 100644
--- a/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebinspector.cpp
+++ b/src/3rdparty/webkit/Source/WebKit/qt/Api/qwebinspector.cpp
@@ -161,7 +161,7 @@ void QWebInspector::showEvent(QShowEvent* event)
#if ENABLE(INSPECTOR)
// Allows QWebInspector::show() to init the inspector.
if (d->page)
- d->page->d->inspectorController()->show();
+ d->page->d->inspectorController()->showAndEnableDebugger();
#endif
}

View File

@ -0,0 +1,268 @@
diff --git a/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.cpp b/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.cpp
index 92b7d5c..c5e5bd5 100644
--- a/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.cpp
+++ b/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.cpp
@@ -22,7 +22,8 @@
#include "InspectorClientQt.h"
#include "InspectorController.h"
-#include "MD5.h"
+#include "Base64.h"
+#include "SHA1.h"
#include "Page.h"
#include "qwebpage.h"
#include "qwebpage_p.h"
@@ -44,43 +45,17 @@ namespace WebCore {
/*!
Computes the WebSocket handshake response given the two challenge numbers and key3.
*/
-static void generateWebSocketChallengeResponse(uint32_t number1, uint32_t number2, const unsigned char key3[8], unsigned char response[16])
+static QByteArray generateWebSocketChallengeResponse(const QByteArray& key)
{
- uint8_t challenge[16];
- qToBigEndian<qint32>(number1, &challenge[0]);
- qToBigEndian<qint32>(number2, &challenge[4]);
- memcpy(&challenge[8], key3, 8);
- MD5 md5;
- md5.addBytes(challenge, sizeof(challenge));
- Vector<uint8_t, 16> digest;
- md5.checksum(digest);
- memcpy(response, digest.data(), 16);
-}
-
-/*!
- Parses and returns a WebSocket challenge number according to the
- method specified in the WebSocket protocol.
-
- The field contains numeric digits interspersed with spaces and
- non-numeric digits. The protocol ignores the characters that are
- neither digits nor spaces. The digits are concatenated and
- interpreted as a long int. The result is this number divided by
- the number of spaces.
- */
-static quint32 parseWebSocketChallengeNumber(QString field)
-{
- QString nString;
- int numSpaces = 0;
- for (int i = 0; i < field.size(); i++) {
- QChar c = field[i];
- if (c == QLatin1Char(' '))
- numSpaces++;
- else if ((c >= QLatin1Char('0')) && (c <= QLatin1Char('9')))
- nString.append(c);
- }
- quint32 num = nString.toLong();
- quint32 result = (numSpaces ? (num / numSpaces) : num);
- return result;
+ SHA1 sha1;
+ Vector<uint8_t, 20> digest;
+ Vector<char> encoded;
+ QByteArray toHash("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+ toHash.prepend(key);
+ sha1.addBytes((uint8_t*)toHash.data(), toHash.size());
+ sha1.computeHash(digest);
+ base64Encode((char*)digest.data(), digest.size(), encoded);
+ return QByteArray(encoded.data(), encoded.size());
}
static InspectorServerQt* s_inspectorServer;
@@ -194,7 +169,7 @@ void InspectorServerRequestHandlerQt::tcpReadyRead()
m_path = header.path();
m_contentType = header.contentType().toLatin1();
m_contentLength = header.contentLength();
- if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String("WebSocket")))
+ if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String("websocket")))
isWebSocket = true;
m_data.clear();
@@ -211,25 +186,19 @@ void InspectorServerRequestHandlerQt::tcpReadyRead()
// switch to websocket-style WebSocketService messaging
if (m_tcpConnection) {
m_tcpConnection->disconnect(SIGNAL(readyRead()));
- connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(webSocketReadyRead()));
-
- QByteArray key3 = m_tcpConnection->read(8);
-
- quint32 number1 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key1")));
- quint32 number2 = parseWebSocketChallengeNumber(header.value(QLatin1String("Sec-WebSocket-Key2")));
-
- char responseData[16];
- generateWebSocketChallengeResponse(number1, number2, (unsigned char*)key3.data(), (unsigned char*)responseData);
- QByteArray response(responseData, sizeof(responseData));
+ connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(webSocketReadyRead()), Qt::QueuedConnection);
+
+ QByteArray key = header.value(QLatin1String("Sec-WebSocket-Key")).toLatin1();
+ QString accept = QString::fromLatin1(generateWebSocketChallengeResponse(key));
QHttpResponseHeader responseHeader(101, QLatin1String("WebSocket Protocol Handshake"), 1, 1);
responseHeader.setValue(QLatin1String("Upgrade"), header.value(QLatin1String("Upgrade")));
responseHeader.setValue(QLatin1String("Connection"), header.value(QLatin1String("Connection")));
- responseHeader.setValue(QLatin1String("Sec-WebSocket-Origin"), header.value(QLatin1String("Origin")));
- responseHeader.setValue(QLatin1String("Sec-WebSocket-Location"), (QLatin1String("ws://") + header.value(QLatin1String("Host")) + m_path));
- responseHeader.setContentLength(response.size());
+ responseHeader.setValue(QLatin1String("Sec-WebSocket-Accept"), accept);
+ // responseHeader.setValue(QLatin1String("Sec-WebSocket-Origin"), header.value(QLatin1String("Sec-WebSocket-Origin")));
+ // responseHeader.setValue(QLatin1String("Sec-WebSocket-Location"), (QLatin1String("ws://") + header.value(QLatin1String("Host")) + m_path));
m_tcpConnection->write(responseHeader.toString().toLatin1());
- m_tcpConnection->write(response);
+ //m_tcpConnection->write(response);
m_tcpConnection->flush();
if ((words.size() == 4)
@@ -308,26 +277,54 @@ void InspectorServerRequestHandlerQt::tcpConnectionDisconnected()
m_tcpConnection = 0;
}
-int InspectorServerRequestHandlerQt::webSocketSend(QByteArray payload)
+int InspectorServerRequestHandlerQt::webSocketSend(const QString& message)
{
- Q_ASSERT(m_tcpConnection);
- m_tcpConnection->putChar(0x00);
- int nBytes = m_tcpConnection->write(payload);
- m_tcpConnection->putChar(0xFF);
- m_tcpConnection->flush();
- return nBytes;
+ QByteArray payload = message.toUtf8();
+ return webSocketSend(payload.data(), payload.size());
}
int InspectorServerRequestHandlerQt::webSocketSend(const char* data, size_t length)
{
Q_ASSERT(m_tcpConnection);
- m_tcpConnection->putChar(0x00);
+ m_tcpConnection->putChar(0x81);
+ if (length <= 125)
+ m_tcpConnection->putChar(static_cast<uint8_t>(length));
+ else if (length <= pow(2,16)) {
+ m_tcpConnection->putChar(126);
+ quint16 length16 = qToBigEndian<quint16>(static_cast<quint16>(length));
+ m_tcpConnection->write(reinterpret_cast<char*>(&length16), 2);
+ } else {
+ m_tcpConnection->putChar(127);
+ quint64 length64 = qToBigEndian<quint64>(static_cast<quint64>(length));
+ m_tcpConnection->write(reinterpret_cast<char*>(&length64), 8);
+ }
int nBytes = m_tcpConnection->write(data, length);
- m_tcpConnection->putChar(0xFF);
m_tcpConnection->flush();
return nBytes;
}
+static QByteArray applyMask(const QByteArray& payload, const QByteArray& maskingKey)
+{
+ Q_ASSERT(maskingKey.size() == 4);
+ QByteArray unmaskedPayload;
+ for (int i = 0; i < payload.size(); ++i) {
+ char unmaskedByte = payload[i] ^ maskingKey[i % 4];
+ unmaskedPayload.append(unmaskedByte);
+ }
+ return unmaskedPayload;
+}
+
+#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
+#define BYTETOBINARY(byte) \
+ (byte & 0x80 ? 1 : 0), \
+ (byte & 0x40 ? 1 : 0), \
+ (byte & 0x20 ? 1 : 0), \
+ (byte & 0x10 ? 1 : 0), \
+ (byte & 0x08 ? 1 : 0), \
+ (byte & 0x04 ? 1 : 0), \
+ (byte & 0x02 ? 1 : 0), \
+ (byte & 0x01 ? 1 : 0)
+
void InspectorServerRequestHandlerQt::webSocketReadyRead()
{
Q_ASSERT(m_tcpConnection);
@@ -336,38 +333,49 @@ void InspectorServerRequestHandlerQt::webSocketReadyRead()
QByteArray content = m_tcpConnection->read(m_tcpConnection->bytesAvailable());
m_data.append(content);
while (m_data.size() > 0) {
- // first byte in websocket frame should be 0
- Q_ASSERT(!m_data[0]);
+ bool isMasked = m_data[1] & 0x80;
+ quint64 payloadLen = m_data[1] & 0x7F;
+ int pos = 2;
- // Start of WebSocket frame is indicated by 0
- if (m_data[0]) {
- qCritical() << "webSocketReadyRead: unknown frame type" << m_data[0];
- m_data.clear();
- m_tcpConnection->close();
- return;
+ if (payloadLen == 126) {
+ payloadLen = qFromBigEndian<quint16>(*reinterpret_cast<quint16*>(m_data.mid(pos, 2).data()));
+ pos = 4;
+ } else if (payloadLen == 127) {
+ payloadLen = qFromBigEndian<quint64>(*reinterpret_cast<quint64*>(m_data.mid(pos, 8).data()));
+ pos = 8;
}
- // End of WebSocket frame indicated by 0xff.
- int pos = m_data.indexOf(0xff, 1);
- if (pos < 1)
- return;
-
- // After above checks, length will be >= 0.
- size_t length = pos - 1;
- if (length <= 0)
- return;
-
- QByteArray payload = m_data.mid(1, length);
+ QByteArray payload;
+ if (isMasked) {
+ QByteArray maskingKey = m_data.mid(pos, 4);
+ pos += 4;
+ payload = applyMask(m_data.mid(pos, payloadLen), maskingKey);
+ } else {
+ payload = m_data.mid(pos, payloadLen);
+ }
+ // Handle fragmentation
+ if ((m_data[0] & 0x80) == 0) { // Non-last fragmented payload
+ m_fragmentedPayload.append(payload);
+
+ m_data = m_data.mid(pos + payloadLen);
+ continue;
+ } else {
+ if ((m_data[0] & 0x0F) == 0) { // Last fragment
+ m_fragmentedPayload.append(payload);
+ payload = m_fragmentedPayload;
+ m_fragmentedPayload.clear();
+ }
+ }
+
+ // Remove this WebSocket message from m_data (payload, start-of-frame byte, end-of-frame byte).
+ m_data = m_data.mid(pos + payloadLen);
#if ENABLE(INSPECTOR)
if (m_inspectorClient) {
InspectorController* inspectorController = m_inspectorClient->m_inspectedWebPage->d->page->inspectorController();
inspectorController->dispatchMessageFromFrontend(QString::fromUtf8(payload));
}
#endif
-
- // Remove this WebSocket message from m_data (payload, start-of-frame byte, end-of-frame byte).
- m_data = m_data.mid(length + 2);
}
}
diff --git a/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.h b/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.h
index 922b63e..e1265b9 100644
--- a/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.h
+++ b/src/3rdparty/webkit/Source/WebKit/qt/WebCoreSupport/InspectorServerQt.h
@@ -83,7 +83,7 @@ public:
InspectorServerRequestHandlerQt(QTcpSocket *tcpConnection, InspectorServerQt *server);
virtual ~InspectorServerRequestHandlerQt();
- virtual int webSocketSend(QByteArray payload);
+ virtual int webSocketSend(const QString& message);
virtual int webSocketSend(const char *payload, size_t length);
private slots:
@@ -100,6 +100,7 @@ private:
int m_contentLength;
bool m_endOfHeaders;
QByteArray m_data;
+ QByteArray m_fragmentedPayload;
InspectorClientQt* m_inspectorClient;
void handleInspectorRequest(QStringList words);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
if phantom.args.length is 0
console.log 'Try to pass some args when invoking this script!'
else
for arg, i in phantom.args
console.log i + ': ' + arg
phantom.exit()

View File

@ -1,8 +1,7 @@
var system = require('system'); if (phantom.args.length === 0) {
if (system.args.length === 1) {
console.log('Try to pass some args when invoking this script!'); console.log('Try to pass some args when invoking this script!');
} else { } else {
system.args.forEach(function (arg, i) { phantom.args.forEach(function (arg, i) {
console.log(i + ': ' + arg); console.log(i + ': ' + arg);
}); });
} }

View File

@ -1,27 +0,0 @@
var spawn = require("child_process").spawn
var execFile = require("child_process").execFile
var child = spawn("ls", ["-lF", "/rooot"])
child.stdout.on("data", function (data) {
console.log("spawnSTDOUT:", JSON.stringify(data))
})
child.stderr.on("data", function (data) {
console.log("spawnSTDERR:", JSON.stringify(data))
})
child.on("exit", function (code) {
console.log("spawnEXIT:", code)
})
//child.kill("SIGKILL")
execFile("ls", ["-lF", "/usr"], null, function (err, stdout, stderr) {
console.log("execFileSTDOUT:", JSON.stringify(stdout))
console.log("execFileSTDERR:", JSON.stringify(stderr))
})
setTimeout(function () {
phantom.exit(0)
}, 2000)

View File

@ -0,0 +1,46 @@
page = require('webpage').create()
page.viewportSize = { width: 400, height : 400 }
page.content = '<html><body><canvas id="surface"></canvas></body></html>'
page.evaluate ->
el = document.getElementById 'surface'
context = el.getContext '2d'
width = window.innerWidth
height = window.innerHeight
cx = width / 2
cy = height / 2
radius = width / 2.3
i = 0
el.width = width
el.height = height
imageData = context.createImageData(width, height)
pixels = imageData.data
for y in [0...height]
for x in [0...width]
i = i + 4
rx = x - cx
ry = y - cy
d = rx * rx + ry * ry
if d < radius * radius
hue = 6 * (Math.atan2(ry, rx) + Math.PI) / (2 * Math.PI)
sat = Math.sqrt(d) / radius
g = Math.floor(hue)
f = hue - g
u = 255 * (1 - sat)
v = 255 * (1 - sat * f)
w = 255 * (1 - sat * (1 - f))
pixels[i] = [255, v, u, u, w, 255, 255][g]
pixels[i + 1] = [w, 255, 255, v, u, u, w][g]
pixels[i + 2] = [u, u, w, 255, 255, v, u][g]
pixels[i + 3] = 255
context.putImageData imageData, 0, 0
document.body.style.backgroundColor = 'white'
document.body.style.margin = '0px'
page.render('colorwheel.png')
phantom.exit()

View File

@ -0,0 +1,8 @@
t = 10
interval = setInterval ->
if t > 0
console.log t--
else
console.log 'BLAST OFF!'
phantom.exit()
, 1000

View File

@ -0,0 +1,40 @@
page = require('webpage').create()
page.onInitialized = ->
page.evaluate ->
userAgent = window.navigator.userAgent
platform = window.navigator.platform
window.navigator =
appCodeName: 'Mozilla'
appName: 'Netscape'
cookieEnabled: false
sniffed: false
window.navigator.__defineGetter__ 'userAgent', ->
window.navigator.sniffed = true
userAgent
window.navigator.__defineGetter__ 'platform', ->
window.navigator.sniffed = true
platform
if phantom.args.length is 0
console.log 'Usage: unsniff.js <some URL>'
phantom.exit()
else
address = phantom.args[0]
console.log 'Checking ' + address + '...'
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
else
window.setTimeout ->
sniffed = page.evaluate(->
navigator.sniffed
)
if sniffed
console.log 'The page tried to sniff the user agent.'
else
console.log 'The page did not try to sniff the user agent.'
phantom.exit()
, 1500

View File

@ -1,7 +1,6 @@
// Detect if a web page sniffs the user agent or not. // Detect if a web page sniffs the user agent or not.
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'),
sniffed, sniffed,
address; address;
@ -32,16 +31,15 @@ page.onInitialized = function () {
}); });
}; };
if (system.args.length === 1) { if (phantom.args.length === 0) {
console.log('Usage: detectsniff.js <some URL>'); console.log('Usage: unsniff.js <some URL>');
phantom.exit(1); phantom.exit();
} else { } else {
address = system.args[1]; address = phantom.args[0];
console.log('Checking ' + address + '...'); console.log('Checking ' + address + '...');
page.open(address, function (status) { page.open(address, function (status) {
if (status !== 'success') { if (status !== 'success') {
console.log('FAIL to load the address'); console.log('FAIL to load the address');
phantom.exit();
} else { } else {
window.setTimeout(function () { window.setTimeout(function () {
sniffed = page.evaluate(function () { sniffed = page.evaluate(function () {

29
examples/direction.coffee Normal file
View File

@ -0,0 +1,29 @@
# Get driving direction using Google Directions API.
page = require('webpage').create()
if phantom.args.length < 2
console.log 'Usage: direction.js origin destination'
console.log 'Example: direction.js "San Diego" "Palo Alto"'
phantom.exit(1)
else
origin = phantom.args[0]
dest = phantom.args[1]
page.open encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin +
'&destination=' + dest + '&units=imperial&mode=driving&sensor=false'),
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
steps = page.content.match(/<html_instructions>(.*)<\/html_instructions>/ig)
if not steps
console.log 'No data available for ' + origin + ' to ' + dest
else
for ins in steps
ins = ins.replace(/\&lt;/ig, '<').replace(/\&gt;/ig, '>')
ins = ins.replace(/\<div/ig, '\n<div')
ins = ins.replace(/<.*?>/g, '')
console.log(ins)
console.log ''
console.log page.content.match(/<copyrights>.*<\/copyrights>/ig).join('').replace(/<.*?>/g, '')
phantom.exit()

View File

@ -1,16 +1,15 @@
// Get driving direction using Google Directions API. // Get driving direction using Google Directions API.
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'),
origin, dest, steps; origin, dest, steps;
if (system.args.length < 3) { if (phantom.args.length < 2) {
console.log('Usage: direction.js origin destination'); console.log('Usage: direction.js origin destination');
console.log('Example: direction.js "San Diego" "Palo Alto"'); console.log('Example: direction.js "San Diego" "Palo Alto"');
phantom.exit(1); phantom.exit(1);
} else { } else {
origin = system.args[1]; origin = phantom.args[0];
dest = system.args[2]; dest = phantom.args[1];
page.open(encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin + page.open(encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin +
'&destination=' + dest + '&units=imperial&mode=driving&sensor=false'), function (status) { '&destination=' + dest + '&units=imperial&mode=driving&sensor=false'), function (status) {
if (status !== 'success') { if (status !== 'success') {

View File

@ -0,0 +1,19 @@
# echoToFile.coffee - Write in a given file all the parameters passed on the CLI
fs = require 'fs'
if phantom.args.length < 2
console.log "Usage: echoToFile.js DESTINATION_FILE <arguments to echo...>"
phantom.exit()
else
content = ""
f = null
i = 1
while i < phantom.args.length
content += phantom.args[i] + (if i == phantom.args.length - 1 then "" else " ")
++i
try
f = fs.open(phantom.args[0], "w")
f.writeLine content
catch e
console.log e
phantom.exit()

View File

@ -1,21 +1,20 @@
// echoToFile.js - Write in a given file all the parameters passed on the CLI // echoToFile.js - Write in a given file all the parameters passed on the CLI
var fs = require('fs'), var fs = require('fs');
system = require('system');
if (system.args.length < 3) { if (phantom.args.length < 2) {
console.log("Usage: echoToFile.js DESTINATION_FILE <arguments to echo...>"); console.log("Usage: echoToFile.js DESTINATION_FILE <arguments to echo...>");
phantom.exit(1); phantom.exit();
} else { } else {
var content = '', var content = '',
f = null, f = null;
i; for ( i= 1; i < phantom.args.length; ++i ) {
for ( i= 2; i < system.args.length; ++i ) { content += phantom.args[i] + (i === phantom.args.length-1 ? '' : ' ');
content += system.args[i] + (i === system.args.length-1 ? '' : ' ');
} }
try { try {
fs.write(system.args[1], content, 'w'); f = fs.open(phantom.args[0], "w");
} catch(e) { f.writeLine(content);
} catch (e) {
console.log(e); console.log(e);
} }

8
examples/fibo.coffee Normal file
View File

@ -0,0 +1,8 @@
fibs = [0, 1]
f = ->
console.log fibs[fibs.length - 1]
fibs.push fibs[fibs.length - 1] + fibs[fibs.length - 2]
if fibs.length > 10
window.clearInterval ticker
phantom.exit()
ticker = window.setInterval(f, 300)

54
examples/follow.coffee Normal file
View File

@ -0,0 +1,54 @@
# List following and followers from several accounts
users= [
'sencha'
'aconran'
'adityabansod'
'ambisinister'
'arnebech'
'ariyahidayat'
'arthurakay'
'bmoeskau'
'darrellmeyer'
'davidfoelber'
'DavidKaneda'
'donovanerba'
'edspencer'
'evantrimboli'
'ExtAnimal'
'jamieavins'
'jarrednicholls'
'jayrobinson'
'lojjic'
'luckymethod'
'merrells'
'mmullany'
'philogb'
'philstrong'
'rdougan'
'SubtleGradient'
'__ted__'
'tmaintz'
'WesleyMoy'
'whereisthysting'
]
follow = (user, callback) ->
page = require('webpage').create()
page.open 'http://mobile.twitter.com/' + user, (status) ->
if status is 'fail'
console.log user + ': ?'
else
data = page.evaluate -> document.querySelector('div.timeline-following').innerText
console.log user + ': ' + data
callback.apply()
process = () ->
if (users.length > 0)
user = users[0]
users.splice(0, 1)
follow(user, process)
else
phantom.exit()
process()

View File

@ -1,13 +1,35 @@
// List following and followers from several accounts // List following and followers from several accounts
var users = ['PhantomJS', var users = ['sencha',
'aconran',
'adityabansod',
'ambisinister',
'arnebech',
'ariyahidayat', 'ariyahidayat',
'detronizator', 'arthurakay',
'KDABQt', 'bmoeskau',
'lfranchi', 'darrellmeyer',
'jonleighton', 'davidfoelber',
'_jamesmgreene', 'DavidKaneda',
'Vitalliumm']; 'donovanerba',
'edspencer',
'evantrimboli',
'ExtAnimal',
'jamieavins',
'jarrednicholls',
'jayrobinson',
'lojjic',
'luckymethod',
'merrells',
'mmullany',
'philogb',
'philstrong',
'rdougan',
'SubtleGradient',
'__ted__',
'tmaintz',
'WesleyMoy',
'whereisthysting'];
function follow(user, callback) { function follow(user, callback) {
var page = require('webpage').create(); var page = require('webpage').create();
@ -16,11 +38,10 @@ function follow(user, callback) {
console.log(user + ': ?'); console.log(user + ': ?');
} else { } else {
var data = page.evaluate(function () { var data = page.evaluate(function () {
return document.querySelector('div.profile td.stat.stat-last div.statnum').innerText; return document.querySelector('div.timeline-following').innerText;
}); });
console.log(user + ': ' + data); console.log(user + ': ' + data);
} }
page.close();
callback.apply(); callback.apply();
}); });
} }

2
examples/hello.coffee Normal file
View File

@ -0,0 +1,2 @@
console.log 'Hello, world!'
phantom.exit()

19
examples/imagebin.coffee Normal file
View File

@ -0,0 +1,19 @@
# Upload an image to imagebin.org
page = require('webpage').create()
if phantom.args.length isnt 1
console.log 'Usage: imagebin.coffee filename'
phantom.exit()
else
fname = phantom.args[0]
page.open 'http://imagebin.org/index.php?page=add', ->
page.uploadFile 'input[name=image]', fname
page.evaluate ->
document.querySelector('input[name=nickname]').value = 'phantom'
document.querySelector('input[name=disclaimer_agree]').click()
document.querySelector('form').submit()
window.setTimeout ->
phantom.exit()
, 3000

View File

@ -1,14 +1,13 @@
// Upload an image to imagebin.org // Upload an image to imagebin.org
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'),
fname; fname;
if (system.args.length !== 2) { if (phantom.args.length !== 1) {
console.log('Usage: imagebin.js filename'); console.log('Usage: imagebin.js filename');
phantom.exit(1); phantom.exit();
} else { } else {
fname = system.args[1]; fname = phantom.args[0];
page.open("http://imagebin.org/index.php?page=add", function () { page.open("http://imagebin.org/index.php?page=add", function () {
page.uploadFile('input[name=image]', fname); page.uploadFile('input[name=image]', fname);
page.evaluate(function () { page.evaluate(function () {

23
examples/injectme.coffee Normal file
View File

@ -0,0 +1,23 @@
# Use 'page.injectJs()' to load the script itself in the Page context
if phantom?
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main
# Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) -> console.log(msg)
page.onAlert = (msg) -> console.log(msg)
console.log "* Script running in the Phantom context."
console.log "* Script will 'inject' itself in a page..."
page.open "about:blank", (status) ->
if status is "success"
if page.injectJs("injectme.coffee")
console.log "... done injecting itself!"
else
console.log "... fail! Check the $PWD?!"
phantom.exit()
else
alert "* Script running in the Page context."

13
examples/ipgeocode.coffee Normal file
View File

@ -0,0 +1,13 @@
# Give the estimated location based on the IP address.
window.cb = (data) ->
loc = data.city
if data.region_name.length > 0
loc = loc + ', ' + data.region_name
console.log 'IP address: ' + data.ip
console.log 'Estimated location: ' + loc
phantom.exit()
el = document.createElement 'script'
el.src = 'http://freegeoip.net/json/?callback=window.cb'
document.body.appendChild el

17
examples/loadspeed.coffee Normal file
View File

@ -0,0 +1,17 @@
page = require('webpage').create()
if phantom.args.length is 0
console.log 'Usage: loadspeed.js <some URL>'
phantom.exit()
else
t = Date.now()
address = phantom.args[0]
page.open address, (status) ->
if status isnt 'success'
console.log('FAIL to load the address')
else
t = Date.now() - t
console.log('Page title is ' + page.evaluate( (-> document.title) ))
console.log('Loading time ' + t + ' msec')
phantom.exit()

View File

@ -1,13 +1,12 @@
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'),
t, address; t, address;
if (system.args.length === 1) { if (phantom.args.length === 0) {
console.log('Usage: loadspeed.js <some URL>'); console.log('Usage: loadspeed.js <some URL>');
phantom.exit(1); phantom.exit();
} else { } else {
t = Date.now(); t = Date.now();
address = system.args[1]; address = phantom.args[0];
page.open(address, function (status) { page.open(address, function (status) {
if (status !== 'success') { if (status !== 'success') {
console.log('FAIL to load the address'); console.log('FAIL to load the address');

View File

@ -1,25 +0,0 @@
var page = require('webpage').create(),
system = require('system');
if (system.args.length < 2) {
console.log('Usage: loadurlwithoutcss.js URL');
phantom.exit();
}
var address = system.args[1];
page.onResourceRequested = function(requestData, request) {
if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData.headers['Content-Type'] == 'text/css') {
console.log('The url of the request is matching. Aborting: ' + requestData['url']);
request.abort();
}
};
page.open(address, function(status) {
if (status === 'success') {
phantom.exit();
} else {
console.log('Unable to load the address!');
phantom.exit();
}
});

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
var universe = require('./universe');
universe.start();
console.log('The answer is' + universe.answer);
phantom.exit();

13
examples/movies.coffee Normal file
View File

@ -0,0 +1,13 @@
# List movies from kids-in-mind.com
window.cbfunc = (data) ->
globaldata = data
list = data.query.results.movie
for item in list
console.log item.title + ' [' + item.rating.MPAA.content + ']'
phantom.exit()
el = document.createElement 'script'
el.src =
"http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20movies.kids-in-mind&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc"
document.body.appendChild el

17
examples/netlog.coffee Normal file
View File

@ -0,0 +1,17 @@
page = require('webpage').create()
address = phantom.args[0]
if phantom.args.length is 0
console.log 'Usage: netlog.coffee <some URL>'
phantom.exit()
else
page.onResourceRequested = (req) ->
console.log 'requested ' + JSON.stringify(req, undefined, 4)
page.onResourceReceived = (res) ->
console.log 'received ' + JSON.stringify(res, undefined, 4)
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit()

View File

@ -1,12 +1,10 @@
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'), address = phantom.args[0];
address;
if (system.args.length === 1) { if (phantom.args.length === 0) {
console.log('Usage: netlog.js <some URL>'); console.log('Usage: netlog.js <some URL>');
phantom.exit(1); phantom.exit();
} else { } else {
address = system.args[1];
page.onResourceRequested = function (req) { page.onResourceRequested = function (req) {
console.log('requested: ' + JSON.stringify(req, undefined, 4)); console.log('requested: ' + JSON.stringify(req, undefined, 4));

109
examples/netsniff.coffee Normal file
View File

@ -0,0 +1,109 @@
if not Date::toISOString
Date::toISOString = ->
pad = (n) ->
if n < 10 then '0' + n else n
ms = (n) ->
if n < 10 then '00' + n else (if n < 100 then '0' + n else n)
@getFullYear() + '-' +
pad(@getMonth() + 1) + '-' +
pad(@getDate()) + 'T' +
pad(@getHours()) + ':' +
pad(@getMinutes()) + ':' +
pad(@getSeconds()) + '.' +
ms(@getMilliseconds()) + 'Z'
createHAR = (address, title, startTime, resources) ->
entries = []
resources.forEach (resource) ->
request = resource.request
startReply = resource.startReply
endReply = resource.endReply
if not request or not startReply or not endReply
return
entries.push
startedDateTime: request.time.toISOString()
time: endReply.time - request.time
request:
method: request.method
url: request.url
httpVersion: 'HTTP/1.1'
cookies: []
headers: request.headers
queryString: []
headersSize: -1
bodySize: -1
response:
status: endReply.status
statusText: endReply.statusText
httpVersion: 'HTTP/1.1'
cookies: []
headers: endReply.headers
redirectURL: ''
headersSize: -1
bodySize: startReply.bodySize
content:
size: startReply.bodySize
mimeType: endReply.contentType
cache: {}
timings:
blocked: 0
dns: -1
connect: -1
send: 0
wait: startReply.time - request.time
receive: endReply.time - startReply.time
ssl: -1
log:
version: '1.2'
creator:
name: 'PhantomJS'
version: phantom.version.major + '.' + phantom.version.minor + '.' + phantom.version.patch
pages: [
startedDateTime: startTime.toISOString()
id: address
title: title
pageTimings: {}
]
entries: entries
page = require('webpage').create()
if phantom.args.length is 0
console.log 'Usage: netsniff.js <some URL>'
phantom.exit()
else
page.address = phantom.args[0]
page.resources = []
page.onLoadStarted = ->
page.startTime = new Date()
page.onResourceRequested = (req) ->
page.resources[req.id] =
request: req
startReply: null
endReply: null
page.onResourceReceived = (res) ->
if res.stage is 'start'
page.resources[res.id].startReply = res
if res.stage is 'end'
page.resources[res.id].endReply = res
page.open page.address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
else
page.title = page.evaluate ->
document.title
har = createHAR page.address, page.title, page.startTime, page.resources
console.log JSON.stringify har, undefined, 4
phantom.exit()

View File

@ -25,12 +25,6 @@ function createHAR(address, title, startTime, resources)
return; return;
} }
// Exclude Data URI from HAR file because
// they aren't included in specification
if (request.url.match(/(^data:image\/.*)/i)) {
return;
}
entries.push({ entries.push({
startedDateTime: request.time.toISOString(), startedDateTime: request.time.toISOString(),
time: endReply.time - request.time, time: endReply.time - request.time,
@ -67,8 +61,7 @@ function createHAR(address, title, startTime, resources)
wait: startReply.time - request.time, wait: startReply.time - request.time,
receive: endReply.time - startReply.time, receive: endReply.time - startReply.time,
ssl: -1 ssl: -1
}, }
pageref: address
}); });
}); });
@ -84,24 +77,21 @@ function createHAR(address, title, startTime, resources)
startedDateTime: startTime.toISOString(), startedDateTime: startTime.toISOString(),
id: address, id: address,
title: title, title: title,
pageTimings: { pageTimings: {}
onLoad: page.endTime - page.startTime
}
}], }],
entries: entries entries: entries
} }
}; };
} }
var page = require('webpage').create(), var page = require('webpage').create();
system = require('system');
if (system.args.length === 1) { if (phantom.args.length === 0) {
console.log('Usage: netsniff.js <some URL>'); console.log('Usage: netsniff.js <some URL>');
phantom.exit(1); phantom.exit();
} else { } else {
page.address = system.args[1]; page.address = phantom.args[0];
page.resources = []; page.resources = [];
page.onLoadStarted = function () { page.onLoadStarted = function () {
@ -129,15 +119,13 @@ if (system.args.length === 1) {
var har; var har;
if (status !== 'success') { if (status !== 'success') {
console.log('FAIL to load the address'); console.log('FAIL to load the address');
phantom.exit(1);
} else { } else {
page.endTime = new Date();
page.title = page.evaluate(function () { page.title = page.evaluate(function () {
return document.title; return document.title;
}); });
har = createHAR(page.address, page.title, page.startTime, page.resources); har = createHAR(page.address, page.title, page.startTime, page.resources);
console.log(JSON.stringify(har, undefined, 4)); console.log(JSON.stringify(har, undefined, 4));
phantom.exit();
} }
phantom.exit();
}); });
} }

View File

@ -1,24 +0,0 @@
var page = require('webpage').create(),
system = require('system'),
host, port, address;
if (system.args.length < 4) {
console.log('Usage: openurlwithproxy.js <proxyHost> <proxyPort> <URL>');
phantom.exit(1);
} else {
host = system.args[1];
port = system.args[2];
address = system.args[3];
phantom.setProxy(host, port, 'manual', '', '');
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address "' +
address + '" using proxy "' + host + ':' + port + '"');
} else {
console.log('Page title is ' + page.evaluate(function () {
return document.title;
}));
}
phantom.exit();
});
}

View File

@ -0,0 +1,12 @@
helloWorld = () -> console.log phantom.outputEncoding + ": こんにちは、世界!"
console.log "Using default encoding..."
helloWorld()
console.log "\nUsing other encodings..."
for enc in ["euc-jp", "sjis", "utf8", "System"]
do (enc) ->
phantom.outputEncoding = enc
helloWorld()
phantom.exit()

View File

@ -1,146 +0,0 @@
// The purpose of this is to show how and when events fire, considering 5 steps
// happening as follows:
//
// 1. Load URL
// 2. Load same URL, but adding an internal FRAGMENT to it
// 3. Click on an internal Link, that points to another internal FRAGMENT
// 4. Click on an external Link, that will send the page somewhere else
// 5. Close page
//
// Take particular care when going through the output, to understand when
// things happen (and in which order). Particularly, notice what DOESN'T
// happen during step 3.
//
// If invoked with "-v" it will print out the Page Resources as they are
// Requested and Received.
//
// NOTE.1: The "onConsoleMessage/onAlert/onPrompt/onConfirm" events are
// registered but not used here. This is left for you to have fun with.
// NOTE.2: This script is not here to teach you ANY JavaScript. It's aweful!
// NOTE.3: Main audience for this are people new to PhantomJS.
var sys = require("system"),
page = require("webpage").create(),
logResources = false,
step1url = "http://en.wikipedia.org/wiki/DOM_events",
step2url = "http://en.wikipedia.org/wiki/DOM_events#Event_flow";
if (sys.args.length > 1 && sys.args[1] === "-v") {
logResources = true;
}
function printArgs() {
var i, ilen;
for (i = 0, ilen = arguments.length; i < ilen; ++i) {
console.log(" arguments[" + i + "] = " + JSON.stringify(arguments[i]));
}
console.log("");
}
////////////////////////////////////////////////////////////////////////////////
page.onInitialized = function() {
console.log("page.onInitialized");
printArgs.apply(this, arguments);
};
page.onLoadStarted = function() {
console.log("page.onLoadStarted");
printArgs.apply(this, arguments);
};
page.onLoadFinished = function() {
console.log("page.onLoadFinished");
printArgs.apply(this, arguments);
};
page.onUrlChanged = function() {
console.log("page.onUrlChanged");
printArgs.apply(this, arguments);
};
page.onNavigationRequested = function() {
console.log("page.onNavigationRequested");
printArgs.apply(this, arguments);
};
page.onRepaintRequested = function() {
console.log("page.onRepaintRequested");
printArgs.apply(this, arguments);
};
if (logResources === true) {
page.onResourceRequested = function() {
console.log("page.onResourceRequested");
printArgs.apply(this, arguments);
};
page.onResourceReceived = function() {
console.log("page.onResourceReceived");
printArgs.apply(this, arguments);
};
}
page.onClosing = function() {
console.log("page.onClosing");
printArgs.apply(this, arguments);
};
// window.console.log(msg);
page.onConsoleMessage = function() {
console.log("page.onConsoleMessage");
printArgs.apply(this, arguments);
};
// window.alert(msg);
page.onAlert = function() {
console.log("page.onAlert");
printArgs.apply(this, arguments);
};
// var confirmed = window.confirm(msg);
page.onConfirm = function() {
console.log("page.onConfirm");
printArgs.apply(this, arguments);
};
// var user_value = window.prompt(msg, default_value);
page.onPrompt = function() {
console.log("page.onPrompt");
printArgs.apply(this, arguments);
};
////////////////////////////////////////////////////////////////////////////////
setTimeout(function() {
console.log("");
console.log("### STEP 1: Load '" + step1url + "'");
page.open(step1url);
}, 0);
setTimeout(function() {
console.log("");
console.log("### STEP 2: Load '" + step2url + "' (load same URL plus FRAGMENT)");
page.open(step2url);
}, 5000);
setTimeout(function() {
console.log("");
console.log("### STEP 3: Click on page internal link (aka FRAGMENT)");
page.evaluate(function() {
var ev = document.createEvent("MouseEvents");
ev.initEvent("click", true, true);
document.querySelector("a[href='#Event_object']").dispatchEvent(ev);
});
}, 10000);
setTimeout(function() {
console.log("");
console.log("### STEP 4: Click on page external link");
page.evaluate(function() {
var ev = document.createEvent("MouseEvents");
ev.initEvent("click", true, true);
document.querySelector("a[title='JavaScript']").dispatchEvent(ev);
});
}, 15000);
setTimeout(function() {
console.log("");
console.log("### STEP 5: Close page and shutdown (with a delay)");
page.close();
setTimeout(function(){
phantom.exit();
}, 100);
}, 20000);

View File

@ -1,17 +0,0 @@
var p = require("webpage").create();
p.onConsoleMessage = function(msg) { console.log(msg); };
// Calls to "callPhantom" within the page 'p' arrive here
p.onCallback = function(msg) {
console.log("Received by the 'phantom' main context: "+msg);
return "Hello there, I'm coming to you from the 'phantom' context instead";
};
p.evaluate(function() {
// Return-value of the "onCallback" handler arrive here
var callbackResponse = window.callPhantom("Hello, I'm coming to you from the 'page' context");
console.log("Received by the 'page' context: "+callbackResponse);
});
phantom.exit();

View File

@ -0,0 +1,13 @@
# Read the Phantom webpage '#intro' element text using jQuery and "includeJs"
page = require('webpage').create()
page.onConsoleMessage = (msg) -> console.log msg
page.open "http://www.phantomjs.org", (status) ->
if status is "success"
page.includeJs "http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", ->
page.evaluate ->
console.log "$(\"#intro\").text() -> " + $("#intro").text()
phantom.exit()

View File

@ -10,7 +10,7 @@ page.open("http://www.phantomjs.org", function(status) {
if ( status === "success" ) { if ( status === "success" ) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
page.evaluate(function() { page.evaluate(function() {
console.log("$(\".explanation\").text() -> " + $(".explanation").text()); console.log("$(\"#intro\").text() -> " + $("#intro").text());
}); });
phantom.exit(); phantom.exit();
}); });

18
examples/pizza.coffee Normal file
View File

@ -0,0 +1,18 @@
# Find pizza in Mountain View using Yelp
page = require('webpage').create()
url = 'http://lite.yelp.com/search?find_desc=pizza&find_loc=94040&find_submit=Search'
page.open url,
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
results = page.evaluate ->
pizza = []
list = document.querySelectorAll 'span.address'
for item in list
pizza.push(item.innerText)
return pizza
console.log results.join('\n')
phantom.exit()

View File

@ -8,7 +8,7 @@ page.open(url, function (status) {
console.log('Unable to access network'); console.log('Unable to access network');
} else { } else {
var results = page.evaluate(function() { var results = page.evaluate(function() {
var list = document.querySelectorAll('address'), pizza = [], i; var list = document.querySelectorAll('span.address'), pizza = [], i;
for (i = 0; i < list.length; i++) { for (i = 0; i < list.length; i++) {
pizza.push(list[i].innerText); pizza.push(list[i].innerText);
} }

12
examples/post.coffee Normal file
View File

@ -0,0 +1,12 @@
# Example using HTTP POST operation
page = require('webpage').create()
server = 'http://posttestserver.com/post.php?dump'
data = 'universe=expanding&answer=42'
page.open server, 'post', data, (status) ->
if status isnt 'success'
console.log 'Unable to post!'
else
console.log page.content
phantom.exit()

View File

@ -1,18 +0,0 @@
// Example using HTTP POST operation
var page = require('webpage').create(),
server = 'http://posttestserver.com/post.php?dump',
data = '{"universe": "expanding", "answer": 42}';
var headers = {
"Content-Type": "application/json"
}
page.open(server, 'post', data, headers, function (status) {
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.content);
}
phantom.exit();
});

View File

@ -1,34 +0,0 @@
// Example using HTTP POST operation
var page = require('webpage').create(),
server = require('webserver').create(),
system = require('system'),
data = 'universe=expanding&answer=42';
if (system.args.length !== 2) {
console.log('Usage: postserver.js <portnumber>');
phantom.exit(1);
}
var port = system.args[1];
service = server.listen(port, function (request, response) {
console.log('Request received at ' + new Date());
response.statusCode = 200;
response.headers = {
'Cache': 'no-cache',
'Content-Type': 'text/plain;charset=utf-8'
};
response.write(JSON.stringify(request, null, 4));
response.close();
});
page.open('http://localhost:' + port + '/', 'post', data, function (status) {
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.plainText);
}
phantom.exit();
});

View File

@ -1,10 +0,0 @@
var system = require('system'),
env = system.env,
key;
for (key in env) {
if (env.hasOwnProperty(key)) {
console.log(key + '=' + env[key]);
}
}
phantom.exit();

View File

@ -1,89 +0,0 @@
var page = require('webpage').create(),
system = require('system');
function someCallback(pageNum, numPages) {
return "<h1> someCallback: " + pageNum + " / " + numPages + "</h1>";
}
if (system.args.length < 3) {
console.log('Usage: printheaderfooter.js URL filename');
phantom.exit(1);
} else {
var address = system.args[1];
var output = system.args[2];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = {
format: 'A4',
margin: "1cm",
/* default header/footer for pages that don't have custom overwrites (see below) */
header: {
height: "1cm",
contents: phantom.callback(function(pageNum, numPages) {
if (pageNum == 1) {
return "";
}
return "<h1>Header <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>";
})
},
footer: {
height: "1cm",
contents: phantom.callback(function(pageNum, numPages) {
if (pageNum == numPages) {
return "";
}
return "<h1>Footer <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>";
})
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
/* check whether the loaded page overwrites the header/footer setting,
i.e. whether a PhantomJSPriting object exists. Use that then instead
of our defaults above.
example:
<html>
<head>
<script type="text/javascript">
var PhantomJSPrinting = {
header: {
height: "1cm",
contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
},
footer: {
height: "1cm",
contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
}
};
</script>
</head>
<body><h1>asdfadsf</h1><p>asdfadsfycvx</p></body>
</html>
*/
if (page.evaluate(function(){return typeof PhantomJSPrinting == "object";})) {
paperSize = page.paperSize;
paperSize.header.height = page.evaluate(function() {
return PhantomJSPrinting.header.height;
});
paperSize.header.contents = phantom.callback(function(pageNum, numPages) {
return page.evaluate(function(pageNum, numPages){return PhantomJSPrinting.header.contents(pageNum, numPages);}, pageNum, numPages);
});
paperSize.footer.height = page.evaluate(function() {
return PhantomJSPrinting.footer.height;
});
paperSize.footer.contents = phantom.callback(function(pageNum, numPages) {
return page.evaluate(function(pageNum, numPages){return PhantomJSPrinting.footer.contents(pageNum, numPages);}, pageNum, numPages);
});
page.paperSize = paperSize;
console.log(page.paperSize.header.height);
console.log(page.paperSize.footer.height);
}
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}

View File

@ -1,35 +0,0 @@
var page = require('webpage').create(),
system = require('system');
if (system.args.length < 7) {
console.log('Usage: printmargins.js URL filename LEFT TOP RIGHT BOTTOM');
console.log(' margin examples: "1cm", "10px", "7mm", "5in"');
phantom.exit(1);
} else {
var address = system.args[1];
var output = system.args[2];
var marginLeft = system.args[3];
var marginTop = system.args[4];
var marginRight = system.args[5];
var marginBottom = system.args[6];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = {
format: 'A4',
margin: {
left: marginLeft,
top: marginTop,
right: marginRight,
bottom: marginBottom
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}

22
examples/rasterize.coffee Normal file
View File

@ -0,0 +1,22 @@
page = require('webpage').create()
if phantom.args.length < 2 or phantom.args.length > 3
console.log 'Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat]'
console.log ' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'
phantom.exit()
else
address = phantom.args[0]
output = phantom.args[1]
page.viewportSize = { width: 600, height: 600 }
if phantom.args.length is 3 and phantom.args[1].substr(-4) is ".pdf"
size = phantom.args[2].split '*'
if size.length is 2
page.paperSize = { width: size[0], height: size[1], border: '0px' }
else
page.paperSize = { format: phantom.args[2], orientation: 'portrait', border: '1cm' }
page.open address, (status) ->
if status isnt 'success'
console.log 'Unable to load the address!'
phantom.exit()
else
window.setTimeout (-> page.render output; phantom.exit()), 200

View File

@ -1,43 +1,22 @@
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'),
address, output, size; address, output, size;
if (system.args.length < 3 || system.args.length > 5) { if (phantom.args.length < 2 || phantom.args.length > 3) {
console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]'); console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat]');
console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'); console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px'); phantom.exit();
console.log(' "800px*600px" window, clipped to 800x600');
phantom.exit(1);
} else { } else {
address = system.args[1]; address = phantom.args[0];
output = system.args[2]; output = phantom.args[1];
page.viewportSize = { width: 600, height: 600 }; page.viewportSize = { width: 600, height: 600 };
if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") { if (phantom.args.length === 3 && phantom.args[1].substr(-4) === ".pdf") {
size = system.args[3].split('*'); size = phantom.args[2].split('*');
page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } page.paperSize = size.length === 2 ? { width: size[0], height: size[1], border: '0px' }
: { format: system.args[3], orientation: 'portrait', margin: '1cm' }; : { format: phantom.args[2], orientation: 'portrait', border: '1cm' };
} else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
size = system.args[3].split('*');
if (size.length === 2) {
pageWidth = parseInt(size[0], 10);
pageHeight = parseInt(size[1], 10);
page.viewportSize = { width: pageWidth, height: pageHeight };
page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
} else {
console.log("size:", system.args[3]);
pageWidth = parseInt(system.args[3], 10);
pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
console.log ("pageHeight:",pageHeight);
page.viewportSize = { width: pageWidth, height: pageHeight };
}
}
if (system.args.length > 4) {
page.zoomFactor = system.args[4];
} }
page.open(address, function (status) { page.open(address, function (status) {
if (status !== 'success') { if (status !== 'success') {
console.log('Unable to load the address!'); console.log('Unable to load the address!');
phantom.exit(1);
} else { } else {
window.setTimeout(function () { window.setTimeout(function () {
page.render(output); page.render(output);

View File

@ -0,0 +1,48 @@
# Render Multiple URLs to file
# FIXME: For now it is fine with pure domain names: don't think it would work with paths and stuff like that
# Extend the Array Prototype with a 'foreach'
Array.prototype.forEach = (action) ->
for i, j in this
action j, i, _len
# Render a given url to a given file
# @param url URL to render
# @param file File to render to
# @param callback Callback function
renderUrlToFile = (url, file, callback) ->
page = require('webpage').create()
page.viewportSize = { width: 800, height : 600 }
page.settings.userAgent = 'Phantom.js bot'
page.open url, (status) ->
if status isnt 'success'
console.log "Unable to render '#{url}'"
else
page.render file
delete page
callback url, file
# Read the passed args
if phantom.args.length > 0
arrayOfUrls = phantom.args
else
# Default (no args passed)
console.log 'Usage: phantomjs render_multi_url.coffee [domain.name1, domain.name2, ...]'
arrayOfUrls = [
'www.google.com',
'www.bbc.co.uk',
'www.phantomjs.org'
]
# For each URL
arrayOfUrls.forEach (pos, url, total) ->
file_name = "./#{url}.png"
# Render to a file
renderUrlToFile "http://#{url}", file_name, (url, file) ->
console.log "Rendered '#{url}' at '#{file}'"
if pos is total - 1
# Close Phantom if it's the last URL
phantom.exit()

View File

@ -1,73 +1,60 @@
// Render Multiple URLs to file // Render Multiple URLs to file
// FIXME: For now it is fine with pure domain names: don't think it would work with paths and stuff like that
var RenderUrlsToFile, arrayOfUrls, system; // Extend the Array Prototype with a 'foreach'
Array.prototype.forEach = function (action) {
system = require("system"); var i, len;
for ( i = 0, len = this.length; i < len; ++i ) {
/* action(i, this[i], len);
Render given urls
@param array of URLs to render
@param callbackPerUrl Function called after finishing each URL, including the last URL
@param callbackFinal Function called after finishing everything
*/
RenderUrlsToFile = function(urls, callbackPerUrl, callbackFinal) {
var getFilename, next, page, retrieve, urlIndex, webpage;
urlIndex = 0;
webpage = require("webpage");
page = null;
getFilename = function() {
return "rendermulti-" + urlIndex + ".png";
};
next = function(status, url, file) {
page.close();
callbackPerUrl(status, url, file);
return retrieve();
};
retrieve = function() {
var url;
if (urls.length > 0) {
url = urls.shift();
urlIndex++;
page = webpage.create();
page.viewportSize = {
width: 800,
height: 600
};
page.settings.userAgent = "Phantom.js bot";
return page.open("http://" + url, function(status) {
var file;
file = getFilename();
if (status === "success") {
return window.setTimeout((function() {
page.render(file);
return next(status, url, file);
}), 200);
} else {
return next(status, url, file);
} }
});
} else {
return callbackFinal();
}
};
return retrieve();
}; };
arrayOfUrls = null; /**
* Render a given url to a given file
* @param url URL to render
* @param file File to render to
* @param callback Callback function
*/
function renderUrlToFile(url, file, callback) {
var page = require('webpage').create();
page.viewportSize = { width: 800, height : 600 };
page.settings.userAgent = "Phantom.js bot";
if (system.args.length > 1) { page.open(url, function(status){
arrayOfUrls = Array.prototype.slice.call(system.args, 1); if ( status !== "success") {
} else { console.log("Unable to render '"+url+"'");
console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]"); } else {
arrayOfUrls = ["www.google.com", "www.bbc.co.uk", "www.phantomjs.org"]; page.render(file);
}
delete page;
callback(url, file);
});
} }
RenderUrlsToFile(arrayOfUrls, (function(status, url, file) { // Read the passed args
if (status !== "success") { var arrayOfUrls;
return console.log("Unable to render '" + url + "'"); if ( phantom.args.length > 0 ) {
} else { arrayOfUrls = phantom.args;
return console.log("Rendered '" + url + "' at '" + file + "'"); } else {
// Default (no args passed)
console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]");
arrayOfUrls = [
'www.google.com',
'www.bbc.co.uk',
'www.phantomjs.org'
];
}
// For each URL
arrayOfUrls.forEach(function(pos, url, total){
var file_name = "./" + url + ".png";
// Render to a file
renderUrlToFile("http://"+url, file_name, function(url, file){
console.log("Rendered '"+url+"' at '"+file+"'");
if ( pos === total-1 ) {
// Close Phantom if it's the last URL
phantom.exit();
} }
}), function() { });
return phantom.exit();
}); });

View File

@ -0,0 +1,59 @@
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit(1)
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if phantom.args.length isnt 1
console.log 'Usage: run-jasmine.coffee URL'
phantom.exit()
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open phantom.args[0], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit()
else
waitFor ->
page.evaluate ->
if document.body.querySelector '.finished-at'
return true
return false
, ->
page.evaluate ->
console.log document.body.querySelector('.description').innerText
list = document.body.querySelectorAll('.failed > .description, .failed > .messages > .resultMessage')
for el in list
console.log el.innerText
phantom.exit()

View File

@ -1,5 +1,3 @@
var system = require('system');
/** /**
* Wait until the test condition is true or a timeout occurs. Useful for waiting * Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur. * on a server response or for a ui change (fadeIn, etc.) to occur.
@ -36,9 +34,9 @@ function waitFor(testFx, onReady, timeOutMillis) {
}; };
if (system.args.length !== 2) { if (phantom.args.length === 0 || phantom.args.length > 2) {
console.log('Usage: run-jasmine.js URL'); console.log('Usage: run-jasmine.js URL');
phantom.exit(1); phantom.exit();
} }
var page = require('webpage').create(); var page = require('webpage').create();
@ -48,44 +46,32 @@ page.onConsoleMessage = function(msg) {
console.log(msg); console.log(msg);
}; };
page.open(system.args[1], function(status){ page.open(phantom.args[0], function(status){
if (status !== "success") { if (status !== "success") {
console.log("Unable to open " + system.args[1]); console.log("Unable to access network");
phantom.exit(1); phantom.exit();
} else { } else {
waitFor(function(){ waitFor(function(){
return page.evaluate(function(){ return page.evaluate(function(){
return document.body.querySelector('.symbolSummary .pending') === null if (document.body.querySelector('.finished-at')) {
return true;
}
return false;
}); });
}, function(){ }, function(){
var exitCode = page.evaluate(function(){ page.evaluate(function(){
try {
console.log('');
console.log(document.body.querySelector('.description').innerText); console.log(document.body.querySelector('.description').innerText);
var list = document.body.querySelectorAll('.results > #details > .specDetail.failed'); list = document.body.querySelectorAll('div.jasmine_reporter > div.suite.failed');
if (list && list.length > 0) {
console.log('');
console.log(list.length + ' test(s) FAILED:');
for (i = 0; i < list.length; ++i) { for (i = 0; i < list.length; ++i) {
var el = list[i], el = list[i];
desc = el.querySelector('.description'), desc = el.querySelectorAll('.description');
msg = el.querySelector('.resultMessage.fail');
console.log('');
console.log(desc.innerText);
console.log(msg.innerText);
console.log(''); console.log('');
for (j = 0; j < desc.length; ++j) {
console.log(desc[j].innerText);
} }
return 1;
} else {
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
return 0;
}
} catch (ex) {
console.log(ex);
return 1;
} }
}); });
phantom.exit(exitCode); phantom.exit();
}); });
} }
}); });

View File

@ -1,92 +0,0 @@
var system = require('system');
/**
* Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur.
*
* @param testFx javascript condition that evaluates to a boolean,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param onReady what to do when testFx condition is fulfilled,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
*/
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timeout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 100); //< repeat check every 100ms
};
if (system.args.length !== 2) {
console.log('Usage: run-jasmine.js URL');
phantom.exit(1);
}
var page = require('webpage').create();
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.open(system.args[1], function(status){
if (status !== "success") {
console.log("Unable to access network");
phantom.exit();
} else {
waitFor(function(){
return page.evaluate(function(){
return document.body.querySelector('.symbolSummary .pending') === null
});
}, function(){
var exitCode = page.evaluate(function(){
console.log('');
var el = document.body.querySelector('.banner');
var banner = el.querySelector('.title').innerText + " " +
el.querySelector('.version').innerText + " " +
el.querySelector('.duration').innerText;
console.log(banner);
var list = document.body.querySelectorAll('.results > .failures > .spec-detail.failed');
if (list && list.length > 0) {
console.log('');
console.log(list.length + ' test(s) FAILED:');
for (i = 0; i < list.length; ++i) {
var el = list[i],
desc = el.querySelector('.description'),
msg = el.querySelector('.messages > .result-message');
console.log('');
console.log(desc.innerText);
console.log(msg.innerText);
console.log('');
}
return 1;
} else {
console.log(document.body.querySelector('.alert > .bar.passed').innerText);
return 0;
}
});
phantom.exit(exitCode);
});
}
});

62
examples/run-qunit.coffee Normal file
View File

@ -0,0 +1,62 @@
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit(1)
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if phantom.args.length isnt 1
console.log 'Usage: run-qunit.coffee URL'
phantom.exit(1)
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open phantom.args[0], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit(1)
else
waitFor ->
page.evaluate ->
el = document.getElementById 'qunit-testresult'
if el and el.innerText.match 'completed'
return true
return false
, ->
failedNum = page.evaluate ->
el = document.getElementById 'qunit-testresult'
console.log el.innerText
try
return el.getElementsByClassName('failed')[0].innerHTML
catch e
return 10000
phantom.exit if parseInt(failedNum, 10) > 0 then 1 else 0

View File

@ -1,5 +1,3 @@
var system = require('system');
/** /**
* Wait until the test condition is true or a timeout occurs. Useful for waiting * Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur. * on a server response or for a ui change (fadeIn, etc.) to occur.
@ -36,7 +34,7 @@ function waitFor(testFx, onReady, timeOutMillis) {
}; };
if (system.args.length !== 2) { if (phantom.args.length === 0 || phantom.args.length > 2) {
console.log('Usage: run-qunit.js URL'); console.log('Usage: run-qunit.js URL');
phantom.exit(1); phantom.exit(1);
} }
@ -48,7 +46,7 @@ page.onConsoleMessage = function(msg) {
console.log(msg); console.log(msg);
}; };
page.open(system.args[1], function(status){ page.open(phantom.args[0], function(status){
if (status !== "success") { if (status !== "success") {
console.log("Unable to access network"); console.log("Unable to access network");
phantom.exit(1); phantom.exit(1);

15
examples/scandir.coffee Normal file
View File

@ -0,0 +1,15 @@
# List all the files in a Tree of Directories
if phantom.args.length != 1
console.log "Usage: phantomjs scandir.js DIRECTORY_TO_SCAN"
phantom.exit()
scanDirectory = (path) ->
fs = require 'fs'
if fs.exists(path) and fs.isFile(path)
console.log path
else if fs.isDirectory(path)
fs.list(path).forEach (e) ->
scanDirectory path + "/" + e if e != "." and e != ".."
scanDirectory phantom.args[0]
phantom.exit()

View File

@ -1,9 +1,8 @@
// List all the files in a Tree of Directories // List all the files in a Tree of Directories
var system = require('system');
if (system.args.length !== 2) { if (phantom.args.length !== 1) {
console.log("Usage: phantomjs scandir.js DIRECTORY_TO_SCAN"); console.log("Usage: phantomjs scandir.js DIRECTORY_TO_SCAN");
phantom.exit(1); phantom.exit();
} }
var scanDirectory = function (path) { var scanDirectory = function (path) {
@ -18,5 +17,5 @@ var scanDirectory = function (path) {
}); });
} }
}; };
scanDirectory(system.args[1]); scanDirectory(phantom.args[0]);
phantom.exit(); phantom.exit();

View File

@ -0,0 +1,17 @@
# Show BBC seasonal food list.
window.cbfunc = (data) ->
list = data.query.results.results.result
names = ['January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December']
for item in list
console.log [item.name.replace(/\s/ig, ' '), ':',
names[item.atItsBestUntil], 'to',
names[item.atItsBestFrom]].join(' ')
phantom.exit()
el = document.createElement 'script'
el.src = 'http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20bbc.goodfood.seasonal%3B&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc'
document.body.appendChild el

View File

@ -1,43 +0,0 @@
var page = require('webpage').create();
var server = require('webserver').create();
var system = require('system');
var host, port;
if (system.args.length !== 2) {
console.log('Usage: server.js <some port>');
phantom.exit(1);
} else {
port = system.args[1];
var listening = server.listen(port, function (request, response) {
console.log("GOT HTTP REQUEST");
console.log(JSON.stringify(request, null, 4));
// we set the headers here
response.statusCode = 200;
response.headers = {"Cache": "no-cache", "Content-Type": "text/html"};
// this is also possible:
response.setHeader("foo", "bar");
// now we write the body
// note: the headers above will now be sent implictly
response.write("<html><head><title>YES!</title></head>");
// note: writeBody can be called multiple times
response.write("<body><p>pretty cool :)</body></html>");
response.close();
});
if (!listening) {
console.log("could not create web server listening on port " + port);
phantom.exit();
}
var url = "http://localhost:" + port + "/foo/bar.php?asdf=true";
console.log("SENDING REQUEST TO:");
console.log(url);
page.open(url, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
} else {
console.log("GOT REPLY FROM SERVER:");
console.log(page.content);
}
phantom.exit();
});
}

View File

@ -1,34 +0,0 @@
var port, server, service,
system = require('system');
if (system.args.length !== 2) {
console.log('Usage: serverkeepalive.js <portnumber>');
phantom.exit(1);
} else {
port = system.args[1];
server = require('webserver').create();
service = server.listen(port, { keepAlive: true }, function (request, response) {
console.log('Request at ' + new Date());
console.log(JSON.stringify(request, null, 4));
var body = JSON.stringify(request, null, 4);
response.statusCode = 200;
response.headers = {
'Cache': 'no-cache',
'Content-Type': 'text/plain',
'Connection': 'Keep-Alive',
'Keep-Alive': 'timeout=5, max=100',
'Content-Length': body.length
};
response.write(body);
response.close();
});
if (service) {
console.log('Web server running on port ' + port);
} else {
console.log('Error: Could not create web server listening on port ' + port);
phantom.exit();
}
}

View File

@ -0,0 +1,35 @@
if phantom.args.length is 0
console.log "Usage: simpleserver.js <portnumber>"
phantom.exit()
else
port = phantom.args[0]
server = require("webserver").create()
service = server.listen(port, (request, response) ->
console.log "Request at " + new Date()
console.log JSON.stringify(request, null, 4)
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/html"
response.write "<html>"
response.write "<head>"
response.write "<title>Hello, world!</title>"
response.write "</head>"
response.write "<body>"
response.write "<p>This is from PhantomJS web server.</p>"
response.write "<p>Request data:</p>"
response.write "<pre>"
response.write JSON.stringify(request, null, 4)
response.write "</pre>"
response.write "</body>"
response.write "</html>"
)
if service
console.log "Web server running on port " + port
else
console.log "Error: Could not create web server listening on port " + port
phantom.exit()

View File

@ -1,11 +1,10 @@
var port, server, service, var port, server, service;
system = require('system');
if (system.args.length !== 2) { if (phantom.args.length !== 1) {
console.log('Usage: simpleserver.js <portnumber>'); console.log('Usage: simpleserver.js <portnumber>');
phantom.exit(1); phantom.exit();
} else { } else {
port = system.args[1]; port = phantom.args[0];
server = require('webserver').create(); server = require('webserver').create();
service = server.listen(port, function (request, response) { service = server.listen(port, function (request, response) {
@ -30,7 +29,6 @@ if (system.args.length !== 2) {
response.write('</pre>'); response.write('</pre>');
response.write('</body>'); response.write('</body>');
response.write('</html>'); response.write('</html>');
response.close();
}); });
if (service) { if (service) {

17
examples/sleepsort.coffee Normal file
View File

@ -0,0 +1,17 @@
###
Sort integers from the command line in a very ridiculous way: leveraging timeouts :P
###
if phantom.args < 1
console.log "Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES"
phantom.exit()
else
sortedCount = 0
for int in phantom.args
setTimeout ((j) ->
->
console.log j
++sortedCount
phantom.exit() if sortedCount is phantom.args.length)(int),
int

View File

@ -1,5 +1,4 @@
// sleepsort.js - Sort integers from the commandline in a very ridiculous way: leveraging timeouts :P // sleepsort.js - Sort integers from the commandline in a very ridiculous way: leveraging timeouts :P
var system = require('system');
function sleepSort(array, callback) { function sleepSort(array, callback) {
var sortedCount = 0, var sortedCount = 0,
@ -15,11 +14,11 @@ function sleepSort(array, callback) {
} }
} }
if ( system.args.length < 2 ) { if ( phantom.args < 1 ) {
console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES"); console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES");
phantom.exit(1); phantom.exit();
} else { } else {
sleepSort(system.args.slice(1), function() { sleepSort(phantom.args, function() {
phantom.exit(); phantom.exit();
}); });
} }

View File

@ -1,18 +0,0 @@
var system = require('system');
system.stdout.write('Hello, system.stdout.write!');
system.stdout.writeLine('\nHello, system.stdout.writeLine!');
system.stderr.write('Hello, system.stderr.write!');
system.stderr.writeLine('\nHello, system.stderr.writeLine!');
system.stdout.writeLine('system.stdin.readLine(): ');
var line = system.stdin.readLine();
system.stdout.writeLine(JSON.stringify(line));
// This is essentially a `readAll`
system.stdout.writeLine('system.stdin.read(5): (ctrl+D to end)');
var input = system.stdin.read(5);
system.stdout.writeLine(JSON.stringify(input));
phantom.exit(0);

17
examples/technews.coffee Normal file
View File

@ -0,0 +1,17 @@
page = require('webpage').create()
page.viewportSize = { width: 320, height: 480 }
page.open 'http://news.google.com/news/i/section?&topic=t',
(status) ->
if status isnt 'success'
console.log 'Unable to access the network!'
else
page.evaluate ->
body = document.body
body.style.backgroundColor = '#fff'
body.querySelector('div#title-block').style.display = 'none'
body.querySelector('form#edition-picker-form')
.parentElement.parentElement.style.display = 'none'
page.render 'technews.png'
phantom.exit()

30
examples/tweets.coffee Normal file
View File

@ -0,0 +1,30 @@
# Get twitter status for given account (or for the default one, "sencha")
page = require('webpage').create()
twitterId = 'sencha' #< default value
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
# Print usage message, if no twitter ID is passed
if phantom.args.length < 1
console.log 'Usage: tweets.coffee [twitter ID]'
else
twitterId = phantom.args[0]
# Heading
console.log "*** Latest tweets from @#{twitterId} ***\n"
# Open Twitter Mobile and, onPageLoad, do...
page.open encodeURI("http://mobile.twitter.com/#{twitterId}"), (status) ->
# Check for page load success
if status isnt 'success'
console.log 'Unable to access network'
else
# Execute some DOM inspection within the page context
page.evaluate ->
list = document.querySelectorAll 'span.status'
for i, j in list
console.log "#{j + 1}: #{i.innerHTML.replace /<.*?>/g, ''}"
phantom.exit()

View File

@ -1,8 +1,7 @@
// Get twitter status for given account (or for the default one, "PhantomJS") // Get twitter status for given account (or for the default one, "sencha")
var page = require('webpage').create(), var page = require('webpage').create(),
system = require('system'), twitterId = "sencha"; //< default value
twitterId = "PhantomJS"; //< default value
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) { page.onConsoleMessage = function(msg) {
@ -10,10 +9,10 @@ page.onConsoleMessage = function(msg) {
}; };
// Print usage message, if no twitter ID is passed // Print usage message, if no twitter ID is passed
if (system.args.length < 2) { if (phantom.args.length < 1) {
console.log("Usage: tweets.js [twitter ID]"); console.log("Usage: tweets.js [twitter ID]");
} else { } else {
twitterId = system.args[1]; twitterId = phantom.args[0];
} }
// Heading // Heading
@ -27,9 +26,9 @@ page.open(encodeURI("http://mobile.twitter.com/" + twitterId), function (status)
} else { } else {
// Execute some DOM inspection within the page context // Execute some DOM inspection within the page context
page.evaluate(function() { page.evaluate(function() {
var list = document.querySelectorAll('div.tweet-text'); var list = document.querySelectorAll('span.status');
for (var i = 0; i < list.length; ++i) { for (var i = 0; i < list.length; ++i) {
console.log((i + 1) + ": " + list[i].innerText); console.log((i + 1) + ": " + list[i].innerHTML.replace(/<.*?>/g, ''));
} }
}); });
} }

View File

@ -1,10 +0,0 @@
// This is to be used by "module.js" (and "module.coffee") example(s).
// There should NOT be a "universe.coffee" as only 1 of the 2 would
// ever be loaded unless the file extension was specified.
exports.answer = 42;
exports.start = function () {
console.log('Starting the universe....');
}

View File

@ -0,0 +1,18 @@
# Modify global object at the page initialization.
# In this example, effectively Math.random() always returns 0.42.
page = require('webpage').create()
page.onInitialized = ->
page.evaluate ->
Math.random = ->
42 / 100
page.open "http://ariya.github.com/js/random/", (status) ->
if status != "success"
console.log "Network error."
else
console.log page.evaluate(->
document.getElementById("numbers").textContent
)
phantom.exit()

11
examples/useragent.coffee Normal file
View File

@ -0,0 +1,11 @@
page = require('webpage').create()
console.log 'The default user agent is ' + page.settings.userAgent
page.settings.userAgent = 'SpecialAgent'
page.open 'http://www.httpuseragent.org', (status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
console.log page.evaluate -> document.getElementById('myagent').innerText
phantom.exit()

Some files were not shown because too many files have changed in this diff Show More