Server Mode¶
With --major-mode server Artemis runs an ‘analysis server’ with a JSON interface for controlling it externally and
reporting what it finds.
In this mode all other arguments except those prefixed by analysis-server-* are ignored, including the URL.
There is a debug view which shows the internal browser, which is shown when the option --analysis-server-debug-view
is given.
The concolic advice mode is documented at Server Mode - Concolic Advice.
The API¶
The server runs on port 8008 by default. This can be changed with the --analysis-server-port option.
Calls to the server are expected to POST a JSON message with the following format:
{
"command": "pageload",
"url": "http://www.example.com"
}
We do not use REST-style URLs to avoid the complications of URL-encoding complex strings like URLs or XPaths.
The command property must always be set, and the rest of the properties depend on which command was used.
There is an echo command which can be used to check the server is running:
curl -w "\n" --data '{"command":"echo","message":"Hello, World"}' localhost:8008
This should return:
{
"message": "Hello, World"
{
Only one command can be sent per request. The server is designed to be blocking; any requests sent while another is still being processed will return an error.
Commands¶
echoUsed for testing. Returns the text provided in the
messagefield. The optionaldelayfield is the number of seconds to delay before sending back the response (integers 0–30 are valid).Send:
{ "command": "echo", "message": "Hello, World", "delay": 1 }
Receive:
{"message": "Hello, World"}
exitShuts down the server.
Send:
{"command": "exit"}Receive:
{"message", "Server is shutting down"}
pageloadLoads a URL in the Artemis browser. The final URL we end up on after redirects etc. is returned.
The optional
timeoutparameter is the number of milliseconds to wait before cancelling the load and returning an error (integers 0–3600000 accepted), 0 implies no timeout.Send:
{ "command": "pageload", "url": "http://www.example.com", "timeout": 5000 }
Receive:
{ "pageload": "done", "url": "http://www.example.com" }
backbuttonUses the browser history to go back one page.
It is an error to call this command before there are at least two pages in the history. Due to an implementation issue, “about:blank” is never accessible via this command.
Send:
{"command": "backbutton"}Receive:
{ "backbutton": "done", "url": "http://www.example.com" }
handlersLists the event handlers registered on the current page. The list returned shows XPath expressions identifying the DOM elements with events, and a list of events attached to each. The special cases “document” or “window” may also be given as an identifier for events registered on those objects.
There must already have been a page load command issued.
Send:
{"command": "handlers"}Receive: (e.g for the handlers.html test case)
{ "handlers": [ { "element": "//a[@id='dom-attr']", "events": ["click"] }, { "element": "//a[@id='js-attr']", "events": ["click"] }, { "element": "//a[@id='listener']", "events": ["click", "focus"] } ] }
It is also possible to specify a filter (by XPath) and receive only the handlers registered on matching elements.
Send:
{ "command": "handlers", "filter": "id('listener')" }
Receive: (e.g for the handlers.html test case)
{ "handlers": [ { "element": "//a[@id='listener']", "events": ["click", "focus"] } ] }
The XPath identifiers returned are Artemis’ internally generated ones and may not match the filter, even if it selects a single element.
clickClicks on an element specified by XPath.
For now then only type of click is a JavaScript-level click, with no option for a GUI click.
N.B. This is now just a special case of the newer
eventcommand.Send:
{ "command": "click", "element": "id(\"clickable\")" }
Receive:
{"click": "done"}There is an optional
methodfield, which allows you to choose the type of click performed. Possible values are:simple(default)Just generates a click event, in the saem way as the
eventcommand would.simulate-jsUses JavaScript events to simulate a user click.
simulate-guiUses GUI events to simulate a click.
N.B. This click is done by clicking the coordinates at the centre of the element. If the element is behind another element or the element bounding box is larger than the clickable/visible area, this command can miss and click the wrong thing.
Send:
{ "command": "click", "element": "id(\"clickable\")", "method": "simulate-js" }
Receive:
{"click": "done"}
eventTriggers a JavaScript event on the element at the specified XPath. (Or custom event; see below.)
N.B. Event names are given as “change” or “focus, not “onchange”, “onfocus”, etc.
Send (e.g. on handlers.html):
{ "command": "event", "element": "id(\"listener\")", "event": "focus" }
Receive:
{"event": "done"}There are also some custom Artemis event types which are not the standard JavaScript events. These are handled separately by Artemis and are not triggered as JavaScript events directly.
So far there is only one implemented: for pressing
Enteron a form field (e.g. to submit the form).Send (e.g. on form-submission.html):
{ "command": "event", "element": "id(\"input-text\")", "event": "ARTEMIS-press-enter" }
Receive:
{"event": "done"}
pageReturns information about the current page (the URL, page title, and DOM statistics).
Send:
{"command": "page"}Receive:
{ "url": "http://www.example.com", "title": "Example Domain", "elements": 12, "characters": 1262 }
The optional “dom” parameter can be set to True to include the entire DOM dump.
Send:
{ "command": "page", "dom": true }
Receive:
{ "url": "http://www.example.com", "title": "Example Domain", "dom": "<html> ... </html>", "elements": 12, "characters": 1262 }
elementReturns the string representation of each element (if any) matching a given XPath.
Send: (e.g. for the click.html test page)
{ "command": "element", "element": "id(\"clickable\")" }
Receive:
{ "elements": [ "<a href=\"\" id=\"clickable\">Click here to add new buttons to the page.</a>" ] }
There is also an optional
propertyfield which will return the string representation of that object property instead.Send:
{ "command": "element", "element": "id(\"clickable\")", "property": "nodeName" }
Receive:
{ "elements": [ "A" ] }
fieldsreadReturns a list of the form fields which have been read by different events since the last page load.
Send:
{"command": "fieldsread"}Receive: (e.g. from form.html test page)
{ "fieldsread": [ { "element": "//button[1]", "event": "click", "reads": [ { "count": 2, "field": "//input[@id='first']" } ] }, { "element": "//button[2]", "event": "click", "reads": [ { "count": 1, "field": "//input[@id='second']" } ] }, { "element": "//button[3]", "event": "click", "reads": [ { "count": 3, "field": "//input[@id='first']" }, { "count": 3, "field": "//input[@id='second']" } ] } ] }
Each “event object” contains the event type triggered and target element (XPath as passed in via the
clickcommand), and a list of the form fields which were read by the handler for that event. Each of these “read objects” contains an XPath to the field and a count of the number of times the field value was read (at a low level in the JavaScript interpreter).
forminputInjects values into form fields and triggers their change handlers. The method of injection can be changed with the optional
methodparameter (see below).Send:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world." }
Receive:
{"forminput": "done"}The valid element types for
fieldareinputandselect.The
valueproperty can be set to a string (as above), integer, or bool. Strings are used when injecting into text fields or select boxes. Integers can be used to inject into a select box by index (sets theselectedIndexproperty to the given value). Booleans are used to inject into inputs with typecheckboxorradio.The allowable combinations of
fieldandvalueare:input(not checkbox or radio)inputwith type checkbox or radioselectString Sets .valueInvalid Sets .valueInt Invalid Invalid Sets .selectedIndexBool Invalid Sets .checkedInvalid For example, the following commands are all valid on the form-injections.html test case:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world." }
This one sets the checkbox to ticked:
{ "command": "forminput", "field": "id('input-checkbox')", "value": true }
When injecting into a select box, the
valueattribute of the appropriateoptionelement must be given, which is not necessarily the text which appears in the UI.:<select id="input-select" > <option value="first" >First Option</option> <option value="second" >Second Option</option> <option value="third" >Third Option</option> </select>
This one selects “Third Option” in the UI:
{ "command": "forminput", "field": "id('input-select')", "value": "third" }
This one also selects “Third Option”, by using the index:
{ "command": "forminput", "field": "id('input-select')", "value": 2 }
The form-injections.html example includes a ‘marker’ element so you can confirm the form input worked:
{ "command": "element", "element": "id('status')" }
{ "elements": [ "<strong id=\"status\">#input-text set to 'Hello, World'</strong>" ] }
There is a
methodfield, which allows you to choose the type of injection performed. Possible values are:injectInject the value into the
.valueproperty (depending on the input type; see above).onchange(default)Inject the value and trigger the
onchangehandler for the form field.simulate-jsUses JavaScript events to simulate a user filling the form field as closely as possible. The support for text inputs is currently much more sophisticated than for checkboxes, radio buttons, and select boxes.
When
simulate-jsis used, an extra optional propertynoblurcan be set to booleantrueto stop the ‘blur’ (de-focus) event being triggered on this element once the injection is complete. This can be useful (for example) to stop auto-complete boxes being hidden when the field is deselected.simulate-guiNot yet implemented.
Send:
{ "command": "forminput", "field": "id('input-text')", "value": "Hello, world.", "method": "inject" }
Receive:
{"forminput": "done"}
xpathEvaluates an XPath query and returns the result.
The result may be a String, Number, Boolean or Node-Set. Node-sets are represented as an array of the string representations of the nodes.
Node-set (all examples on the click.html test case):
{ "command": "xpath", "xpath": "//h1" }
{ "result": [ "<h1>Clickable elements</h1>" ] }
String:
{ "command": "xpath", "xpath": "string(//h1)" }
{ "result": "Clickable elements" }
Number:
{ "command": "xpath", "xpath": "string-length(string(//h1))" }
{ "result": 18 }
Boolean:
{ "command": "xpath", "xpath": "string-length(string(//h1)) > 10" }
{ "result": true }
It is also possible to provide a list of XPaths to evaluate. The result will be a list of the results of each XPath as above:
{ "command": "xpath", "xpath": [ "//h1", "string(//h1)", "string-length(string(//h1))", "string-length(string(//h1)) > 10" ] }
{ "result": [ [ "<h1>Clickable elements</h1>" ], "Clickable elements", 18, true ] }
N.B. Non-matching queries are handled as normal in a browser’s XPath evaluation:
//does-not-exist => [] string(//does-not-exist) => "" boolean(//does-not-exist) => false
An XPath which cannot be evaluated (because it is invalid) will return an error.
windowsizeSet the size of the browser window.
Send:
{ "command": "windowsize", "width": 1024, "height": 768 }
Receive:
{ "windowsize": "done" }
concolicadviceAllows the server to record traces nito a concolic execution tree and return advice about new form field values which can lead to new exploration.
See the Server Mode - Concolic Advice documentation for details.
evaluate-jsEvaluates a JavaScript string on the current page.
Send:
{ "command": "evaluatejs", "js": "document.getElementById('clickable').click()" }
Receive:
{ "evaluatejs": "done" }
setsymbolicvaluesSets the internal symbolic values of variables accessed via
artemisInputBoolean(),artemisInputInteger(), andartemisInputString(). This can be used for testing the internal concolic engine of the platform. For normal testing of web pages theforminputcommand should be used instead for concolic testing.The
valuesparameter is a mapping from variable names (strings) to values, which may be strings, integers or booleans.The
resetparameter is optional, and if set totrue, the internal symbolic value table will be cleared before setting these replacement values.Send:
{ "command": "setsymbolicvalues", "values": { "X": "Hello", "Y": 123, "Z": true }, "reset": true }
Receive:
{ "setsymbolicvalues": "done" }Now a call like the following would update the DOM with the injected symbolic values:
{ "command": "evaluatejs", "js": "document.getElementById('status').textContent = artemisInputString('X') + ' ' + artemisInputInteger('Y') + ' ' + artemisInputBoolean('Z');" }
coverageReturns a report of the line coverage from the executed commands. The line coverage is taken since the server was started, and cannot be reset.
The
reportis a list of reports for each distinct JavaScript source (web page, JS file, etc.). The line-by-line coverage report is human-readable, not in a good machine-readable format. It can be parsed with analyse-coverage.py.The
linescoveredparameter is a list of line numbers which were covered.N.B. A line is considered covered if some interpretation was done on that line. So the close-braces of if statements, else statements, blank lines, and so on will never be considered covered.
Send:
{ "command": "coverage" }
Receive:
{ "coverage": [ { "url": "...", "line": "...", "linescovered": [...] "report": "..." }, { ... } ] }