Skip to content
This repository
Browse code

First import of `ghostdriver.qrc` & related files.

  • Loading branch information...
commit 2dcccc8968889c2dd80fa2d32d39c2e114db7c6c 1 parent 63dd362
Ivan De Marino authored November 16, 2012 ariya committed November 27, 2012

Showing 51 changed files with 19,013 additions and 0 deletions. Show diff stats Hide diff stats

  1. 2  src/filesystem.cpp
  2. 231  src/ghostdriver/errors.js
  3. 79  src/ghostdriver/ghostdriver.qrc
  4. 84  src/ghostdriver/hub_register.js
  5. 344  src/ghostdriver/inputs.js
  6. 7  src/ghostdriver/lastupdate
  7. 81  src/ghostdriver/main.js
  8. 205  src/ghostdriver/request_handlers/request_handler.js
  9. 106  src/ghostdriver/request_handlers/router_request_handler.js
  10. 180  src/ghostdriver/request_handlers/session_manager_request_handler.js
  11. 762  src/ghostdriver/request_handlers/session_request_handler.js
  12. 58  src/ghostdriver/request_handlers/shutdown_request_handler.js
  13. 64  src/ghostdriver/request_handlers/status_request_handler.js
  14. 496  src/ghostdriver/request_handlers/webelement_request_handler.js
  15. 400  src/ghostdriver/session.js
  16. 70  src/ghostdriver/third_party/parseuri.js
  17. 249  src/ghostdriver/third_party/uuid.js
  18. 47  src/ghostdriver/third_party/webdriver-atoms/active_element.js
  19. 132  src/ghostdriver/third_party/webdriver-atoms/clear.js
  20. 17  src/ghostdriver/third_party/webdriver-atoms/clear_local_storage.js
  21. 17  src/ghostdriver/third_party/webdriver-atoms/clear_session_storage.js
  22. 140  src/ghostdriver/third_party/webdriver-atoms/click.js
  23. 47  src/ghostdriver/third_party/webdriver-atoms/default_content.js
  24. 14,032  src/ghostdriver/third_party/webdriver-atoms/deps.js
  25. 121  src/ghostdriver/third_party/webdriver-atoms/double_click.js
  26. 120  src/ghostdriver/third_party/webdriver-atoms/drag.js
  27. 15  src/ghostdriver/third_party/webdriver-atoms/execute_async_script.js
  28. 13  src/ghostdriver/third_party/webdriver-atoms/execute_script.js
  29. 16  src/ghostdriver/third_party/webdriver-atoms/execute_sql.js
  30. 90  src/ghostdriver/third_party/webdriver-atoms/find_element.js
  31. 90  src/ghostdriver/third_party/webdriver-atoms/find_elements.js
  32. 103  src/ghostdriver/third_party/webdriver-atoms/focus_on_element.js
  33. 91  src/ghostdriver/third_party/webdriver-atoms/frame_by_id_or_name.js
  34. 47  src/ghostdriver/third_party/webdriver-atoms/frame_by_index.js
  35. 16  src/ghostdriver/third_party/webdriver-atoms/get_appcache_status.js
  36. 55  src/ghostdriver/third_party/webdriver-atoms/get_attribute.js
  37. 60  src/ghostdriver/third_party/webdriver-atoms/get_attribute_value.js
  38. 7  src/ghostdriver/third_party/webdriver-atoms/get_current_position.js
  39. 7  src/ghostdriver/third_party/webdriver-atoms/get_element_from_cache.js
  40. 47  src/ghostdriver/third_party/webdriver-atoms/get_frame_window.js
  41. 40  src/ghostdriver/third_party/webdriver-atoms/get_in_view_location.js
  42. 17  src/ghostdriver/third_party/webdriver-atoms/get_local_storage_item.js
  43. 17  src/ghostdriver/third_party/webdriver-atoms/get_local_storage_keys.js
  44. 17  src/ghostdriver/third_party/webdriver-atoms/get_local_storage_size.js
  45. 9  src/ghostdriver/third_party/webdriver-atoms/get_location.js
  46. 49  src/ghostdriver/third_party/webdriver-atoms/get_location_in_view.js
  47. 17  src/ghostdriver/third_party/webdriver-atoms/get_session_storage_item.js
  48. 17  src/ghostdriver/third_party/webdriver-atoms/get_session_storage_keys.js
  49. 17  src/ghostdriver/third_party/webdriver-atoms/get_session_storage_size.js
  50. 65  src/ghostdriver/third_party/webdriver-atoms/get_size.js
2  src/filesystem.cpp
@@ -360,6 +360,8 @@ QString FileSystem::absolute(const QString &relativePath) const
360 360
 // Files
361 361
 QObject *FileSystem::_open(const QString &path, const QVariantMap &opts) const
