Skip to content

More developer tools student project

Josh Matthews edited this page Apr 22, 2015 · 7 revisions

Expand the developer tools implementation

Background information: Firefox supports remote developer tools - ie. communicating with an arbitrary server that implements a protocol for exposing information about web content. Servo implements a very basic developer tools server that currently supports executing JS remotely and investigating the DOM tree in the document inspector. We want to expand these capabilities by completing previous work that enables remote logging from web content, and add new capabilities to log HTTP requests and responses to allow for easier debugging of network-related problems in Servo.

Initial step: Build Servo, then email the mozilla.dev.servo mailing list introducing your group and your progress. Run Servo on a webpage with the --devtools 6000 argument, connect to it from a recent version of Firefox (see docs about configuring Firefox for this), and experiment with the document inspector and web consoles. Note how executing the expression console.log("foo") does not cause any message to show up in the FF web console - by opening the FF Browser Console and looking at the output (and reading FF's source code, we know to make the following changes to the ConsoleMsg struct in components/devtools/libs.rs:

  • rename logLevel to level and make it a String
  • rename timestamp to timeStamp
  • add an arguments vector of Strings
  • remove the message field and add the value to the arguments vector
  • add filename, lineNumber, and columnNumber fields

Now add corresponding filename, lineNumber, and columnNumber fields to the LogMessage enum and send fake values that can be adjusted later. The "foo" message from earlier should now appear in the web console!

Subsequent steps:

  • Add an HTTRequest variant to the DevtoolsControlMsg enum in devtools_traits/lib.rs, containing fields for the target url, the method, headers, and the request body. Use the types that are present in the LoadData struct in components/net/resource_task.rs.
  • Add an HTTPResponse variant to the DevtoolsControlMsg enum containing fields for the response headers, status, and body. Use the same types that are present in the Metadata struct in components/net/resource_task.rs.
  • Make the HTTP loader's load function take an optional Sender<DevtoolsControlMsg>. Use the cookies_chan argument as a model. Send HTTPRequest and HTTPResponse messages using this sender at the appropriate times.
  • Create a NetworkEventActor actor in the devtools crate that stores the request and response information transmitted in the new messages. Add a String field to HTTPRequest and HTTPResponse which contains a unique ID that joins them - see Node::summarize for an example of creating this. Associate the unique IDs with the corresponding NetworkEventActor names via a hashtable.
  • Send the networkEvent message when the HTTPRequest and HTTPResponse messages are received. Use the Firefox devtools code (onNetworkEvent) as a reference.
  • Implement the getRequestHeaders, getRequestCookies, getRequestPostData, getReponseHeaders, getReponseCookies, and getResponseContent messages for NetworkEventActor

Other useful information Live packet dumps captured from a Firefox session. This is ideally what the messages that Servo's server sends to Firefox should resemble:

{
  "from": "server1.conn0.consoleActor2",
  "type": "networkEvent",
  "eventActor": {
    "actor": "server1.conn0.netEvent45",
    "startedDateTime": "2015-04-22T20:47:08.545Z",
    "url": "https://aus4.mozilla.org/update/3/Firefox/40.0a1/20150421152828/Darwin_x86_64-gcc3/en-US/default/Darwin%2013.4.0/default/default/update.xml?force=1",
    "method": "GET",
    "isXHR": true,
    "private": false
  }
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "requestCookies",
  "cookies": 4
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "responseStart",
  "response": {
    "httpVersion": "HTTP/1.1",
    "remoteAddress": "63.245.217.43",
    "remotePort": 443,
    "status": "200",
    "statusText": "OK",
    "headersSize": 337,
    "discardResponseBody": true
  }
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "securityInfo",
  "state": "secure"
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "responseHeaders",
  "headers": 9,
  "headersSize": 337
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "responseCookies",
  "cookies": 0
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "eventTimings",
  "totalTime": 798
}

{
  "from": "server1.conn0.netEvent45",
  "type": "networkEventUpdate",
  "updateType": "responseContent",
  "mimeType": "text/xml; charset=utf-8",
  "contentSize": 0,
  "transferredSize": 42,
  "discardResponseBody": true
}
Clone this wiki locally