CSC/ECE 517 Spring 2015 M1503 EDTS
Extending Developer Tools for Servo
Introduction
Rust
Rust is a general purpose, multi-paradigm, compiled programming language developed by Mozilla Research. It is designed to be a "safe, concurrent, practical language", supporting pure-functional, concurrent-actor, imperative-procedural, and object-oriented styles.<ref>http://en.wikipedia.org/wiki/Rust_%28programming_language%29</ref> Being a modern systems programming language focusing on safety and speed, it accomplishes these goals by being memory safe without using garbage collection.<ref>http://doc.rust-lang.org/nightly/intro.html</ref>
Servo
Servo is an experimental project to build a Web browser engine for a new generation of hardware: mobile devices, multi-core processors and high-performance GPUs. With Servo, we are rethinking the browser at every level of the technology stack — from input parsing to page layout to graphics rendering — to optimize for power efficiency and maximum parallelism. Servo builds on top of Rust to provide a secure and reliable foundation. Memory safety at the core of the platform ensures a high degree of assurance in the browser’s trusted computing base. Rust’s lightweight task mechanism also promises to allow fine-grained isolation between browser components, such as tabs and extensions, without the need for expensive runtime protection schemes, like operating system process isolation.<ref>https://www.mozilla.org/en-US/research/projects/</ref>
Background
Remote Developer Tools
Firefox supports remote developer tools - ie. communicating with an arbitrary server that implements a protocol for exposing information about web content. You can use the Firefox developer tools on your desktop to debug Web sites and Web apps running in other browsers or runtimes. The other browser might be on the same device as the tools themselves or on a different device, such as a phone connected over USB.
Project Description
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.<ref>https://github.com/servo/servo/wiki/More-developer-tools-student-project</ref>
Requirement Analysis
Implementation
- 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.
Architecture
enum
Enums are datatypes with several alternate representations. A simple enum defines one or more constants with the same data type. In Rust, an enum can have complex variants though, like a struct. For example, consider an enum 'Shape' with variants 'Circle' and 'Triangle' each of which is a struct.
enum Shape { Circle { center: Point, radius: f64 }, Triangle{ vert1: Point, vert2: Point, vert3: Point } }
A variable of type Shape can be resolved to its appropriate variant by using a 'match'.
fn area(sh: Shape) -> f64 { match sh { Circle(_, size) => f64::consts::PI * size * size, Rectangle(Point { x, y }, Point { x: x2, y: y2 }) => (x2 - x) * (y2 - y) } }
The Servo Developers Tools project has a 'DevtoolsControlMsg' enum which is used to instruct the devtools server to update its known actors/state according to changes in the browser. The current project requires the addition of two new variants to the 'DevtoolsControlMsg' enum, namely 'HTTRequest' and 'HTTResponse'.
Sender<DevtoolsControlMsg>
In Rust, a pipe is used for communication between tasks. A pipe is simply a pair of endpoints: one for sending messages and another for receiving messages(Sender and Receiver). The simplest way to create a pipe is to use the channel function to create a (Sender, Receiver) pair. In Rust parlance, a sender is a sending endpoint of a pipe, and a receiver is the receiving endpoint. A simple channel can be created as follows:
let (tx, rx) = channel(); spawn(proc() { tx.send(10i); }); assert_eq!(rx.recv(), 10i);
In this project, whenever a HTTPRequest or a HTTPResponse is received, we are going to send a new message using a 'Sender' object that could send variants of the type 'DevtoolsControlMsg'. This 'Sender<DevtoolsControlMsg>' objects sends the messages at appropriate times in the HTTPLoader function.
NetworkEventActor
Design Patterns
Actor Model<ref>http://en.wikipedia.org/wiki/Actor_model</ref>
The actor model in computer science is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and determine how to respond to the next message received.
The Actor model adopts the philosophy that everything is an actor. This is similar to the everything is an object philosophy used by some object-oriented programming languages, but differs in that object-oriented software is typically executed sequentially, while the Actor model is inherently concurrent.
An actor is a computational entity that, in response to a message it receives, can concurrently:
- send a finite number of messages to other actors;
- create a finite number of new actors;
- designate the behavior to be used for the next message it receives.
UML Diagrams
Proposed Test Cases
Reference
<references/>