362 362
 {
  363
+    qDebug() << "FileSystem - _open:" << path << opts;
  364
+
363 365
     const QVariant modeVar = opts["mode"];
364 366
     // Ensure only strings
365 367
     if (modeVar.type() != QVariant::String) {
231  src/ghostdriver/errors.js
... ...
@@ -0,0 +1,231 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+All rights reserved.
  6
+
  7
+Redistribution and use in source and binary forms, with or without modification,
  8
+are permitted provided that the following conditions are met:
  9
+
  10
+    * Redistributions of source code must retain the above copyright notice,
  11
+      this list of conditions and the following disclaimer.
  12
+    * Redistributions in binary form must reproduce the above copyright notice,
  13
+      this list of conditions and the following disclaimer in the documentation
  14
+      and/or other materials provided with the distribution.
  15
+
  16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  20
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+//------------------------------------------------------- Invalid Request Errors
  29
+//----- http://code.google.com/p/selenium/wiki/JsonWireProtocol#Invalid_Requests
  30
+exports.INVALID_REQ = {
  31
+    "UNKNOWN_COMMAND"               : "Unknown Command",
  32
+    "UNIMPLEMENTED_COMMAND"         : "Unimplemented Command",
  33
+    "VARIABLE_RESOURCE_NOT_FOUND"   : "Variable Resource Not Found",
  34
+    "INVALID_COMMAND_METHOD"        : "Invalid Command Method",
  35
+    "MISSING_COMMAND_PARAMETER"     : "Missing Command Parameter"
  36
+};
  37
+
  38
+var _invalidReqHandle = function(res) {
  39
+    // Set the right Status Code
  40
+    switch(this.name) {
  41
+        case exports.INVALID_REQ.UNIMPLEMENTED_COMMAND:
  42
+            res.statusCode = 501;   //< 501 Not Implemented
  43
+            break;
  44
+        case exports.INVALID_REQ.INVALID_COMMAND_METHOD:
  45
+            res.statusCode = 405;   //< 405 Method Not Allowed
  46
+            break;
  47
+        case exports.INVALID_REQ.MISSING_COMMAND_PARAMETER:
  48
+            res.statusCode = 400;   //< 400 Bad Request
  49
+            break;
  50
+        default:
  51
+            res.statusCode = 404;   //< 404 Not Found
  52
+            break;
  53
+    }
  54
+
  55
+    res.setHeader("Content-Type", "text/plain");
  56
+    res.writeAndClose(this.name + " - " + this.message);
  57
+};
  58
+
  59
+// Invalid Request Error Handler
  60
+exports.createInvalidReqEH = function(errorName, req) {
  61
+    var e = new Error();
  62
+
  63
+    e.name = errorName;
  64
+    e.message = "Request => " + JSON.stringify(req);
  65
+    e.handle = _invalidReqHandle;
  66
+
  67
+    return e;
  68
+};
  69
+exports.handleInvalidReqEH = function(errorName, req, res) {
  70
+    exports.createInvalidReqEH(errorName, req).handle(res);
  71
+};
  72
+
  73
+// Invalid Request Unknown Command Error Handler
  74
+exports.createInvalidReqUnknownCommandEH = function(req) {
  75
+    return exports.createInvalidReqEH (
  76
+        exports.INVALID_REQ.UNKNOWN_COMMAND,
  77
+        req);
  78
+};
  79
+exports.handleInvalidReqUnknownCommandEH = function(req, res) {
  80
+    exports.createInvalidReqUnknownCommandEH(req).handle(res);
  81
+};
  82
+
  83
+// Invalid Request Unimplemented Command Error Handler
  84
+exports.createInvalidReqUnimplementedCommandEH = function(req) {
  85
+    return exports.createInvalidReqEH (
  86
+        exports.INVALID_REQ.UNIMPLEMENTED_COMMAND,
  87
+        req);
  88
+};
  89
+exports.handleInvalidReqUnimplementedCommandEH = function(req, res) {
  90
+    exports.createInvalidReqUnimplementedCommandEH(req).handle(res);
  91
+};
  92
+
  93
+// Invalid Request Variable Resource Not Found Error Handler
  94
+exports.createInvalidReqVariableResourceNotFoundEH = function(req) {
  95
+    return exports.createInvalidReqEH (
  96
+        exports.INVALID_REQ.VARIABLE_RESOURCE_NOT_FOUND,
  97
+        req);
  98
+};
  99
+exports.handleInvalidReqVariableResourceNotFoundEH = function(req, res) {
  100
+    exports.createInvalidReqVariableResourceNotFoundEH(req).handle(res);
  101
+};
  102
+
  103
+// Invalid Request Invalid Command Method Error Handler
  104
+exports.createInvalidReqInvalidCommandMethodEH = function(req) {
  105
+    return exports.createInvalidReqEH (
  106
+        exports.INVALID_REQ.INVALID_COMMAND_METHOD,
  107
+        req);
  108
+};
  109
+exports.handleInvalidReqInvalidCommandMethodEH = function(req, res) {
  110
+    exports.createInvalidReqInvalidCommandMethodEH(req).handle(res);
  111
+};
  112
+
  113
+// Invalid Request Missing Command Parameter Error Handler
  114
+exports.createInvalidReqMissingCommandParameterEH = function(req) {
  115
+    return exports.createInvalidReqEH (
  116
+        exports.INVALID_REQ.MISSING_COMMAND_PARAMETER,
  117
+        req);
  118
+};
  119
+exports.handleInvalidReqMissingCommandParameterEH = function(req, res) {
  120
+    exports.createInvalidReqMissingCommandParameterEH(req).handle(res);
  121
+};
  122
+
  123
+//-------------------------------------------------------- Failed Command Errors
  124
+//------ http://code.google.com/p/selenium/wiki/JsonWireProtocol#Failed_Commands
  125
+exports.FAILED_CMD_STATUS = {
  126
+    "SUCCESS"                       : "Success",
  127
+    "NO_SUCH_ELEMENT"               : "NoSuchElement",
  128
+    "NO_SUCH_FRAME"                 : "NoSuchFrame",
  129
+    "UNKNOWN_COMMAND"               : "UnknownCommand",
  130
+    "STALE_ELEMENT_REFERENCE"       : "StaleElementReference",
  131
+    "ELEMENT_NOT_VISIBLE"           : "ElementNotVisible",
  132
+    "INVALID_ELEMENT_STATE"         : "InvalidElementState",
  133
+    "UNKNOWN_ERROR"                 : "UnknownError",
  134
+    "ELEMENT_IS_NOT_SELECTABLE"     : "ElementIsNotSelectable",
  135
+    "JAVA_SCRIPT_ERROR"             : "JavaScriptError",
  136
+    "XPATH_LOOKUP_ERROR"            : "XPathLookupError",
  137
+    "TIMEOUT"                       : "Timeout",
  138
+    "NO_SUCH_WINDOW"                : "NoSuchWindow",
  139
+    "INVALID_COOKIE_DOMAIN"         : "InvalidCookieDomain",
  140
+    "UNABLE_TO_SET_COOKIE"          : "UnableToSetCookie",
  141
+    "UNEXPECTED_ALERT_OPEN"         : "UnexpectedAlertOpen",
  142
+    "NO_ALERT_OPEN_ERROR"           : "NoAlertOpenError",
  143
+    "SCRIPT_TIMEOUT"                : "ScriptTimeout",
  144
+    "INVALID_ELEMENT_COORDINATES"   : "InvalidElementCoordinates",
  145
+    "IME_NOT_AVAILABLE"             : "IMENotAvailable",
  146
+    "IME_ENGINE_ACTIVATION_FAILED"  : "IMEEngineActivationFailed",
  147
+    "INVALID_SELECTOR"              : "InvalidSelector"
  148
+};
  149
+exports.FAILED_CMD_STATUS_CODES = {
  150
+    "Success"                   : 0,
  151
+    "NoSuchElement"             : 7,
  152
+    "NoSuchFrame"               : 8,
  153
+    "UnknownCommand"            : 9,
  154
+    "StaleElementReference"     : 10,
  155
+    "ElementNotVisible"         : 11,
  156
+    "InvalidElementState"       : 12,
  157
+    "UnknownError"              : 13,
  158
+    "ElementIsNotSelectable"    : 15,
  159
+    "JavaScriptError"           : 17,
  160
+    "XPathLookupError"          : 19,
  161
+    "Timeout"                   : 21,
  162
+    "NoSuchWindow"              : 23,
  163
+    "InvalidCookieDomain"       : 24,
  164
+    "UnableToSetCookie"         : 25,
  165
+    "UnexpectedAlertOpen"       : 26,
  166
+    "NoAlertOpenError"          : 27,
  167
+    "ScriptTimeout"             : 28,
  168
+    "InvalidElementCoordinates" : 29,
  169
+    "IMENotAvailable"           : 30,
  170
+    "IMEEngineActivationFailed" : 31,
  171
+    "InvalidSelector"           : 32
  172
+};
  173
+exports.FAILED_CMD_STATUS_CODES_NAMES       = [];
  174
+exports.FAILED_CMD_STATUS_CODES_NAMES[0]    = "Success";
  175
+exports.FAILED_CMD_STATUS_CODES_NAMES[7]    = "NoSuchElement";
  176
+exports.FAILED_CMD_STATUS_CODES_NAMES[8]    = "NoSuchFrame";
  177
+exports.FAILED_CMD_STATUS_CODES_NAMES[9]    = "UnknownCommand";
  178
+exports.FAILED_CMD_STATUS_CODES_NAMES[10]   = "StaleElementReference";
  179
+exports.FAILED_CMD_STATUS_CODES_NAMES[11]   = "ElementNotVisible";
  180
+exports.FAILED_CMD_STATUS_CODES_NAMES[12]   = "InvalidElementState";
  181
+exports.FAILED_CMD_STATUS_CODES_NAMES[13]   = "UnknownError";
  182
+exports.FAILED_CMD_STATUS_CODES_NAMES[15]   = "ElementIsNotSelectable";
  183
+exports.FAILED_CMD_STATUS_CODES_NAMES[17]   = "JavaScriptError";
  184
+exports.FAILED_CMD_STATUS_CODES_NAMES[19]   = "XPathLookupError";
  185
+exports.FAILED_CMD_STATUS_CODES_NAMES[21]   = "Timeout";
  186
+exports.FAILED_CMD_STATUS_CODES_NAMES[23]   = "NoSuchWindow";
  187
+exports.FAILED_CMD_STATUS_CODES_NAMES[24]   = "InvalidCookieDomain";
  188
+exports.FAILED_CMD_STATUS_CODES_NAMES[25]   = "UnableToSetCookie";
  189
+exports.FAILED_CMD_STATUS_CODES_NAMES[26]   = "UnexpectedAlertOpen";
  190
+exports.FAILED_CMD_STATUS_CODES_NAMES[27]   = "NoAlertOpenError";
  191
+exports.FAILED_CMD_STATUS_CODES_NAMES[28]   = "ScriptTimeout";
  192
+exports.FAILED_CMD_STATUS_CODES_NAMES[29]   = "InvalidElementCoordinates";
  193
+exports.FAILED_CMD_STATUS_CODES_NAMES[30]   = "IMENotAvailable";
  194
+exports.FAILED_CMD_STATUS_CODES_NAMES[31]   = "IMEEngineActivationFailed";
  195
+exports.FAILED_CMD_STATUS_CODES_NAMES[32]   = "InvalidSelector";
  196
+
  197
+var _failedCommandHandle = function(res) {
  198
+    // Generate response body
  199
+    var body = {
  200
+        "sessionId" : this.errorSessionId,
  201
+        "status" : this.errorStatusCode,
  202
+        "value" : {
  203
+            "message" : this.message,
  204
+            "screen" : this.errorScreenshot,
  205
+            "class" : this.errorClassName
  206
+        }
  207
+    };
  208
+
  209
+    // Send it
  210
+    res.statusCode = 500; //< 500 Internal Server Error
  211
+    res.writeJSONAndClose(body);
  212
+};
  213
+
  214
+// Failed Command Error Handler
  215
+exports.createFailedCommandEH = function(errorName, errorMsg, req, session, className) {
  216
+    var e = new Error();
  217
+
  218
+    e.name = errorName;
  219
+    e.message = "Error Message => '" + errorMsg + "'\n" + " caused by Request => " + JSON.stringify(req);
  220
+    e.errorStatusCode = exports.FAILED_CMD_STATUS_CODES[errorName] || 13; //< '13' Unkown Error
  221
+    e.errorSessionId = session.getId() || null;
  222
+    e.errorClassName = className || "unknown";
  223
+    e.errorScreenshot = (session.getCapabilities().takesScreenshot && session.getCurrentWindow() !== null) ?
  224
+        session.getCurrentWindow().renderBase64("png") : "";
  225
+    e.handle = _failedCommandHandle;
  226
+
  227
+    return e;
  228
+};
  229
+exports.handleFailedCommandEH = function(errorName, errorMsg, req, res, session, className) {
  230
+    exports.createFailedCommandEH(errorName, errorMsg, req, session, className).handle(res);
  231
+};
79  src/ghostdriver/ghostdriver.qrc
... ...
@@ -0,0 +1,79 @@
  1
+<RCC>
  2
+    <qresource prefix="ghostdriver/">
  3
+        <file>errors.js</file>
  4
+        <file>hub_register.js</file>
  5
+        <file>inputs.js</file>
  6
+        <file>main.js</file>
  7
+        <file>request_handlers/request_handler.js</file>
  8
+        <file>request_handlers/router_request_handler.js</file>
  9
+        <file>request_handlers/session_manager_request_handler.js</file>
  10
+        <file>request_handlers/session_request_handler.js</file>
  11
+        <file>request_handlers/shutdown_request_handler.js</file>
  12
+        <file>request_handlers/status_request_handler.js</file>
  13
+        <file>request_handlers/webelement_request_handler.js</file>
  14
+        <file>session.js</file>
  15
+        <file>third_party/parseuri.js</file>
  16
+        <file>third_party/uuid.js</file>
  17
+        <file>third_party/webdriver-atoms/active_element.js</file>
  18
+        <file>third_party/webdriver-atoms/clear.js</file>
  19
+        <file>third_party/webdriver-atoms/clear_local_storage.js</file>
  20
+        <file>third_party/webdriver-atoms/clear_session_storage.js</file>
  21
+        <file>third_party/webdriver-atoms/click.js</file>
  22
+        <file>third_party/webdriver-atoms/default_content.js</file>
  23
+        <file>third_party/webdriver-atoms/deps.js</file>
  24
+        <file>third_party/webdriver-atoms/double_click.js</file>
  25
+        <file>third_party/webdriver-atoms/drag.js</file>
  26
+        <file>third_party/webdriver-atoms/execute_async_script.js</file>
  27
+        <file>third_party/webdriver-atoms/execute_script.js</file>
  28
+        <file>third_party/webdriver-atoms/execute_sql.js</file>
  29
+        <file>third_party/webdriver-atoms/find_element.js</file>
  30
+        <file>third_party/webdriver-atoms/find_elements.js</file>
  31
+        <file>third_party/webdriver-atoms/focus_on_element.js</file>
  32
+        <file>third_party/webdriver-atoms/frame_by_id_or_name.js</file>
  33
+        <file>third_party/webdriver-atoms/frame_by_index.js</file>
  34
+        <file>third_party/webdriver-atoms/get_appcache_status.js</file>
  35
+        <file>third_party/webdriver-atoms/get_attribute.js</file>
  36
+        <file>third_party/webdriver-atoms/get_attribute_value.js</file>
  37
+        <file>third_party/webdriver-atoms/get_current_position.js</file>
  38
+        <file>third_party/webdriver-atoms/get_element_from_cache.js</file>
  39
+        <file>third_party/webdriver-atoms/get_frame_window.js</file>
  40
+        <file>third_party/webdriver-atoms/get_in_view_location.js</file>
  41
+        <file>third_party/webdriver-atoms/get_local_storage_item.js</file>
  42
+        <file>third_party/webdriver-atoms/get_local_storage_keys.js</file>
  43
+        <file>third_party/webdriver-atoms/get_local_storage_size.js</file>
  44
+        <file>third_party/webdriver-atoms/get_location.js</file>
  45
+        <file>third_party/webdriver-atoms/get_location_in_view.js</file>
  46
+        <file>third_party/webdriver-atoms/get_session_storage_item.js</file>
  47
+        <file>third_party/webdriver-atoms/get_session_storage_keys.js</file>
  48
+        <file>third_party/webdriver-atoms/get_session_storage_size.js</file>
  49
+        <file>third_party/webdriver-atoms/get_size.js</file>
  50
+        <file>third_party/webdriver-atoms/get_text.js</file>
  51
+        <file>third_party/webdriver-atoms/get_top_left_coordinates.js</file>
  52
+        <file>third_party/webdriver-atoms/get_value_of_css_property.js</file>
  53
+        <file>third_party/webdriver-atoms/get_window_position.js</file>
  54
+        <file>third_party/webdriver-atoms/get_window_size.js</file>
  55
+        <file>third_party/webdriver-atoms/is_displayed.js</file>
  56
+        <file>third_party/webdriver-atoms/is_enabled.js</file>
  57
+        <file>third_party/webdriver-atoms/is_online.js</file>
  58
+        <file>third_party/webdriver-atoms/is_selected.js</file>
  59
+        <file>third_party/webdriver-atoms/lastupdate</file>
  60
+        <file>third_party/webdriver-atoms/move_mouse.js</file>
  61
+        <file>third_party/webdriver-atoms/pinch.js</file>
  62
+        <file>third_party/webdriver-atoms/remove_local_storage_item.js</file>
  63
+        <file>third_party/webdriver-atoms/remove_session_storage_item.js</file>
  64
+        <file>third_party/webdriver-atoms/right_click.js</file>
  65
+        <file>third_party/webdriver-atoms/rotate.js</file>
  66
+        <file>third_party/webdriver-atoms/scroll_into_view.js</file>
  67
+        <file>third_party/webdriver-atoms/scroll_mouse.js</file>
  68
+        <file>third_party/webdriver-atoms/set_local_storage_item.js</file>
  69
+        <file>third_party/webdriver-atoms/set_session_storage_item.js</file>
  70
+        <file>third_party/webdriver-atoms/set_window_position.js</file>
  71
+        <file>third_party/webdriver-atoms/set_window_size.js</file>
  72
+        <file>third_party/webdriver-atoms/submit.js</file>
  73
+        <file>third_party/webdriver-atoms/swipe.js</file>
  74
+        <file>third_party/webdriver-atoms/tap.js</file>
  75
+        <file>third_party/webdriver-atoms/type.js</file>
  76
+        <file>webdriver_atoms.js</file>
  77
+        <file>webelementlocator.js</file>
  78
+    </qresource>
  79
+</RCC>
84  src/ghostdriver/hub_register.js
... ...
@@ -0,0 +1,84 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+All rights reserved.
  6
+
  7
+Redistribution and use in source and binary forms, with or without modification,
  8
+are permitted provided that the following conditions are met:
  9
+
  10
+    * Redistributions of source code must retain the above copyright notice,
  11
+      this list of conditions and the following disclaimer.
  12
+    * Redistributions in binary form must reproduce the above copyright notice,
  13
+      this list of conditions and the following disclaimer in the documentation
  14
+      and/or other materials provided with the distribution.
  15
+
  16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  20
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+/* generate node configuration for this node */
  29
+var nodeconf = function(ip, port, hub) {
  30
+    var ref$, hubHost, hubPort;
  31
+    ref$ = hub.match(/([\w\d\.]+):(\d+)/), hubHost = ref$[1], hubPort = ref$[2];
  32
+    hubPort = +hubPort;
  33
+    return {
  34
+        capabilities: [{
  35
+            browserName: "phantomjs",
  36
+            maxInstances: 1,
  37
+            seleniumProtocol: "WebDriver"
  38
+        }],
  39
+        configuration: {
  40
+            hub: hub,
  41
+            hubHost: hubHost,
  42
+            hubPort: hubPort,
  43
+            port: port,
  44
+            proxy: "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
  45
+            // Note that multiple webdriver sessions or instances within a single
  46
+            // Ghostdriver process will interact in unexpected and undesirable ways.
  47
+            maxSession: 1,
  48
+            register: true,
  49
+            registerCycle: 5000,
  50
+            role: "wd",
  51
+            url: "http://" + ip + ":" + port,
  52
+            remoteHost: "http://" + ip + ":" + port
  53
+        }
  54
+    };
  55
+};
  56
+
  57
+module.exports = {
  58
+    register: function(ip, port, hub) {
  59
+        var page = require('webpage').create();
  60
+        port = +port;
  61
+        if(!hub.match(/\/$/)) {
  62
+            hub += '/';
  63
+        }
  64
+
  65
+        /* Register with selenium grid server */
  66
+        page.open(hub + 'grid/register', {
  67
+            operation: 'post',
  68
+            data: JSON.stringify(nodeconf(ip, port, hub)),
  69
+            headers: {
  70
+                'Content-Type': 'application/json'
  71
+            }
  72
+        }, function(status) {
  73
+            if(status !== 'success') {
  74
+                console.error("Unable to contact grid " + hub + ": " + status);
  75
+                phantom.exit(1);
  76
+            }
  77
+            if(page.framePlainText !== "ok") {
  78
+                console.error("Problem registering with grid " + hub + ": " + page.content);
  79
+                phantom.exit(1);
  80
+            }
  81
+            console.log("Registered with grid hub: " + hub + " (" + page.framePlainText + ")");
  82
+        });
  83
+    }
  84
+};
344  src/ghostdriver/inputs.js
... ...
@@ -0,0 +1,344 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+Copyright (c) 2012, Jim Evans <james.h.evans.jr@gmail.com>
  6
+All rights reserved.
  7
+
  8
+Redistribution and use in source and binary forms, with or without modification,
  9
+are permitted provided that the following conditions are met:
  10
+
  11
+* Redistributions of source code must retain the above copyright notice,
  12
+this list of conditions and the following disclaimer.
  13
+* Redistributions in binary form must reproduce the above copyright notice,
  14
+this list of conditions and the following disclaimer in the documentation
  15
+and/or other materials provided with the distribution.
  16
+
  17
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  21
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  24
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27
+*/
  28
+
  29
+var ghostdriver = ghostdriver || {};
  30
+
  31
+ghostdriver.Inputs = function () {
  32
+    // private:
  33
+    var
  34
+    _mousePos = { x: 0, y: 0 },
  35
+    _keyboardState = {},
  36
+    _specialKeys = {
  37
+        '\uE000': "Escape",        // NULL
  38
+        '\uE001': "Cancel",        // Cancel
  39
+        '\uE002': "F1",            // Help
  40
+        '\uE003': "Backspace",     // Backspace
  41
+        '\uE004': "Tab",           // Tab
  42
+        '\uE005': "Clear",         // Clear
  43
+        '\uE006': "\n",
  44
+        '\uE007': "\n",
  45
+        '\uE008': "Shift",         // Shift
  46
+        '\uE009': "Control",       // Control
  47
+        '\uE00A': "Alt",           // Alt
  48
+        '\uE00B': "Pause",         // Pause
  49
+        '\uE00C': "Escape",        // Escape
  50
+        '\uE00D': "Space",         // Space
  51
+        '\uE00E': "PageUp",        // PageUp
  52
+        '\uE00F': "PageDown",      // PageDown
  53
+        '\uE010': "End",           // End
  54
+        '\uE011': "Home",          // Home
  55
+        '\uE012': "Left",          // Left arrow
  56
+        '\uE013': "Up",            // Up arrow
  57
+        '\uE014': "Right",         // Right arrow
  58
+        '\uE015': "Down",          // Down arrow
  59
+        '\uE016': "Insert",        // Insert
  60
+        '\uE017': "Delete",        // Delete
  61
+        '\uE018': ";",     // Semicolon
  62
+        '\uE019': "=",     // Equals
  63
+        '\uE01A': "0",     // Numpad 0
  64
+        '\uE01B': "1",     // Numpad 1
  65
+        '\uE01C': "2",     // Numpad 2
  66
+        '\uE01D': "3",     // Numpad 3
  67
+        '\uE01E': "4",     // Numpad 4
  68
+        '\uE01F': "5",     // Numpad 5
  69
+        '\uE020': "6",     // Numpad 6
  70
+        '\uE021': "7",     // Numpad 7
  71
+        '\uE022': "8",     // Numpad 8
  72
+        '\uE023': "9",     // Numpad 9
  73
+        '\uE024': "*",     // Multiply
  74
+        '\uE025': "+",     // Add
  75
+        '\uE026': ",",     // Separator
  76
+        '\uE027': "-",     // Subtract
  77
+        '\uE028': ".",     // Decimal
  78
+        '\uE029': "/",      // Divide
  79
+        '\uE031': "F1",            // F1
  80
+        '\uE032': "F2",            // F2
  81
+        '\uE033': "F3",            // F3
  82
+        '\uE034': "F4",            // F4
  83
+        '\uE035': "F5",            // F5
  84
+        '\uE036': "F6",            // F6
  85
+        '\uE037': "F7",            // F7
  86
+        '\uE038': "F8",            // F8
  87
+        '\uE039': "F9",            // F9
  88
+        '\uE03A': "F10",           // F10
  89
+        '\uE03B': "F11",           // F11
  90
+        '\uE03C': "F12",           // F12
  91
+        '\uE03D': "Meta"           // Command/Meta
  92
+    },
  93
+
  94
+    _implicitShiftKeys = {
  95
+        "A": "a",
  96
+        "B": "b",
  97
+        "C": "c",
  98
+        "D": "d",
  99
+        "E": "e",
  100
+        "F": "f",
  101
+        "G": "g",
  102
+        "H": "h",
  103
+        "I": "i",
  104
+        "J": "j",
  105
+        "K": "k",
  106
+        "L": "l",
  107
+        "M": "m",
  108
+        "N": "n",
  109
+        "O": "o",
  110
+        "P": "p",
  111
+        "Q": "q",
  112
+        "R": "r",
  113
+        "S": "s",
  114
+        "T": "t",
  115
+        "U": "u",
  116
+        "V": "v",
  117
+        "W": "w",
  118
+        "X": "x",
  119
+        "Y": "y",
  120
+        "Z": "z",
  121
+        "!": "1",
  122
+        "@": "2",
  123
+        "#": "3",
  124
+        "$": "4",
  125
+        "%": "5",
  126
+        "^": "6",
  127
+        "&": "7",
  128
+        "*": "8",
  129
+        "(": "9",
  130
+        ")": "0",
  131
+        "_": "-",
  132
+        "+": "=",
  133
+        "{": "[",
  134
+        "}": "]",
  135
+        "|": "\\",
  136
+        ":": ";",
  137
+        "<": ",",
  138
+        ">": ".",
  139
+        "?": "/",
  140
+        "~": "`",
  141
+        "\"": "'"
  142
+    },
  143
+
  144
+    _shiftKeys = {
  145
+        "a": "A",
  146
+        "b": "B",
  147
+        "c": "C",
  148
+        "d": "D",
  149
+        "e": "E",
  150
+        "f": "F",
  151
+        "g": "G",
  152
+        "h": "H",
  153
+        "i": "I",
  154
+        "j": "J",
  155
+        "k": "K",
  156
+        "l": "L",
  157
+        "m": "M",
  158
+        "n": "N",
  159
+        "o": "O",
  160
+        "p": "P",
  161
+        "q": "Q",
  162
+        "r": "R",
  163
+        "s": "S",
  164
+        "t": "T",
  165
+        "u": "U",
  166
+        "v": "V",
  167
+        "w": "W",
  168
+        "x": "X",
  169
+        "y": "Y",
  170
+        "z": "Z",
  171
+        "1": "!",
  172
+        "2": "@",
  173
+        "3": "#",
  174
+        "4": "$",
  175
+        "5": "%",
  176
+        "6": "^",
  177
+        "7": "&",
  178
+        "8": "*",
  179
+        "9": "(",
  180
+        "0": ")",
  181
+        "-": "_",
  182
+        "=": "+",
  183
+        "[": "{",
  184
+        "]": "}",
  185
+        "\\": "|",
  186
+        ";": ":",
  187
+        ",": "<",
  188
+        ".": ">",
  189
+        "/": "?",
  190
+        "`": "~",
  191
+        "'": "\""
  192
+    },
  193
+
  194
+    _modifierKeyValues = {
  195
+        "SHIFT": 0x02000000,   // A Shift key on the keyboard is pressed.
  196
+        "CONTROL": 0x04000000, // A Ctrl key on the keyboard is pressed.
  197
+        "ALT": 0x08000000,     // An Alt key on the keyboard is pressed.
  198
+        "META": 0x10000000,    // A Meta key on the keyboard is pressed.
  199
+        "NUMPAD": 0x20000000   // Keypad key.
  200
+    },
  201
+
  202
+    _currentModifierKeys = 0,
  203
+
  204
+    _isModifierKey = function (key) {
  205
+        return key === "\uE008" || key === "\uE009" || key === "\uE00A" || key === "\uE03D";
  206
+    },
  207
+
  208
+    _isModifierKeyPressed = function (key) {
  209
+        return _currentModifierKeys & _modifierKeyValues[_specialKeys[key].toUpperCase()];
  210
+    },
  211
+
  212
+    _sendKeys = function (session, keys) {
  213
+        var keySequence = keys.split('');
  214
+        for (var i = 0; i < keySequence.length; i++) {
  215
+            var key = keys[i];
  216
+            var actualKey = _translateKey(session, key);
  217
+
  218
+            if (key === '\uE000') {
  219
+                _clearModifierKeys(session);
  220
+            } else {
  221
+                if (_isModifierKey(key)) {
  222
+                    if (_isModifierKeyPressed(key)) {
  223
+                        _keyUp(session, actualKey);
  224
+                    } else {
  225
+                        _keyDown(session, actualKey);
  226
+                    }
  227
+                } else {
  228
+                    if (_implicitShiftKeys.hasOwnProperty(actualKey)) {
  229
+                        session.getCurrentWindow().sendEvent("keydown", _translateKey(session, "\uE008"));
  230
+                        _pressKey(session, actualKey);
  231
+                        session.getCurrentWindow().sendEvent("keyup", _translateKey(session, "\uE008"));
  232
+                    } else {
  233
+                        if ((_currentModifierKeys & _modifierKeyValues.SHIFT) && _shiftKeys.hasOwnProperty(actualKey)) {
  234
+                            _pressKey(session, _shiftKeys[actualKey]);
  235
+                        } else {
  236
+                            _pressKey(session, actualKey);
  237
+                        }
  238
+                    }
  239
+                }
  240
+            }
  241
+        }
  242
+    },
  243
+
  244
+    _clearModifierKeys = function (session) {
  245
+        if (_currentModifierKeys & _modifierKeyValues.SHIFT) {
  246
+            _keyUp(session, _translateKey(session, "\uE008"));
  247
+        }
  248
+        if (_currentModifierKeys & _modifierKeyValues.CONTROL) {
  249
+            _keyUp(session, _translateKey(session, "\uE009"));
  250
+        }
  251
+        if (_currentModifierKeys & _modifierKeyValues.ALT) {
  252
+            _keyUp(session, _translateKey(session, "\uE00A"));
  253
+        }
  254
+    },
  255
+
  256
+    _updateModifierKeys = function (modifierKeyValue, on) {
  257
+        if (on) {
  258
+            _currentModifierKeys = _currentModifierKeys | modifierKeyValue;
  259
+        } else {
  260
+            _currentModifierKeys = _currentModifierKeys & ~modifierKeyValue;
  261
+        }
  262
+    },
  263
+
  264
+    _translateKey = function (session, key) {
  265
+        var actualKey = key;
  266
+        var phantomjskeys = session.getCurrentWindow().event.key;
  267
+        if (_specialKeys.hasOwnProperty(key)) {
  268
+            actualKey = _specialKeys[key];
  269
+            if (session.getCurrentWindow().event.key.hasOwnProperty(actualKey)) {
  270
+                actualKey = session.getCurrentWindow().event.key[actualKey];
  271
+            }
  272
+        }
  273
+        return actualKey;
  274
+    },
  275
+
  276
+    _pressKey = function (session, key) {
  277
+        // translate WebDriver key value to key code.
  278
+        _keyEvent(session, "keypress", key);
  279
+    },
  280
+
  281
+    _keyDown = function (session, key) {
  282
+        _keyEvent(session, "keydown", key);
  283
+        if (key == _translateKey(session, "\uE008")) {
  284
+            _updateModifierKeys(_modifierKeyValues.SHIFT, true);
  285
+        } else if (key == _translateKey(session, "\uE009")) {
  286
+            _updateModifierKeys(_modifierKeyValues.CONTROL, true);
  287
+        } else if (key == _translateKey(session, "\uE00A")) {
  288
+            _updateModifierKeys(_modifierKeyValues.ALT, true);
  289
+        }
  290
+    },
  291
+
  292
+    _keyUp = function (session, key) {
  293
+        if (key == _translateKey(session, "\uE008")) {
  294
+            _updateModifierKeys(_modifierKeyValues.SHIFT, false);
  295
+        } else if (key == _translateKey(session, "\uE009")) {
  296
+            _updateModifierKeys(_modifierKeyValues.CONTROL, false);
  297
+        } else if (key == _translateKey(session, "\uE00A")) {
  298
+            _updateModifierKeys(_modifierKeyValues.ALT, false);
  299
+        }
  300
+        _keyEvent(session, "keyup", key);
  301
+    },
  302
+
  303
+    _mouseClick = function (session, coords) {
  304
+        _mouseMove(session, coords);
  305
+        _mouseButtonEvent(session, "click", "left");
  306
+    },
  307
+
  308
+    _mouseMove = function (session, coords) {
  309
+        session.getCurrentWindow().sendEvent("mousemove", coords.x, coords.y);
  310
+        _mousePos = { x: coords.x, y: coords.y };
  311
+    },
  312
+
  313
+    _mouseButtonDown = function (session, button) {
  314
+        _mouseButtonClick(session, "mousedown", button);
  315
+    },
  316
+
  317
+    _mouseButtonUp = function (session, button) {
  318
+        _mouseButtonClick(session, "mouseUp", button);
  319
+    },
  320
+
  321
+    _keyEvent = function (session, eventType, keyCode) {
  322
+        eventType = eventType || "keypress";
  323
+        session.getCurrentWindow().sendEvent(eventType, keyCode, null, null, _currentModifierKeys);
  324
+    },
  325
+
  326
+    _mouseButtonEvent = function (session, eventType, button) {
  327
+        button = button || "left";
  328
+        eventType = eventType || "click";
  329
+        session.getCurrentWindow().sendEvent(eventType,
  330
+            _mousePos.x, _mousePos.y, //< x, y
  331
+            button, _currentModifierKeys);
  332
+    };
  333
+
  334
+    return {
  335
+        getCurrentCoordinates: function () { return _mousePos; },
  336
+        mouseClick: _mouseClick,
  337
+        mouseMove: _mouseMove,
  338
+        mouseButtonDown: _mouseButtonDown,
  339
+        mouseButtonUp: _mouseButtonUp,
  340
+        mouseButtonClick: _mouseButtonEvent,
  341
+        sendKeys: _sendKeys,
  342
+        clearModifierKeys: _clearModifierKeys
  343
+    };
  344
+};
7  src/ghostdriver/lastupdate
... ...
@@ -0,0 +1,7 @@
  1
+2012-11-18 00:51:11
  2
+
  3
+commit 7c23d7684929bf26deb5be901ba1e5bc51f3e48a
  4
+Author: Ivan De Marino <ivan.de.marino@gmail.com>
  5
+Date:   Sun Nov 18 00:42:32 2012 +0000
  6
+
  7
+    Avoid listing directories into `ghostdriver.qrc`
81  src/ghostdriver/main.js
... ...
@@ -0,0 +1,81 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+All rights reserved.
  6
+
  7
+Redistribution and use in source and binary forms, with or without modification,
  8
+are permitted provided that the following conditions are met:
  9
+
  10
+    * Redistributions of source code must retain the above copyright notice,
  11
+      this list of conditions and the following disclaimer.
  12
+    * Redistributions in binary form must reproduce the above copyright notice,
  13
+      this list of conditions and the following disclaimer in the documentation
  14
+      and/or other materials provided with the distribution.
  15
+
  16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  20
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+// Load dependencies
  29
+// NOTE: We need to provide PhantomJS with the "require" module ASAP. This is a pretty s**t way to load dependencies
  30
+var ghostdriver = {
  31
+        system : require('system'),
  32
+        hub    : require('./hub_register')
  33
+    },
  34
+    server = require('webserver').create(),
  35
+    router,
  36
+    parseURI,
  37
+    listenOn,
  38
+    listenOnIp = "127.0.0.1",
  39
+    listenOnPort = "8080";
  40
+
  41
+// Enable "strict mode" for the 'parseURI' library
  42
+parseURI = require("./third_party/parseuri.js");
  43
+parseURI.options.strictMode = true;
  44
+
  45
+phantom.injectJs("session.js");
  46
+phantom.injectJs("inputs.js");
  47
+phantom.injectJs("request_handlers/request_handler.js");
  48
+phantom.injectJs("request_handlers/status_request_handler.js");
  49
+phantom.injectJs("request_handlers/shutdown_request_handler.js");
  50
+phantom.injectJs("request_handlers/session_manager_request_handler.js");
  51
+phantom.injectJs("request_handlers/session_request_handler.js");
  52
+phantom.injectJs("request_handlers/webelement_request_handler.js");
  53
+phantom.injectJs("request_handlers/router_request_handler.js");
  54
+phantom.injectJs("webelementlocator.js");
  55
+
  56
+// HTTP Request Router
  57
+router = new ghostdriver.RouterReqHand();
  58
+
  59
+// Check if parameters were given, regarding the "ip:port" to listen to
  60
+if (ghostdriver.system.args[1]) {
  61
+    if (ghostdriver.system.args[1].indexOf(':') >= 0) {
  62
+        listenOn = ghostdriver.system.args[1].split(':');
  63
+        listenOnIp = listenOn[0];
  64
+        listenOnPort = listenOn[1];
  65
+    } else {
  66
+        listenOnPort = ghostdriver.system.args[1];
  67
+    }
  68
+}
  69
+
  70
+// Start the server
  71
+if (server.listen(listenOnPort, router.handle)) {
  72
+    console.log('Ghost Driver running on port ' + server.port);
  73
+
  74
+    // If parameters regarding a Selenium Grid HUB were given, register to it!
  75
+    if (ghostdriver.system.args[2]) {
  76
+        ghostdriver.hub.register(listenOnIp, listenOnPort, ghostdriver.system.args[2]);
  77
+    }
  78
+} else {
  79
+    console.error("ERROR: Could not start Ghost Driver");
  80
+    phantom.exit(1);
  81
+}
205  src/ghostdriver/request_handlers/request_handler.js
... ...
@@ -0,0 +1,205 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+All rights reserved.
  6
+
  7
+Redistribution and use in source and binary forms, with or without modification,
  8
+are permitted provided that the following conditions are met:
  9
+
  10
+    * Redistributions of source code must retain the above copyright notice,
  11
+      this list of conditions and the following disclaimer.
  12
+    * Redistributions in binary form must reproduce the above copyright notice,
  13
+      this list of conditions and the following disclaimer in the documentation
  14
+      and/or other materials provided with the distribution.
  15
+
  16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  20
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+var ghostdriver = ghostdriver || {};
  29
+
  30
+ghostdriver.RequestHandler = function() {
  31
+    // private:
  32
+    var
  33
+    _errors = require("./errors.js"),
  34
+    _handle = function(request, response) {
  35
+        // NOTE: Some language bindings result in a malformed "post" object.
  36
+        // This might have to do with PhantomJS poor WebServer implementation.
  37
+        // Here we override "request.post" with the "request.postRaw" that
  38
+        // is usually left intact.
  39
+        if (request.hasOwnProperty("postRaw")) {
  40
+            request["post"] = request["postRaw"];
  41
+        }
  42
+
  43
+        _decorateRequest(request);
  44
+        _decorateResponse(response);
  45
+    },
  46
+
  47
+    _reroute = function(request, response, prefixToRemove) {
  48
+        // Store the original URL before re-routing in 'request.urlOriginal':
  49
+        // This is done only for requests never re-routed.
  50
+        // We don't want to override the original URL during a second re-routing.
  51
+        if (typeof(request.urlOriginal) === "undefined") {
  52
+            request.urlOriginal = request.url;
  53
+        }
  54
+
  55
+        // Rebase the "url" to start from AFTER the given prefix to remove
  56
+        request.url = request.urlParsed.source.substr((prefixToRemove).length);
  57
+        // Re-decorate the Request object
  58
+        _decorateRequest(request);
  59
+
  60
+        // Handle the re-routed request
  61
+        this.handle(request, response);
  62
+    },
  63
+
  64
+    _decorateRequest = function(request) {
  65
+        request.urlParsed = require("./third_party/parseuri.js").parse(request.url);
  66
+    },
  67
+
  68
+    _writeJSONDecorator = function(obj) {
  69
+        this.write(JSON.stringify(obj));
  70
+    },
  71
+
  72
+    _successDecorator = function(sessionId, value) {
  73
+        this.statusCode = 200;
  74
+        if (arguments.length > 0) {
  75
+            // write something, only if there is something to write
  76
+            this.writeJSONAndClose(_buildSuccessResponseBody(sessionId, value));
  77
+        } else {
  78
+            this.closeGracefully();
  79
+        }
  80
+    },
  81
+
  82
+    _writeAndCloseDecorator = function(body) {
  83
+        this.setHeader("Content-Length", unescape(encodeURIComponent(body)).length);
  84
+        this.write(body);
  85
+        this.close();
  86
+    },
  87
+
  88
+    _writeJSONAndCloseDecorator = function(obj) {
  89
+        var objStr = JSON.stringify(obj);
  90
+        this.setHeader("Content-Length", unescape(encodeURIComponent(objStr)).length);
  91
+        this.write(objStr);
  92
+        this.close();
  93
+    },
  94
+
  95
+    _respondBasedOnResultDecorator = function(session, req, result) {
  96
+        //console.log("respondBasedOnResult => "+JSON.stringify(result));
  97
+
  98
+        // Convert string to JSON
  99
+        if (typeof(result) === "string") {
  100
+            try {
  101
+                result = JSON.parse(result);
  102
+            } catch (e) {
  103
+                // In case the conversion fails, report and "Invalid Command Method" error
  104
+                _errors.handleInvalidReqInvalidCommandMethodEH(req, this);
  105
+            }
  106
+        }
  107
+
  108
+        // In case the JSON doesn't contain the expected fields
  109
+        if (result === null ||
  110
+            typeof(result) === "undefined" ||
  111
+            typeof(result) !== "object" ||
  112
+            typeof(result.status) === "undefined" ||
  113
+            typeof(result.value) === "undefined") {
  114
+            _errors.handleFailedCommandEH(
  115
+                _errors.FAILED_CMD_STATUS.UNKNOWN_ERROR,
  116
+                "Command failed without producing the expected error report",
  117
+                req,
  118
+                this,
  119
+                session,
  120
+                "ReqHand");
  121
+            return;
  122
+        }
  123
+
  124
+        // An error occurred but we got an error report to use
  125
+        if (result.status !== 0) {
  126
+            _errors.handleFailedCommandEH(
  127
+                _errors.FAILED_CMD_STATUS_CODES_NAMES[result.status],
  128
+                result.value.message,
  129
+                req,
  130
+                this,
  131
+                session,
  132
+                "ReqHand");
  133
+            return;
  134
+        }
  135
+
  136
+        // If we arrive here, everything should be fine, birds are singing, the sky is blue
  137
+        this.success(session.getId(), result.value);
  138
+    },
  139
+
  140
+    _decorateResponse = function(response) {
  141
+        response.setHeader("Cache", "no-cache");
  142
+        response.setHeader("Content-Type", "application/json;charset=UTF-8");
  143
+        response.writeAndClose = _writeAndCloseDecorator;
  144
+        response.writeJSON = _writeJSONDecorator;
  145
+        response.writeJSONAndClose = _writeJSONAndCloseDecorator;
  146
+        response.success = _successDecorator;
  147
+        response.respondBasedOnResult = _respondBasedOnResultDecorator;
  148
+    },
  149
+
  150
+    _buildResponseBody = function(sessionId, value, statusCode) {
  151
+        // Need to check for undefined to prevent errors when trying to return boolean false
  152
+        if(typeof(value) === "undefined") value = {};
  153
+        return {
  154
+            "sessionId" : sessionId || null,
  155
+            "status" : statusCode || 0, //< '0' is Success
  156
+            "value" : value
  157
+        };
  158
+    },
  159
+
  160
+    _buildSuccessResponseBody = function(sessionId, value) {
  161
+        return _buildResponseBody(sessionId, value, 0); //< '0' is Success
  162
+    },
  163
+
  164
+    _getSessionCurrWindow = function(session, req) {
  165
+        return _getSessionWindow(null, session, req);
  166
+    },
  167
+
  168
+    _getSessionWindow = function(handleOrName, session, req) {
  169
+        var win,
  170
+            errorMsg;
  171
+
  172
+        // Fetch the right window
  173
+        win = handleOrName === null ?
  174
+            session.getCurrentWindow() :       //< current window
  175
+            session.getWindow(handleOrName);   //< window by handle
  176
+        if (win !== null) {
  177
+            return win;
  178
+        }
  179
+
  180
+        errorMsg = handleOrName === null ?
  181
+            "Currently Window handle/name is invalid (closed?)" :
  182
+            "Window handle/name '"+handleOrName+"' is invalid (closed?)";
  183
+
  184
+        // Report the error throwing the appropriate exception
  185
+        throw _errors.createFailedCommandEH(
  186
+                    _errors.FAILED_CMD_STATUS.NO_SUCH_WINDOW, //< error name
  187
+                    errorMsg,                                 //< error message
  188
+                    req,                                      //< request
  189
+                    session,                                  //< session
  190
+                    "SessionReqHand");                        //< class name
  191
+    };
  192
+
  193
+    // public:
  194
+    return {
  195
+        handle : _handle,
  196
+        reroute : _reroute,
  197
+        buildResponseBody : _buildResponseBody,
  198
+        buildSuccessResponseBody : _buildSuccessResponseBody,
  199
+        decorateRequest : _decorateRequest,
  200
+        decorateResponse : _decorateResponse,
  201
+        errors : _errors,
  202
+        getSessionWindow : _getSessionWindow,
  203
+        getSessionCurrWindow : _getSessionCurrWindow
  204
+    };
  205
+};
106  src/ghostdriver/request_handlers/router_request_handler.js
... ...
@@ -0,0 +1,106 @@
  1
+/*
  2
+This file is part of the GhostDriver project from Neustar inc.
  3
+
  4
+Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com / detronizator@gmail.com>
  5
+All rights reserved.
  6
+
  7
+Redistribution and use in source and binary forms, with or without modification,
  8
+are permitted provided that the following conditions are met:
  9
+
  10
+    * Redistributions of source code must retain the above copyright notice,
  11
+      this list of conditions and the following disclaimer.
  12
+    * Redistributions in binary form must reproduce the above copyright notice,
  13
+      this list of conditions and the following disclaimer in the documentation
  14
+      and/or other materials provided with the distribution.
  15
+
  16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  20
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  23
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+var ghostdriver = ghostdriver || {};
  29
+
  30
+/**
  31
+ * This Class does first level routing: based on the REST Path, sends Request and Response to the right Request Handler.
  32
+ */
  33
+ghostdriver.RouterReqHand = function() {
  34
+    // private:
  35
+    var
  36
+    _protoParent = ghostdriver.RouterReqHand.prototype,
  37
+    _statusRH = new ghostdriver.StatusReqHand(),
  38
+    _shutdownRH = new ghostdriver.ShutdownReqHand(),
  39
+    _sessionManRH = new ghostdriver.SessionManagerReqHand(),
  40
+    _const = {
  41
+        STATUS          : "status",
  42
+        SESSION         : "session",
  43
+        SESSIONS        : "sessions",
  44
+        SESSION_DIR     : "/session/",
  45
+        SHUTDOWN        : "shutdown"
  46
+    },
  47
+    _errors = _protoParent.errors,
  48
+
  49
+    _handle = function(req, res) {
  50
+        var session,
  51
+            sessionRH;
  52
+
  53
+        // Invoke parent implementation
  54
+        _protoParent.handle.call(this, req, res);
  55
+