Team JaM (Servo) [2016]

This summer, we will be hacking on Servo, a web browser engine written with Rust. We are looking forward to getting intimate with Rust, a new system programming language, and web browser engines, which are used by most (if not all!) of us who surf the web.

Mentors

Supervisors

October 26, 2016

In our last blog (wow, it’s already been almost a month!) we mentioned a sEcReT bLoG pOsT!
Here is our series on implementing the new Doge API for those are interested in contributing to Servo!:
Part 1: How to implement a new DOM API for Servo
Part 2: How to test a DOM API for Servo
Yesterday … Read more.

October 01, 2016

Today is the last day of RGSoC. We are incredibly sad, and proud of our summer!

Things we did:

Both of us worked on a secret blog post. It will be ready soon!

Things we learned:

A couple failing tests and their reasons:assert_equals: response type is basic expected "basic" but got "default"
- our API for returning responses (ie. process_response) doesn't differentiate between the different types yet, so we need to make that possible to make those tests pass. Josh thinks that FetchMetadata will need to be changed.

assert_equals: Content-Type is text/html; charset=utf-8 expected "text/html;charset=utf-8" but got "text/html; charset=utf-8"
There's a lot of debate what to do with a space.

TODO:

Keep learning.

Improve Fetch so that it passes more tests!

September 30, 2016

Today is the last day of RGSoC. We are incredibly sad, and proud of our summer!
Things we did:
Both of us worked on a secret blog post. It will be ready soon!
Things we learned:
A couple failing tests and their reasons:
assert_equals: response type is basic expected "basic" but got … Read more.

Things we did:

Spent the morning categorizing fetch/api/basic tests. >90% of failing tests were due to fetch is not defined. The remaining two failures were due to assert_equals: Request.text() should decode data as UTF-8 and assert_equals: Response.text() should decode data as UTF-8 expected. In the afternoon fetch got merged into master, so I retested response and basic at that point....now there is a lot of assert_equals: Request.text() should decode data as UTF-8 expected and assert_equals: Response's type is basic expected "basic" but got "default". Started trying to figure out what's wrong with body's text() Looked into request/request-consume.html and /basic/text-utf8.html....not sure how to fix!

Jeena

Started writing a blog post that is a secret yet!

TODO:

We’re having our end of summer party. We’re going to see thousands of swift birds fly into a chimney for the night! So excited.
Things we did:
Body
Body mixin methods are now supported!
Fetch
Fetch method is now supported too!
Malisa
Spent the … Read more.

Things we learned:

Trait object in Rust. Trait objects are the difference between fn foo(object: &Trait) (this is trait object) and fn foo<T: Trait>(object: &T). The former will result in the compiler generating less code, so the compile time will be faster. However, this puts a little more strain during run time, because it will have to check whether the parameter object implements the &Trait. The latter generates more code during compilation because it will create unique functions for each type that implements Trait. This saves time during run time because the functions for each type is already defined. As Josh said "classic tradeoff between time and space!"

Things we did:

Body

Spent the morning (!!) rebasing Body on top of master (did it the hard way using rebase the first time, until Jeena suggested I just reset and cherry-pick my commits on top...the latter way had only a few merge conflicts as opposed to a LOT). And a little rewriting to get things to compile. Still need to implement the BodyTrait for request.rs. More tests are passing now!! Yay :)

Fetch

Hmm, homu tests kept failing. Web platform tests related to cors/ and redirect/ seemed to fail intermittently, so we decided to skip those tests for now.

Package Data Algorithm

The parser for body when MIMEType is "multipart/form-data" is not clearly defined, so I decided to skip it for now.

General

We started writing our end-of-summer blog post. So sad!

Things we learned:

git cherry-pick is sometimes easier than git rebase

git clean -f -d gets rid of untracked files and directories. I used this today right before a git reset.

September 26, 2016

Things we did:
Body
Spent the morning (!!) rebasing Body on top of master (did it the hard way using rebase the first time, until Jeena suggested I just reset and cherry-pick my commits on top…the latter way had only a few merge conflicts as opposed to a LOT). And a little rewriting to … Read more.

September 25, 2016

Things we did:

Finished refactoring (for the most part) and pushed to a temporary branch for the Body API while Jeena adds her changes. I'll probably implement the BodyTrait for dom::request while she does that.

Package Data Algorithm

Added/Refactored the package data algorithm to the temporary branch! And it compiles!

Things we learned:

You can directly access struct fields only if you're in the same file as the struct that you're trying to access. This at first seemed really weird and arbitrary to me, but apparently this turns out to be less of a headache (and fairly reasonable) compared to the way internal field access would be handles in C++ (according to our coach Nick). This is why it sometimes easier to implement a trait for a struct in the same file that the struct is defined (as opposed to, say, the file that the trait is defined).

TODO:

Body (Malisa)

implement the BodyTrait for dom::request. Also, rebase on top of the current master (now that promises and fetch are merged in ^^)

Test Curation

Go through the new tests, and categorize them.

Package Data Algorithm

Figure out how to write FormData() when MIMEType is "multipart/form-data"

Clean up the code

September 23, 2016

Things we did:
Body
Finished refactoring (for the most part) and pushed to a temporary branch for the Body API while Jeena adds her changes. I’ll probably implement the BodyTrait for dom::request while she does that.
Package Data Algorithm
Added/Refactored the … Read more.

Things we did:

Body

Started refactoring consumebody based on feedback and yesterday's planning. Created body.rs and pulled out `consumebodyandrunpackagedata_algorithminto it, and created aBodyTrait`. The project was oddly compiling without complaints for most of the day. I mentioned this to Jeena, who reminded me that I have to list new dom files it in dom/mod.rs......haha. :) I did, and then all my bugs were then revealed upon the next compile. :P

Promise in Fetch

net_traits had changed! So I had to modify the process_response() method to accomodate the changes. It is more secure now as it allows the fetched data to be filtered. Filter exists to protect sites from having their data stolen by other sites.

Package Data Algorithm

I implemented(though no guarantee it works :wink:) Json(), Blob(), and part of FormData().

September 22, 2016

Things we did:
Body
Started refactoring consume_body based on feedback and yesterday’s planning. Created body.rs and pulled out consume_body and run_package_data_algorithm into it, and created a BodyTrait. The project was oddly compiling without complaints for most of the day. I … Read more.

TODO:

Body (Malisa)

Fix code based on jdm's feedback and refactor.

Test Curation

Go through the new tests, and categorize them.

Package Data Algorithm (Jeena)

We decided that I should work on implementing the rest of the package data algorithm. This decides what to do given a Body, depending on its type (a text, json, and etc). Malisa already implemented text, so that's great! Malisa will focus on going through review comments from her recent PR, and refactoring consume_body and making it into a public function. That way, it can be called by both Request and Response. At this moment, consume_body is customized for Response specifically, and it will be redundant to do the write the same function for Request.

September 21, 2016

Things we did:
Body
Submitted PR last night for dom::Response’s Body::text function. Got back some feedback. Spent some of this afternoon planning the next steps.
Blog
I (Malisa) spent some time writing my Strange Loop blog….will try to do some more coding … Read more.

Things we did:

Ms2ger implemented OpenEndedDictionary! This is what will allow more Headers/Request/Response tests to pass. Woohoo!

So I modified our Headers and Request APIs to adapt to this change. I fought with the borrow checker a lot today, but overall, it was successful. Thanks rustc!

Body

Got dom::Response's Body text() function to the point that it compiles, but additional tests are not passing. I keep getting the same error Promise is not defined in testharness.js.

Things we learned:

When T doesn't derive clone, or has a clone implementation, the compiler makes another reference when .clone() is called to a &T, ending up with &&T. When .clone() is called, the compiler derefs &T to T, realizes T cannot be cloned, and so it creates a clone to the reference, hence creating a double reference.

TODO:

Promise in Fetch

Go through failing tests and figure out what I can fix.

Test Curation

Go through the new tests, and categorize them.

OpenEndedDictionary in DOM

Is it time for a PR?

Body

Figure out whether I have a bug. Ask jdm. Then submit PR.

September 20, 2016

Things we did:
OpenEndedDictionary in DOM (Jeena)
Ms2ger implemented OpenEndedDictionary! This is what will allow more Headers/Request/Response tests to pass. Woohoo!
So I modified our Headers and Request APIs to adapt to this change. I fought with the borrow checker a lot today, … Read more.

September 14, 2016

Day 50! Today was a good day. We listened to our mentor Josh give a great talk about Optimizing your project for contribution. As mentees, we really appreciate all the work that's put into making Servo accessible to beginners.

Things we did:

Promise in Fetch

So yesterday, we found that JSCompartment::wrap had a parameter with a null pointer, which was the reason Servo was crashing. Josh recommended looking at dom/testbinding.rs to see how JSAutoCompartment is used, and to copy it in fetch.rs. After a little bit of wrestling with fetch.rs (because I mistakenly looked at the wrong code), fetch, at least for now, works!

Some more explanation on JSCompartments is at the Today We Learned section. What was happening yesterday with the null pointer was that promise didn't enter any compartment, because JSAutoCompartment::new() wasn't called. promise had not entered any compartment, and therefore, when SpiderMonkey (JS Engine) called JSCompartment::wrap(), which would take a JSContext to the compartment of a JSObject, a null pointer was given. Apparently in order to enter a compartment, JSContext has to already have entered a compartment. And that's why Servo crashed!

We had been doing systems programming for two months, and this was our first time encountering a null pointer (which was in C++ code). Nick said that this shows how safe Rust is, because Rust would not have compiled in the first place. I haven't programmed in C++, but it must be annoying if a code compiles and so much time could pass until you find a memory pointer bug.

I still didn't get a lot of code-writing done, but I have a better idea of where I'm headed now. I was unsure how closely I should be following the spec for utf-8 decoding. I asked jdm, and it turns out the answer is "just closely enough" (my own words). So that's good, and I think I'm starting to understand how to not get super caught up in spec-reading loops of infinite link-following. It also turns out I can make use of the encoding crate, which I believe means a lot of the actual decoding part has already been written for me.

Things we learned:

Spider Monkey specific: What is JSAutoCompartment? JSAutoCompartment helps a JSContext to enter a compartment, and leave the compartment when it is out of scope.

Spider Monkey specific: What is a Compartment? Every JSContext has a current Compartment, but it won't enter its current compartment until JSAutoCompartment::new() is called. In a browser, one tab (one window) will have at least one compartment. Two tabs will have at least two compartments. Compartment is important for security, because there can be little cross-over that will be strictly controlled. You wouldn't want data jumping back and forth between different compartments.

Things we did:

On Friday, wrapping Rc<Promise> with Trusted didn't work. Over the weekend Josh pushed another commit to enable Trusted<Promise> and TrustedPromise::root() that will return a Rc<Promise>. On Sunday, I encountered two borrow check errors:

process_response requires &mut self as a parameter (not mut self). When I try to get the root of TrustedPromise, it throws an error saying "cannot move out of borrowed content”. lines 122, 124, 136, and 138

the root() of TrustedPromise requires self parameter. In line 101, with let context = fetch_context.lock().unwrap(); which is type MutexGuard, which derefs to &T. When we try to access the Rc<Promise> via context.fetch_promise.root(), the compiler throws a borrow error.

That helped me learn that Fetch isn't working :scream:. I started debugging (which means, me = stressed out) and learned a few things:

metadata that is used for process_response looks good. It's Ok(_) and has the fields that look not incorrect.

After promise is taken from FetchContext through self.fetch_promise.take(), no other line is called... WEIRD. WHY. Well, luckily, I was working at the Mozilla Office, and three(!) people helped me debug. Special thanks to @sanxiyn, @fitzgen, and @jimblandy.

Frame is older with higher frame number, i.e. frame #6 is called before frame #5.

frame #6 shows that to_jsval was called. This in turn calls JS_WrapValue in frame #5. This in turn calls JSCompartment::wrap in frame #4.

JSCompartment::wrap has a parameter that is this=&0x0. 0x0 is a null pointer!!! We have a memory-unsafe code here!!! Woohoo!

Body

Read the spec and some more about Unicode encodings in order to understand the UTF-8 decoder. Wrote a little code. Progress was slow due to being sick today.

Things we learned:

When you write . after an object, it automatically derefs! For example, if I do fetch_context.lock(), I'm derefing fetch_context then applying the lock() method.

assigning different types to the same binding name (via let statements) seems to be acceptable practice, at least in some contexts.

0x0 is the synonym to null pointer in C++! If your stack backtrace includes 0x0 that's probably not something you wanted :)

When debugging Servo, you can use the --debug tag, i.e. ./mach run -d ~/src/fetch_example.html --debug. Servo uses lldb debugger by default.

You can set a breakpoint, for example, if you want the code to pause when it calls rust_panic function, you can write b rust_panic<ENTER>run.

While you're at the breakpoint, (or maybe some other time too but I'm not too sure) you can type bt which will print all the backtrace! COOL.

Rc and Trusted has to maintain a 1:1 relationship, and therefore, Trusted should not have a &self parameter because that could break that 1:1 constraint. In Servo's promise, Rc counts the references, and therefore TrustedPromise has to be connected to the one and only Rc<Promise>, because otherwise, the reference count will be incorrect.

TODO:

September 10, 2016

Things we did:

Promise in Fetch

Wrote process_response method. I think the remaining relevant FetchResponseListener methods are process_response_eof (invoked when fetching response is complete) and process_response_chunk (invoked when fetching response body). But process_response_eof requires response trailer support, which is not implemented, and process_response_chunk can probably wait until the response body is implemented.

Turns out when Josh said to create FetchContext later when it's necessary, he meant literally creating it further down in the method (like physically located further down). Haha oops! I started working on creating FetchContext!

Body

Started implementing the Body functions without ReadableStream. The spec refers to streams a lot, but servo doesn't implement ReadableStream, so I am trying to figure out how to write things correctly using Vec instead. Set up skeleton code for implementing text() for dom::Request and dom::Response. Then dug into dom::Response's text(), which led to writing bits of consume_body(), run_package_data_algorithm(), and utf8_decode().

Things we learned:

In order to use Promise::maybe_resolve_native() and the like, it needs a JS Context parameter. JS Context can be obtained through self.global().r().get_cx(). JSContext is a context in which JS can be invoked, and is required by APIs that interact with the JS engine (or it can use a JSRuntime argument). It's confusing to me, but for now, I'll just think of it as a connector to the JS world! (probably not 100% accurate).

vec.drain(..3); removes the first 3 elements of a vec.

TODO:

September 09, 2016

Things we did:

Yesterday, we went to PDX Rust meetup, which was great! A lot of people visiting Portland for RustConf showed up, so it was lovely. Nick Cameron talked about common Rust patterns and a repo to catalogue them. Jamey Sharp talked about Corrode, a software that translates C source files to Rust source files using Haskell(!).

Today we had a monthly meeting with everyone, and it was gooood. Special thanks to Scott for the pep talk! Also, we picked and ate figs from the fig tree by Jeena's home as a break.

Promise in Fetch

Today was indeed a different day! I started working on implementing the FetchResponseListener. FetchResponseListener is invoked when (I think) the network level fetch gets some data back. For example, a method in FetchResponseListener is process_response, which will update the response object with the data it got back from fetching.

Josh suggested not worrying about the FetchContext, which will be the struct to hold promise and response together, until later. Creating the FetchContext will require a lot of wrappings.

The fetch listener (FetchContext) has to be Arc<Mutex<T>>. Inside FetchContext, there will be response_object with type Response and promise with type Rc<Promise>. Both of them will need to be wrapped with Trusted to be shared across threads safely.

I think Response should be wrapped wtih DOMRefCell to allow inner mutability, but we shall see. response_object has to be rooted as well, so it will be Root<Response> type. Josh said that since FetchResponseListener will be implemented on FetchContext, calling self.response.root() will obtain a Root value in the callbacks that can be manipulated like usual.

promise is Rc<T> so we will need a method that will pull out Rc from Trusted, like self.response.root() would.

Body

Wrote step 34 of Request constructor to extract Body contents. The extract body method still doesn't use ReadableStream so I'm not sure if it will need to be rewritten.

Step 7.3 of Response

Things we learned:

The difference between Mutex types and regular-ol'-mutable-rust-variables. Both only allow mutation of their data one thing at a time, through either & mut or for mutex lock() and unlock(). What makes Mutex special? It is specifically designed for sharing across threads (often used in conjunction with Arc), whereas regular mutable borrow is not. So, only one thread can safely access the same data at one time. On the other hand, regular-ol'-& mut will not be allowed by the borrow checker if you try to use it across threads.

A whole lot about network-level fetch! Network level fetch is the communication with the core resource thread that invokes fetch algorithms, as described in the spec. There are a couple Servo parts that already use the network-level fetch: XMLHttpRequest and script.

Rc<T> is not thread-safe, but Trusted<T> is, like in Trusted<XMLHttpRequest>.

September 08, 2016

Things we did:

Promise in Fetch

I feel like I didn't make much progress today. I've been looking at how XHR is implemented the whole day, and couldn't understand it very much :disappointed: What I get is that there needs to be an object (probably FetchContext) that will hold the intermediate Response, and communicate with Promise to get the status of fetch. Hopefully tomorrow will be different!

Body

Started to write the extract-body function until I realized it's already been written in XHR.

Moved onto more of the Body logic. Not sure how ReadableStream will be dealt with. I feel like a lot of what I'm doing will cross tracks with what Jeena's doing. We'll see...!

Things we learned:

We went to the monthly Rust meetup today. We learned about some patterns we should and shouldn't do, a shout-out to clippy, and a C to Rust converter (wow!). We saw a lot of the Rust community in person (they flew in from around the world for the upcoming RustConf this weekend), so it was pretty exciting!

September 07, 2016

Yesterday was Labor Day, so we celebrated it by not working! Woohoo! Malisa is traveling back today, so I (Jeena) worked alone today.

Things we did:

Promise in Fetch

jdm is back! He rebased his promises branch! :clap: The rust compiler still panics instead of throwing error as it uses the older rust version, but that's ok! I can work around it.

It turns out there's a lot more to do with implementing promise in fetch so I spent the day trying to understand what I need to do. Roughly, there are two things I can do:

figure out how to reject/resolve Promise in fetch. Promise::maybe_resolve_native is probably a better choice than Promise::maybe_resolve because they take regular DOM objects. This seems partially dependent on the next thing.

implement FetchResponseListener in fetch.rs. This turns out to have a lot more pre-requisite infrastructure! fetch.rs needs a FetchContext struct that will store the intermediate fetch. XMLHttpRequest is done very similarly to fetch, so I should look into how XHR is implemented in Servo. How XHR implements FetchResponseListener is here.

Things we learned:

Promise doesn't have to be rooted! Whaaaat. jdm says "Rc would usually be unsafe but Promise is designed in such a way that it's safe, whereas Rooted would be incorrect." Whaaaat? I don't even understand! We'll find out the reason later...

Things we did:

When Fetch.webidl and window.rs/workerglobalscope.rs state that fetch() returns a void, and fetch() does return a void, it compiles.

When Fetch.webidl and window.rs/workerglobalscope.rs state that fetch() returns a void, but fetch() returns Promise, it compiles. This is strange because the compiler should throw a type mismatch error.

When Fetch.webidl or window.rs/workerglobalscope.rs state that fetch() returns a Promise, and fetch()does return Promise, compiler fails with this error.

This rust bug is fixed with the latest nightly which Servo uses. When I rebase jdm:promises on top of the latest servo:master, a lot of conflicts happen and I'm not sure how to resolve them as I'm unfamiliar with the changes. I tried a few approaches (not really organized…) and they all have failed

Things we did:

Categorized the tests! I haven't filed the issues yet, but it boils down to roughly two large groups:

"Promise is not defined": While the test messages are saying promise is not defined, these tests are in fact related to body. Body has a few methods that return Promise.

"xxxxdict is not iterable": OpenEndedDictionary needs to be implemented. What Nick said about this: "OpenEndedDictionary isn't supported in HeadersInit, bindings glue tries to convert the object into something that is supported in HeadersInit. The object is not a Headers object, so that doesn't work. Then the glue code tries to treat it as a Sequence. However, it is not an iterable sequence, so it throws the error you're seeing."

There are a few notes:

Each API has a -idl.html test file that are currently timing out. I'm not exactly sure what they do, but it looks like once webidls are fully implemented, these tests will pass.

Some subtests related to stream like readableStreamfail. I'm not sure if stream is something we can implement or is already implemented. Will have to ask someone knows more about this.

Response is currently throwing an error about network error code. Malisa will be working on this!

Response

PR is finally ready to be merged (or so we thought), but Jeena discovered a test which is failing which should be passing, so I'm fixing that up.

Body

Tried to understand how/where I should be implementing Body. Decided to start with writing body's extract method.

Things we learned:

In JavaScript there is a distinction between for ... of loops and for ... in loops. E.g.

In Python, for x in foo is the same as in JS, for (x of foo). In this case, x is the object you ultimately want to view or manipulate.

In Python, for x in foo.keys() is the same as in JS, for (x in foo). In this case, x is the key to the dictionary you might what to iterate over.

TODO:

Response

Figure out how to encode StatusCode 0 as an Enum, which is not supported currently.

August 30, 2016

Things we did:

I rebased Fetch implementation on top of jdm's branch, and tried to use Promise in fetch(). Strangely, it's causing the Rust compiler panics unexpectedly. I'm not sure how to move forward…

Test Curation (Jeena)

Haven't started on this yet. As I'm lost about Promise in Fetch, I'll work on this first.

Response

Still fixing things. Currently in git rebase hell.

Things we learned:

By doing let hello = b"hello";, an array is created. An array has a static length. So in our Headers code, we ended up making unnecessary transformations here. We wrote combined_value.push(b","[0]); which means, "create an array that has length of 1, and whose only element is a comma byte. Then, take the first element of it and add that to combined_value. We can improve this line by writing combined_value.push(b',');

August 26, 2016

Things we did:

I wrote the algorithm to send the fetch message to the resource thread (net_traits).

It looks like the parts I can do right now are mostly done, but it needs double checking!

Things we learned:

Closures! We went to Portland's Papers We Love meetup yesterday and learned about Garbage Collectors. It seems like with JS closures, sometimes you might have to move stack-created objects to the heap. Interesting!

TODO:

Promise in Fetch

implement the Promise return value for fetch() on top of jdm's branch

Test Curation

curate the failing tests and opening an issue for each category so that others can pick up where we left if we don't finish implementing fetch, i.e. tests that fail because of Promise, because of OpenDictionary, etc.

Things we did:

Fetch

Set up the skeletons for Fetch. It was a tricky process. Fetch is defined in WindowOrWorkerGlobalScope.webidl which is a newer addition to the spec and was not present in Servo. I had to add it to Servo, and WindowOrWorkerGlobalScope is not a interface object, so no bindings were created. The compiler told me that dom/window.rs and dom/workerglobalscope.rs had to implement Fetch(). So what we decided to do is have a script/fetch.rs where the Fetch method will live, and have dom/window.rs and dom/workerglobalscope.rs delegate the Fetch method to script/fetch.rs.

Response

Ended up having to replace instances of RawStatus (which takes a utf-8 encoded Cow-str) in Servo's codebase with (u16, Vec<u8>), which is not UTF-8-dependent. I spent the whole day re-building and finding new places in the codebase which were affected by this change, fixing, and re-building again! Finally the relevant test is passing though :)

Things we learned:

Don't spend too much time trying to predict the repercussions of a change in your Rust code. (I do this a lot - Malisa) Often-times the Rust compiler will tell you what those repercussions are, and save you a lot of time, even though you might get surprised by some unexpected errors while building your project!

TODO:

Fetch

It seems like a huge chunk of Fetch is already implemented in net/fetch/method.rs. Figure out how to wrap script/fetch.rs around net/fetch.

Response

update tests, clean up code, and submit the PR already!

Miscellaneous

Publish a blog post about move, clone, and copy! (Jeena)

Before Josh goes on a vacation, ask him what we should work on next week.

August 24, 2016

Things we did:

PR sparked some discussion… This might take a bit longer to resolve. Tried to implement header values to be stored as Vec<Vec<u8>> in which the inner vector is one header value. Not sure how this will mesh with hyper::header::Header existing methods. (Or, how do I separate the different header values? Will the comma have to be added as a separate vector?)

Fetch

Started working on this, and encountered some ~issues~ challenges! See TODO.

Response

Still dealing with wpt test errors. Fixed one (adding dummy argument to constructor so it takesthe right number of arguments), still dealing with a UTF-8 conversion error on one of the tests.

Things we learned:

if you want to import the latest changes in a file from a different branch to your current branch:
git checkout remote-name/branch /path/to/file

TODO:

Fetch

It looks like fetch requires WindowOrWorkerGlobalScope which is not implemented yet. Hear what Josh has to say, and do that!

Response

Submit the PR once tests pass.

Start trying to understand the work that would go into implementing the body APIs, working on top of jdm's Promise branch (Malisa)

Things we did:

Submitted a PR for updating DOM Headers. Making more tests pass is fun!!!

Response

Finished up implementing dom::Response. Now dealing with wpt test errors.

Things we learned:

Fetch requests originate in the script thread via a JavaScript function. The request gets sent to the dom objects (e.g. dom::Request) and are sent to the resource thread using net_traits::CoreResourceMsg. The resource thread calls the actual HttpRequest. The response is sent back to the script thread and the original Promise is resolved. Yay! This is just a broad overview...

TODO:

Fetch Method (Jeena)

Read about fetch. Decided to start working on fetch (one of jdm's suggestions). He wrote:
"Start working on the actual fetch() API, focusing on the code that deals with the arguments and initiating the request and ignoring the return value for now." At this moment, I won't have to worry about Promise because "there's enough work that goes into dealing with the arguments to the function and initiating the request that the promise-related bits can be done separately and subsequently."

Things we did:

Got completely confused about what I'm supposed to do next. Gave up trying to reconcile the spec, the multiple hyper::header::Headers objects, and the nuances of implementing for Servo (for now).

Focusing on just writing the Response API as though I only have one version of hyper::header::Headers in dom::Headers...

Things we learned:

Threads vs processes (thanks wiki!): In the operating system, two "processes" do not share memory. A process can contain multiple "threads" which share memory and other resources.

This is rather relevant to the whole multiple-references-to-the-same-object problem. You need to be aware of whether the references exist in different processes (if so, you can't use the Rc or Arc types, which are for sharing within a process).

TODO:

Response API:

Work on the constructor while figuring out what to do next

Headers Iterable

Continue implementing parse

Refactor iterable implementation

August 15, 2016

Things we did:

Submitted PR to wrap hyper::header::Headers in Rc. This solution may or may not work for the Response API, however, because Rc doesn't work across threads. Instead of manipulating the same object in multiple places, I might end up having to just work with one version of hyper::header::Headers, or replace Rc with Arc.

Things we did:

Fought with the borrow checker the whole day. Implemented clone for net_traits::response::Response and dealt with side-effects of using internal Rc types... x_X

Request API

Decided not to file a spec issue, but clarified the reasoning for the additional step in request.rs in the comments.

Made the code more readable, and removed unnecessary parts.

jdm gave me the permission to squash! Woohoo! Merge is near.

Things we learned:

Parentheses are useful! Long story short, wrapping parentheses around (*gadget1.owner) applies the deref * to just gadget1.owner, which is just what I needed. :)

Reflog is what git uses to keep track of updates to the tip of branches, including those that are invisible on git log! This acts as a great safety net. For example, if you want to undo git rebase, you can find the HEAD of pre-rebase, and git reset --hard to that HEAD.

You cannot modify a field that is in a borrowed context. Read more about it in our blog post.

TODO:

Response API:

Deal with current build errors (now the side-effects of wrapping headers with Rc and RefCell are appearing in places like fetch/methods.rs, uh oh)

And then modify net_traits::request::Request and dom::headers as well......

Implement JSTraceable for RefCell in dom::Headers

And then finally work on dom::Response! >:-|

Request API:

If merge happens, start working on making Headers iterable based on jdm's PR.

August 11, 2016

Things we did:

Spent most of the day trying to figure out how to best make references between objects within the Response struct.

Request API

Turns out I had to debug the crap out of Request, not Headers!

Fixed a bug. More in depth description below.

More tests are passing! I updated the expected test results.

Things we learned:

How to use reference-counted boxes: Rc<>. They are a way to refer to the same internal object in multiple places. Different from RefCell, which I believe is more of a way to provide mutability of already-borrowed objects.

When debugging a Rust code, you can print the memory address of the object (in this case, x) through: println!("{:p}", &x);

Approach debugging as if performing a scientific experiment. Do you have a hypothesis where it might be breaking? Sprinkle some print statements in the code, or set breaking points in the debugger. Study the results. Can you find a pointer that would lead to the next hypothesis? Repeat! And don't get frustrated!

TODO:

Response API:

Update net_traits::Response and net_traits::Request and dom::headers::Headers to wrap Rc<> around their internal hyper::header::Headers objects. That way they will be clonable into reference-counted boxes.

After that hopefully I can actually do work on the Response constructor....fingers crossed...

Things we did:

Had our monthly meeting with everyone! Everyone is doing well. :D

Blast from the past! Back to Headers API.

With the help of Stefan and the rust playground, we realized there were bugs in the is_field_content and Append functions in the Headers API. After fixing these, more of the Headers API tests passed! Oops...

Response API/CodegenRust

Received feedback on bindings generator PR. Once merged in, these changes will allow me to move forward with Response WebIDL implementation.

ASCII is limited to only 128 characters, via a 7-bit character set (so, fits in one byte). UTF-8 is flexible, on the other hand, and can represent characters that require between 1 and 4 bytes. The first 128 characters are the same for ASCII and UTF-8. UTF standards encode the "code points" as defined in Unicode.

This is useful for us to know because we are often converting between ByteString types, which are basically sequences of 8-bit unsigned integers, and characters or Strings. Many of the specs we have to follow reference these encodings. Knowing hexadecimal representation of characters is also useful.

Things we did:

Met with Stefan who showed us some useful tools for looking at Requests/Responses/Headers and also cleared up some questions which had been bugging us.

Things we learned:

dom::bindings::js::MutNullableHeap allows lazy construction of objects (they can be initialized only when you need them)

The cache-control header "directives control who can cache the response, under which conditions, and for how long".

Also learned about cookies from Stefan. Plus neato command-line tools like zsh-autosuggestions and zsh-syntax-highlighting. Also Charles for web debugging.

We asked Stefan about where to find the actual code that makes the HttpRequest to the remote server. The ultimate goal of all this code we're writing is to make an HttpRequest (well, one of the goals), yet the code we're writing seems to dance around that very topic while never actually making the call to the remote server. So this helped clarify things a bit!

Continued working on Constructor. Currently, up to step 15 is compiling successfully. A draft up to step 24 is written.

Things we learned:

There are different types of references in Rust. one of them is &, but you can also have "user-defined custom smart pointers" or wrappers with particular behavior for references, like Ref and RefCell. A helpful explanation is here and here.

You can customize the type name in a use statement. For example, instead of writing use hyper and writing hyper::header::Headers throughout the code, you can use use hyper::header::Headers as HyperHeaders and use HyperHeaders in the code body.

July 28, 2016

Things we did:

Wrote a couple helper methods for finding associated and current url, given a url list.

Started writing constructor step 13.

Headers API

Finished up the remaining functions defined in the webidl. My job was made easier because I don't need to implement iterable<ByteString, ByteString> just quite yet.

Things we learned:

Even though the result of the two code blocks below are the same in practice, it's only due to the rust optimizer.

This first version only ever deals with one memory location on the stack
let mut valid_name = something;
valid_name = something_else;

This second version instructs Rust to create two memory locations for each valid_name. Only due to the Rust optimizer does the computer realize that it can reuse the same spot.
let valid_name = something;
let valid_name = something_else;

When returning a reference to a RefCell, wrap the content with Ref which can be done through Ref::map.

July 26, 2016

Things we did:

Realized that the hyper::header::Headersset_raw() and get_raw() act as though there is only one entry for a given unique header name.

Spent much of the day understanding the consequences of this (do we re-write our Headers append() method or re-write hyper::header::Headers?), piecing together instructions from various specs, and planning the next steps --> Decided to go with the current hyper::header::Headers implementation.

Currently re-working the append() method and other Header API functions.

Things we learned:

if let is handy if you want to match for only certain cases. For example, following code snippets are the same.

July 22, 2016

Things we did:

Request API

Turns out there is a Request struct already written in Servo. But the names it uses are different from what the codegen generates from the webidl. So I have to write Into implementation to allow translation between the two.

Completed writing Into implementation.

Headers API

Worked on filling in the constructor for the Headers API, following the spec.

Things we learned:

Trace Garbage Collection

In a garbage collected language (such as JavaScript and Python, but not Rust), GC manages the memory by freeing it when the memory occupant is no longer in use. Whenever a new object is created, it is done so through GC and GC will add to its set of objects created.

Once in a while, GC will be triggered, probably through the danger of memory running out. GC is expensive, and therefore, it should not be triggered too often. When GC is triggered, it traces memory, checking which objects are referenced, in other words, still in use. Tri-color marking is the one we learned about, and its wikipedia page provides an excellent summary.

Long story short, GC has the ability to compare the sets of objects created and objects that are still used. GC will free the memory occupied by whatever is in the difference.

July 20, 2016

Things we did:

Addressed the feedback that we missed yesterday, and new feedback we received today.

We got an approval from Josh! Woohoo!

Started working on our next goals. Malisa will continue working on headers, and Jeena will start working on request.

Things we learned:

git rebase -i <remote>/<branch> allows you to squash the commits between the current HEAD and the HEAD of <remote>/<branch>. If you are on local features branch and know that local master is untouched, you can git rebase -i master.

July 15, 2016

Things we did:

Submitted PR#2 for code review, the append method for the Headers API. The code compiles on our machines locally but seems to fail Travis CI on github. Our coach @jdm also gave us a lot of good feedback which we are working through.

Spent the afternoon brushing up on Rust!

Things we learned:

Debugging: Rust is a compiled language, so code needs to be built before running it. This means that you can get errors at two different stages, compile-time and runtime. As opposed to an interpreted language like Python where errors are found as each line of code is executed in order (top-to-bottom), Rust code is parsed in its entirety during compilation and different types of errors are found in stages. Python debugging is like a straight celery stick, and Rust debugging is more like an onion, with layers. One side-effect of this is that when we build Servo, the errors do not appear in a "linear" fashion, and fixing one bug at line 20 does not mean that lines 1-19 are perfect.

Reflectors! For the past two weeks we have been mystified by the presence of Reflectors in Servo DOM objects. Today we learned that Reflectors are JS objects allocated by SpiderMonkey (Mozilla's JS engine), that "reflect" the containing Rust object. An example of its use is here. This concept is hard to digest at first because it is circular: the JS reflector is embedded within the Rust DOM object, yet has a reference to the DOM object.

TODO:

Address all the feedback from PR#2, including a lot of refactoring and adding a new_inherited method (somewhat related to Reflectors).

Should we write tests for our append method and associated helper functions?

Come to a conclusion regarding the field-content production, i.e. here.

Things we did:

Ran into a lot of incompatible type issues. And we are still learning! :) :) :)

We decided to be more aware of each other when pair programming. :D

Used DOMRefCell instead of RefCell because DOMRefCell implements JSTraceable. With RefCell, the compiler threw an error saying it requires JSTraceable implementation.

The reason we need RefCell is that it allows interior mutability to immutable borrowed content. The header_list needs to be mutated while auto-generated HeadersBindings.rs will borrow Headers immutably.

Things we learned:

return can only return from the current function, i.e. you can't return from an enclosing function in a closure.

match doesn't introduce a new function or closure, so it is fine to return from a match arm

Things we learned:

How to add crate dependencies (assuming script is the root directory of our files):

In components/script/lib.rs, add extern crate unicase;.

In components/script/Cargo.toml, add use unicase="1.4.0".

Cow automatically handles copy and writing when you have a borrowed immutable reference.

Emacs tip "defining macro":

C-x (C-x )C-e

String is guaranteed to be UTF8 and is heap-allocated (and therefore growable). &str is a string-slice. dom::bindings::str::ByteString is not guaranteed to be UTF8.

If Result only returns an error, use Result<(), Error>.

For Boolean matching in Rust, use &&.

Because the Headers API interacts with JS, JS garbage collector must be able to trace Headers API's elements. In order to allow that, above a struct or enum that declares, add #[derive(JSTraceable, HeapSizeOf)].

Crate regex supports pattern matching on bytes. Add use regex::bytes to the code.

TODO:

Finish writing field name and field content parsers.

Figure out how to wrap our Headers struct around hyper::headers::Headers. Ask jdm!

July 08, 2016

Things we did:

After reviewing, went through each line of the normalize function from yesterday.

Started writing test for normalize function.

Things we learned:

In Rust, only one thing can own a mutable reference at a time.

Many things can have a reference to another thing, but only if it's an immutable reference.

Dereferencing is a tricky concept. It can also be done in a couple different ways. For example two code snippets below would do the same thing:
for byte in &value[first_index..last_index + 1] {
normalized_value.push(*byte); // dereferencing here
}

Yesterday we attended the PDX Rust meet-up and saw Andy Grover give a presentation on his project Froyo.

Today we worked at the Portland Mozilla office to program on a really easy Servo issue just to get used to the workflow. With the help of our coach Nick we were able to submit our first pull request, which was accepted. :)

Things we did:

Re-factored some code related to Interval Profiling, specifically the calculation of the mean, median, minimum, and maximum of the time spent on various events. (Not related to the Fetch API, which is our main project.) The PR: here.

Upgraded Emacs configuration, e.g. rust-mode, and learned some best practices for using Emacs

Implemented step one of Headers.append() for the Fetch API (normalize), together with Nick.

To-Do:

July 07, 2016

Things we did:

Had a kick-off call to say hi, discuss various logistics, and the best way to ramp up to speed on Servo

We are planning on spending Thursday working on an E-Easy tagged Servo issue with our coaches, just to get used to the workflow

In terms of dividing our time between learning Rust and working on Servo, the consensus was that it is good to know enough Rust to understand basic Servo code, but it is also important to dive into the issues!

Decided to do work on our own Servo forks as opposed to a team fork. Learned how to reset our working repo to a particular fork, branch, or commit.

Ran into more build issues. Oddly, the build that worked for us yesterday didn't work for us this morning. After some troubleshooting we got it to run again. In the process we learned:

Learned that we need to add #[dom_struct] before our headers.rsstruct declaration, and the first field of the struct has to either be a Reflector or the object it inherits

To-Do:

Go to the Rust PDX meet-up tonight!

Learn more Rust

Ask Josh how often to pull from Servo (pulling and re-building every day might result in a significant amount of our time spent dealing with build failures)

October 26, 2016

In our last blog (wow, it’s already been almost a month!) we mentioned a sEcReT bLoG pOsT!
Here is our series on implementing the new Doge API for those are interested in contributing to Servo!:
Part 1: How to implement a new DOM API for Servo
Part 2: How to test a DOM API for Servo
Yesterday … Read more.

October 01, 2016

Today is the last day of RGSoC. We are incredibly sad, and proud of our summer!

Things we did:

Both of us worked on a secret blog post. It will be ready soon!

Things we learned:

A couple failing tests and their reasons:assert_equals: response type is basic expected "basic" but got "default"
- our API for returning responses (ie. process_response) doesn't differentiate between the different types yet, so we need to make that possible to make those tests pass. Josh thinks that FetchMetadata will need to be changed.

assert_equals: Content-Type is text/html; charset=utf-8 expected "text/html;charset=utf-8" but got "text/html; charset=utf-8"
There's a lot of debate what to do with a space.

TODO:

Keep learning.

Improve Fetch so that it passes more tests!

September 30, 2016

Today is the last day of RGSoC. We are incredibly sad, and proud of our summer!
Things we did:
Both of us worked on a secret blog post. It will be ready soon!
Things we learned:
A couple failing tests and their reasons:
assert_equals: response type is basic expected "basic" but got … Read more.

Things we did:

Spent the morning categorizing fetch/api/basic tests. >90% of failing tests were due to fetch is not defined. The remaining two failures were due to assert_equals: Request.text() should decode data as UTF-8 and assert_equals: Response.text() should decode data as UTF-8 expected. In the afternoon fetch got merged into master, so I retested response and basic at that point....now there is a lot of assert_equals: Request.text() should decode data as UTF-8 expected and assert_equals: Response's type is basic expected "basic" but got "default". Started trying to figure out what's wrong with body's text() Looked into request/request-consume.html and /basic/text-utf8.html....not sure how to fix!

Jeena

Started writing a blog post that is a secret yet!

TODO:

We’re having our end of summer party. We’re going to see thousands of swift birds fly into a chimney for the night! So excited.
Things we did:
Body
Body mixin methods are now supported!
Fetch
Fetch method is now supported too!
Malisa
Spent the … Read more.

Things we learned:

Trait object in Rust. Trait objects are the difference between fn foo(object: &Trait) (this is trait object) and fn foo<T: Trait>(object: &T). The former will result in the compiler generating less code, so the compile time will be faster. However, this puts a little more strain during run time, because it will have to check whether the parameter object implements the &Trait. The latter generates more code during compilation because it will create unique functions for each type that implements Trait. This saves time during run time because the functions for each type is already defined. As Josh said "classic tradeoff between time and space!"

Things we did:

Body

Spent the morning (!!) rebasing Body on top of master (did it the hard way using rebase the first time, until Jeena suggested I just reset and cherry-pick my commits on top...the latter way had only a few merge conflicts as opposed to a LOT). And a little rewriting to get things to compile. Still need to implement the BodyTrait for request.rs. More tests are passing now!! Yay :)

Fetch

Hmm, homu tests kept failing. Web platform tests related to cors/ and redirect/ seemed to fail intermittently, so we decided to skip those tests for now.

Package Data Algorithm

The parser for body when MIMEType is "multipart/form-data" is not clearly defined, so I decided to skip it for now.

General

We started writing our end-of-summer blog post. So sad!

Things we learned:

git cherry-pick is sometimes easier than git rebase

git clean -f -d gets rid of untracked files and directories. I used this today right before a git reset.

September 26, 2016

Things we did:
Body
Spent the morning (!!) rebasing Body on top of master (did it the hard way using rebase the first time, until Jeena suggested I just reset and cherry-pick my commits on top…the latter way had only a few merge conflicts as opposed to a LOT). And a little rewriting to … Read more.

September 25, 2016

Things we did:

Finished refactoring (for the most part) and pushed to a temporary branch for the Body API while Jeena adds her changes. I'll probably implement the BodyTrait for dom::request while she does that.

Package Data Algorithm

Added/Refactored the package data algorithm to the temporary branch! And it compiles!

Things we learned:

You can directly access struct fields only if you're in the same file as the struct that you're trying to access. This at first seemed really weird and arbitrary to me, but apparently this turns out to be less of a headache (and fairly reasonable) compared to the way internal field access would be handles in C++ (according to our coach Nick). This is why it sometimes easier to implement a trait for a struct in the same file that the struct is defined (as opposed to, say, the file that the trait is defined).

TODO:

Body (Malisa)

implement the BodyTrait for dom::request. Also, rebase on top of the current master (now that promises and fetch are merged in ^^)

Test Curation

Go through the new tests, and categorize them.

Package Data Algorithm

Figure out how to write FormData() when MIMEType is "multipart/form-data"

Clean up the code

September 23, 2016

Things we did:
Body
Finished refactoring (for the most part) and pushed to a temporary branch for the Body API while Jeena adds her changes. I’ll probably implement the BodyTrait for dom::request while she does that.
Package Data Algorithm
Added/Refactored the … Read more.

Things we did:

Body

Started refactoring consumebody based on feedback and yesterday's planning. Created body.rs and pulled out `consumebodyandrunpackagedata_algorithminto it, and created aBodyTrait`. The project was oddly compiling without complaints for most of the day. I mentioned this to Jeena, who reminded me that I have to list new dom files it in dom/mod.rs......haha. :) I did, and then all my bugs were then revealed upon the next compile. :P

Promise in Fetch

net_traits had changed! So I had to modify the process_response() method to accomodate the changes. It is more secure now as it allows the fetched data to be filtered. Filter exists to protect sites from having their data stolen by other sites.

Package Data Algorithm

I implemented(though no guarantee it works :wink:) Json(), Blob(), and part of FormData().

September 22, 2016

Things we did:
Body
Started refactoring consume_body based on feedback and yesterday’s planning. Created body.rs and pulled out consume_body and run_package_data_algorithm into it, and created a BodyTrait. The project was oddly compiling without complaints for most of the day. I … Read more.

TODO:

Body (Malisa)

Fix code based on jdm's feedback and refactor.

Test Curation

Go through the new tests, and categorize them.

Package Data Algorithm (Jeena)

We decided that I should work on implementing the rest of the package data algorithm. This decides what to do given a Body, depending on its type (a text, json, and etc). Malisa already implemented text, so that's great! Malisa will focus on going through review comments from her recent PR, and refactoring consume_body and making it into a public function. That way, it can be called by both Request and Response. At this moment, consume_body is customized for Response specifically, and it will be redundant to do the write the same function for Request.

September 21, 2016

Things we did:
Body
Submitted PR last night for dom::Response’s Body::text function. Got back some feedback. Spent some of this afternoon planning the next steps.
Blog
I (Malisa) spent some time writing my Strange Loop blog….will try to do some more coding … Read more.

Things we did:

Ms2ger implemented OpenEndedDictionary! This is what will allow more Headers/Request/Response tests to pass. Woohoo!

So I modified our Headers and Request APIs to adapt to this change. I fought with the borrow checker a lot today, but overall, it was successful. Thanks rustc!

Body

Got dom::Response's Body text() function to the point that it compiles, but additional tests are not passing. I keep getting the same error Promise is not defined in testharness.js.

Things we learned:

When T doesn't derive clone, or has a clone implementation, the compiler makes another reference when .clone() is called to a &T, ending up with &&T. When .clone() is called, the compiler derefs &T to T, realizes T cannot be cloned, and so it creates a clone to the reference, hence creating a double reference.

TODO:

Promise in Fetch

Go through failing tests and figure out what I can fix.

Test Curation

Go through the new tests, and categorize them.

OpenEndedDictionary in DOM

Is it time for a PR?

Body

Figure out whether I have a bug. Ask jdm. Then submit PR.

September 20, 2016

Things we did:
OpenEndedDictionary in DOM (Jeena)
Ms2ger implemented OpenEndedDictionary! This is what will allow more Headers/Request/Response tests to pass. Woohoo!
So I modified our Headers and Request APIs to adapt to this change. I fought with the borrow checker a lot today, … Read more.

September 14, 2016

Day 50! Today was a good day. We listened to our mentor Josh give a great talk about Optimizing your project for contribution. As mentees, we really appreciate all the work that's put into making Servo accessible to beginners.

Things we did:

Promise in Fetch

So yesterday, we found that JSCompartment::wrap had a parameter with a null pointer, which was the reason Servo was crashing. Josh recommended looking at dom/testbinding.rs to see how JSAutoCompartment is used, and to copy it in fetch.rs. After a little bit of wrestling with fetch.rs (because I mistakenly looked at the wrong code), fetch, at least for now, works!

Some more explanation on JSCompartments is at the Today We Learned section. What was happening yesterday with the null pointer was that promise didn't enter any compartment, because JSAutoCompartment::new() wasn't called. promise had not entered any compartment, and therefore, when SpiderMonkey (JS Engine) called JSCompartment::wrap(), which would take a JSContext to the compartment of a JSObject, a null pointer was given. Apparently in order to enter a compartment, JSContext has to already have entered a compartment. And that's why Servo crashed!

We had been doing systems programming for two months, and this was our first time encountering a null pointer (which was in C++ code). Nick said that this shows how safe Rust is, because Rust would not have compiled in the first place. I haven't programmed in C++, but it must be annoying if a code compiles and so much time could pass until you find a memory pointer bug.

I still didn't get a lot of code-writing done, but I have a better idea of where I'm headed now. I was unsure how closely I should be following the spec for utf-8 decoding. I asked jdm, and it turns out the answer is "just closely enough" (my own words). So that's good, and I think I'm starting to understand how to not get super caught up in spec-reading loops of infinite link-following. It also turns out I can make use of the encoding crate, which I believe means a lot of the actual decoding part has already been written for me.

Things we learned:

Spider Monkey specific: What is JSAutoCompartment? JSAutoCompartment helps a JSContext to enter a compartment, and leave the compartment when it is out of scope.

Spider Monkey specific: What is a Compartment? Every JSContext has a current Compartment, but it won't enter its current compartment until JSAutoCompartment::new() is called. In a browser, one tab (one window) will have at least one compartment. Two tabs will have at least two compartments. Compartment is important for security, because there can be little cross-over that will be strictly controlled. You wouldn't want data jumping back and forth between different compartments.

Things we did:

On Friday, wrapping Rc<Promise> with Trusted didn't work. Over the weekend Josh pushed another commit to enable Trusted<Promise> and TrustedPromise::root() that will return a Rc<Promise>. On Sunday, I encountered two borrow check errors:

process_response requires &mut self as a parameter (not mut self). When I try to get the root of TrustedPromise, it throws an error saying "cannot move out of borrowed content”. lines 122, 124, 136, and 138

the root() of TrustedPromise requires self parameter. In line 101, with let context = fetch_context.lock().unwrap(); which is type MutexGuard, which derefs to &T. When we try to access the Rc<Promise> via context.fetch_promise.root(), the compiler throws a borrow error.

That helped me learn that Fetch isn't working :scream:. I started debugging (which means, me = stressed out) and learned a few things:

metadata that is used for process_response looks good. It's Ok(_) and has the fields that look not incorrect.

After promise is taken from FetchContext through self.fetch_promise.take(), no other line is called... WEIRD. WHY. Well, luckily, I was working at the Mozilla Office, and three(!) people helped me debug. Special thanks to @sanxiyn, @fitzgen, and @jimblandy.

Frame is older with higher frame number, i.e. frame #6 is called before frame #5.

frame #6 shows that to_jsval was called. This in turn calls JS_WrapValue in frame #5. This in turn calls JSCompartment::wrap in frame #4.

JSCompartment::wrap has a parameter that is this=&0x0. 0x0 is a null pointer!!! We have a memory-unsafe code here!!! Woohoo!

Body

Read the spec and some more about Unicode encodings in order to understand the UTF-8 decoder. Wrote a little code. Progress was slow due to being sick today.

Things we learned:

When you write . after an object, it automatically derefs! For example, if I do fetch_context.lock(), I'm derefing fetch_context then applying the lock() method.

assigning different types to the same binding name (via let statements) seems to be acceptable practice, at least in some contexts.

0x0 is the synonym to null pointer in C++! If your stack backtrace includes 0x0 that's probably not something you wanted :)

When debugging Servo, you can use the --debug tag, i.e. ./mach run -d ~/src/fetch_example.html --debug. Servo uses lldb debugger by default.

You can set a breakpoint, for example, if you want the code to pause when it calls rust_panic function, you can write b rust_panic<ENTER>run.

While you're at the breakpoint, (or maybe some other time too but I'm not too sure) you can type bt which will print all the backtrace! COOL.

Rc and Trusted has to maintain a 1:1 relationship, and therefore, Trusted should not have a &self parameter because that could break that 1:1 constraint. In Servo's promise, Rc counts the references, and therefore TrustedPromise has to be connected to the one and only Rc<Promise>, because otherwise, the reference count will be incorrect.

TODO:

September 10, 2016

Things we did:

Promise in Fetch

Wrote process_response method. I think the remaining relevant FetchResponseListener methods are process_response_eof (invoked when fetching response is complete) and process_response_chunk (invoked when fetching response body). But process_response_eof requires response trailer support, which is not implemented, and process_response_chunk can probably wait until the response body is implemented.

Turns out when Josh said to create FetchContext later when it's necessary, he meant literally creating it further down in the method (like physically located further down). Haha oops! I started working on creating FetchContext!

Body

Started implementing the Body functions without ReadableStream. The spec refers to streams a lot, but servo doesn't implement ReadableStream, so I am trying to figure out how to write things correctly using Vec instead. Set up skeleton code for implementing text() for dom::Request and dom::Response. Then dug into dom::Response's text(), which led to writing bits of consume_body(), run_package_data_algorithm(), and utf8_decode().

Things we learned:

In order to use Promise::maybe_resolve_native() and the like, it needs a JS Context parameter. JS Context can be obtained through self.global().r().get_cx(). JSContext is a context in which JS can be invoked, and is required by APIs that interact with the JS engine (or it can use a JSRuntime argument). It's confusing to me, but for now, I'll just think of it as a connector to the JS world! (probably not 100% accurate).

vec.drain(..3); removes the first 3 elements of a vec.

TODO:

September 09, 2016

Things we did:

Yesterday, we went to PDX Rust meetup, which was great! A lot of people visiting Portland for RustConf showed up, so it was lovely. Nick Cameron talked about common Rust patterns and a repo to catalogue them. Jamey Sharp talked about Corrode, a software that translates C source files to Rust source files using Haskell(!).

Today we had a monthly meeting with everyone, and it was gooood. Special thanks to Scott for the pep talk! Also, we picked and ate figs from the fig tree by Jeena's home as a break.

Promise in Fetch

Today was indeed a different day! I started working on implementing the FetchResponseListener. FetchResponseListener is invoked when (I think) the network level fetch gets some data back. For example, a method in FetchResponseListener is process_response, which will update the response object with the data it got back from fetching.

Josh suggested not worrying about the FetchContext, which will be the struct to hold promise and response together, until later. Creating the FetchContext will require a lot of wrappings.

The fetch listener (FetchContext) has to be Arc<Mutex<T>>. Inside FetchContext, there will be response_object with type Response and promise with type Rc<Promise>. Both of them will need to be wrapped with Trusted to be shared across threads safely.

I think Response should be wrapped wtih DOMRefCell to allow inner mutability, but we shall see. response_object has to be rooted as well, so it will be Root<Response> type. Josh said that since FetchResponseListener will be implemented on FetchContext, calling self.response.root() will obtain a Root value in the callbacks that can be manipulated like usual.

promise is Rc<T> so we will need a method that will pull out Rc from Trusted, like self.response.root() would.

Body

Wrote step 34 of Request constructor to extract Body contents. The extract body method still doesn't use ReadableStream so I'm not sure if it will need to be rewritten.

Step 7.3 of Response

Things we learned:

The difference between Mutex types and regular-ol'-mutable-rust-variables. Both only allow mutation of their data one thing at a time, through either & mut or for mutex lock() and unlock(). What makes Mutex special? It is specifically designed for sharing across threads (often used in conjunction with Arc), whereas regular mutable borrow is not. So, only one thread can safely access the same data at one time. On the other hand, regular-ol'-& mut will not be allowed by the borrow checker if you try to use it across threads.

A whole lot about network-level fetch! Network level fetch is the communication with the core resource thread that invokes fetch algorithms, as described in the spec. There are a couple Servo parts that already use the network-level fetch: XMLHttpRequest and script.

Rc<T> is not thread-safe, but Trusted<T> is, like in Trusted<XMLHttpRequest>.

September 08, 2016

Things we did:

Promise in Fetch

I feel like I didn't make much progress today. I've been looking at how XHR is implemented the whole day, and couldn't understand it very much :disappointed: What I get is that there needs to be an object (probably FetchContext) that will hold the intermediate Response, and communicate with Promise to get the status of fetch. Hopefully tomorrow will be different!

Body

Started to write the extract-body function until I realized it's already been written in XHR.

Moved onto more of the Body logic. Not sure how ReadableStream will be dealt with. I feel like a lot of what I'm doing will cross tracks with what Jeena's doing. We'll see...!

Things we learned:

We went to the monthly Rust meetup today. We learned about some patterns we should and shouldn't do, a shout-out to clippy, and a C to Rust converter (wow!). We saw a lot of the Rust community in person (they flew in from around the world for the upcoming RustConf this weekend), so it was pretty exciting!

September 07, 2016

Yesterday was Labor Day, so we celebrated it by not working! Woohoo! Malisa is traveling back today, so I (Jeena) worked alone today.

Things we did:

Promise in Fetch

jdm is back! He rebased his promises branch! :clap: The rust compiler still panics instead of throwing error as it uses the older rust version, but that's ok! I can work around it.

It turns out there's a lot more to do with implementing promise in fetch so I spent the day trying to understand what I need to do. Roughly, there are two things I can do:

figure out how to reject/resolve Promise in fetch. Promise::maybe_resolve_native is probably a better choice than Promise::maybe_resolve because they take regular DOM objects. This seems partially dependent on the next thing.

implement FetchResponseListener in fetch.rs. This turns out to have a lot more pre-requisite infrastructure! fetch.rs needs a FetchContext struct that will store the intermediate fetch. XMLHttpRequest is done very similarly to fetch, so I should look into how XHR is implemented in Servo. How XHR implements FetchResponseListener is here.

Things we learned:

Promise doesn't have to be rooted! Whaaaat. jdm says "Rc would usually be unsafe but Promise is designed in such a way that it's safe, whereas Rooted would be incorrect." Whaaaat? I don't even understand! We'll find out the reason later...

Things we did:

When Fetch.webidl and window.rs/workerglobalscope.rs state that fetch() returns a void, and fetch() does return a void, it compiles.

When Fetch.webidl and window.rs/workerglobalscope.rs state that fetch() returns a void, but fetch() returns Promise, it compiles. This is strange because the compiler should throw a type mismatch error.

When Fetch.webidl or window.rs/workerglobalscope.rs state that fetch() returns a Promise, and fetch()does return Promise, compiler fails with this error.

This rust bug is fixed with the latest nightly which Servo uses. When I rebase jdm:promises on top of the latest servo:master, a lot of conflicts happen and I'm not sure how to resolve them as I'm unfamiliar with the changes. I tried a few approaches (not really organized…) and they all have failed

Things we did:

Categorized the tests! I haven't filed the issues yet, but it boils down to roughly two large groups:

"Promise is not defined": While the test messages are saying promise is not defined, these tests are in fact related to body. Body has a few methods that return Promise.

"xxxxdict is not iterable": OpenEndedDictionary needs to be implemented. What Nick said about this: "OpenEndedDictionary isn't supported in HeadersInit, bindings glue tries to convert the object into something that is supported in HeadersInit. The object is not a Headers object, so that doesn't work. Then the glue code tries to treat it as a Sequence. However, it is not an iterable sequence, so it throws the error you're seeing."

There are a few notes:

Each API has a -idl.html test file that are currently timing out. I'm not exactly sure what they do, but it looks like once webidls are fully implemented, these tests will pass.

Some subtests related to stream like readableStreamfail. I'm not sure if stream is something we can implement or is already implemented. Will have to ask someone knows more about this.

Response is currently throwing an error about network error code. Malisa will be working on this!

Response

PR is finally ready to be merged (or so we thought), but Jeena discovered a test which is failing which should be passing, so I'm fixing that up.

Body

Tried to understand how/where I should be implementing Body. Decided to start with writing body's extract method.

Things we learned:

In JavaScript there is a distinction between for ... of loops and for ... in loops. E.g.

In Python, for x in foo is the same as in JS, for (x of foo). In this case, x is the object you ultimately want to view or manipulate.

In Python, for x in foo.keys() is the same as in JS, for (x in foo). In this case, x is the key to the dictionary you might what to iterate over.

TODO:

Response

Figure out how to encode StatusCode 0 as an Enum, which is not supported currently.

August 30, 2016

Things we did:

I rebased Fetch implementation on top of jdm's branch, and tried to use Promise in fetch(). Strangely, it's causing the Rust compiler panics unexpectedly. I'm not sure how to move forward…

Test Curation (Jeena)

Haven't started on this yet. As I'm lost about Promise in Fetch, I'll work on this first.

Response

Still fixing things. Currently in git rebase hell.

Things we learned:

By doing let hello = b"hello";, an array is created. An array has a static length. So in our Headers code, we ended up making unnecessary transformations here. We wrote combined_value.push(b","[0]); which means, "create an array that has length of 1, and whose only element is a comma byte. Then, take the first element of it and add that to combined_value. We can improve this line by writing combined_value.push(b',');

August 26, 2016

Things we did:

I wrote the algorithm to send the fetch message to the resource thread (net_traits).

It looks like the parts I can do right now are mostly done, but it needs double checking!

Things we learned:

Closures! We went to Portland's Papers We Love meetup yesterday and learned about Garbage Collectors. It seems like with JS closures, sometimes you might have to move stack-created objects to the heap. Interesting!

TODO:

Promise in Fetch

implement the Promise return value for fetch() on top of jdm's branch

Test Curation

curate the failing tests and opening an issue for each category so that others can pick up where we left if we don't finish implementing fetch, i.e. tests that fail because of Promise, because of OpenDictionary, etc.

Things we did:

Fetch

Set up the skeletons for Fetch. It was a tricky process. Fetch is defined in WindowOrWorkerGlobalScope.webidl which is a newer addition to the spec and was not present in Servo. I had to add it to Servo, and WindowOrWorkerGlobalScope is not a interface object, so no bindings were created. The compiler told me that dom/window.rs and dom/workerglobalscope.rs had to implement Fetch(). So what we decided to do is have a script/fetch.rs where the Fetch method will live, and have dom/window.rs and dom/workerglobalscope.rs delegate the Fetch method to script/fetch.rs.

Response

Ended up having to replace instances of RawStatus (which takes a utf-8 encoded Cow-str) in Servo's codebase with (u16, Vec<u8>), which is not UTF-8-dependent. I spent the whole day re-building and finding new places in the codebase which were affected by this change, fixing, and re-building again! Finally the relevant test is passing though :)

Things we learned:

Don't spend too much time trying to predict the repercussions of a change in your Rust code. (I do this a lot - Malisa) Often-times the Rust compiler will tell you what those repercussions are, and save you a lot of time, even though you might get surprised by some unexpected errors while building your project!

TODO:

Fetch

It seems like a huge chunk of Fetch is already implemented in net/fetch/method.rs. Figure out how to wrap script/fetch.rs around net/fetch.

Response

update tests, clean up code, and submit the PR already!

Miscellaneous

Publish a blog post about move, clone, and copy! (Jeena)

Before Josh goes on a vacation, ask him what we should work on next week.

August 24, 2016

Things we did:

PR sparked some discussion… This might take a bit longer to resolve. Tried to implement header values to be stored as Vec<Vec<u8>> in which the inner vector is one header value. Not sure how this will mesh with hyper::header::Header existing methods. (Or, how do I separate the different header values? Will the comma have to be added as a separate vector?)

Fetch

Started working on this, and encountered some ~issues~ challenges! See TODO.

Response

Still dealing with wpt test errors. Fixed one (adding dummy argument to constructor so it takesthe right number of arguments), still dealing with a UTF-8 conversion error on one of the tests.

Things we learned:

if you want to import the latest changes in a file from a different branch to your current branch:
git checkout remote-name/branch /path/to/file

TODO:

Fetch

It looks like fetch requires WindowOrWorkerGlobalScope which is not implemented yet. Hear what Josh has to say, and do that!

Response

Submit the PR once tests pass.

Start trying to understand the work that would go into implementing the body APIs, working on top of jdm's Promise branch (Malisa)

Things we did:

Submitted a PR for updating DOM Headers. Making more tests pass is fun!!!

Response

Finished up implementing dom::Response. Now dealing with wpt test errors.

Things we learned:

Fetch requests originate in the script thread via a JavaScript function. The request gets sent to the dom objects (e.g. dom::Request) and are sent to the resource thread using net_traits::CoreResourceMsg. The resource thread calls the actual HttpRequest. The response is sent back to the script thread and the original Promise is resolved. Yay! This is just a broad overview...

TODO:

Fetch Method (Jeena)

Read about fetch. Decided to start working on fetch (one of jdm's suggestions). He wrote:
"Start working on the actual fetch() API, focusing on the code that deals with the arguments and initiating the request and ignoring the return value for now." At this moment, I won't have to worry about Promise because "there's enough work that goes into dealing with the arguments to the function and initiating the request that the promise-related bits can be done separately and subsequently."

Things we did:

Got completely confused about what I'm supposed to do next. Gave up trying to reconcile the spec, the multiple hyper::header::Headers objects, and the nuances of implementing for Servo (for now).

Focusing on just writing the Response API as though I only have one version of hyper::header::Headers in dom::Headers...

Things we learned:

Threads vs processes (thanks wiki!): In the operating system, two "processes" do not share memory. A process can contain multiple "threads" which share memory and other resources.

This is rather relevant to the whole multiple-references-to-the-same-object problem. You need to be aware of whether the references exist in different processes (if so, you can't use the Rc or Arc types, which are for sharing within a process).

TODO:

Response API:

Work on the constructor while figuring out what to do next

Headers Iterable

Continue implementing parse

Refactor iterable implementation

August 15, 2016

Things we did:

Submitted PR to wrap hyper::header::Headers in Rc. This solution may or may not work for the Response API, however, because Rc doesn't work across threads. Instead of manipulating the same object in multiple places, I might end up having to just work with one version of hyper::header::Headers, or replace Rc with Arc.

Things we did:

Fought with the borrow checker the whole day. Implemented clone for net_traits::response::Response and dealt with side-effects of using internal Rc types... x_X

Request API

Decided not to file a spec issue, but clarified the reasoning for the additional step in request.rs in the comments.

Made the code more readable, and removed unnecessary parts.

jdm gave me the permission to squash! Woohoo! Merge is near.

Things we learned:

Parentheses are useful! Long story short, wrapping parentheses around (*gadget1.owner) applies the deref * to just gadget1.owner, which is just what I needed. :)

Reflog is what git uses to keep track of updates to the tip of branches, including those that are invisible on git log! This acts as a great safety net. For example, if you want to undo git rebase, you can find the HEAD of pre-rebase, and git reset --hard to that HEAD.

You cannot modify a field that is in a borrowed context. Read more about it in our blog post.

TODO:

Response API:

Deal with current build errors (now the side-effects of wrapping headers with Rc and RefCell are appearing in places like fetch/methods.rs, uh oh)

And then modify net_traits::request::Request and dom::headers as well......

Implement JSTraceable for RefCell in dom::Headers

And then finally work on dom::Response! >:-|

Request API:

If merge happens, start working on making Headers iterable based on jdm's PR.

August 11, 2016

Things we did:

Spent most of the day trying to figure out how to best make references between objects within the Response struct.

Request API

Turns out I had to debug the crap out of Request, not Headers!

Fixed a bug. More in depth description below.

More tests are passing! I updated the expected test results.

Things we learned:

How to use reference-counted boxes: Rc<>. They are a way to refer to the same internal object in multiple places. Different from RefCell, which I believe is more of a way to provide mutability of already-borrowed objects.

When debugging a Rust code, you can print the memory address of the object (in this case, x) through: println!("{:p}", &x);

Approach debugging as if performing a scientific experiment. Do you have a hypothesis where it might be breaking? Sprinkle some print statements in the code, or set breaking points in the debugger. Study the results. Can you find a pointer that would lead to the next hypothesis? Repeat! And don't get frustrated!

TODO:

Response API:

Update net_traits::Response and net_traits::Request and dom::headers::Headers to wrap Rc<> around their internal hyper::header::Headers objects. That way they will be clonable into reference-counted boxes.

After that hopefully I can actually do work on the Response constructor....fingers crossed...

Things we did:

Had our monthly meeting with everyone! Everyone is doing well. :D

Blast from the past! Back to Headers API.

With the help of Stefan and the rust playground, we realized there were bugs in the is_field_content and Append functions in the Headers API. After fixing these, more of the Headers API tests passed! Oops...

Response API/CodegenRust

Received feedback on bindings generator PR. Once merged in, these changes will allow me to move forward with Response WebIDL implementation.

ASCII is limited to only 128 characters, via a 7-bit character set (so, fits in one byte). UTF-8 is flexible, on the other hand, and can represent characters that require between 1 and 4 bytes. The first 128 characters are the same for ASCII and UTF-8. UTF standards encode the "code points" as defined in Unicode.

This is useful for us to know because we are often converting between ByteString types, which are basically sequences of 8-bit unsigned integers, and characters or Strings. Many of the specs we have to follow reference these encodings. Knowing hexadecimal representation of characters is also useful.

Things we did:

Met with Stefan who showed us some useful tools for looking at Requests/Responses/Headers and also cleared up some questions which had been bugging us.

Things we learned:

dom::bindings::js::MutNullableHeap allows lazy construction of objects (they can be initialized only when you need them)

The cache-control header "directives control who can cache the response, under which conditions, and for how long".

Also learned about cookies from Stefan. Plus neato command-line tools like zsh-autosuggestions and zsh-syntax-highlighting. Also Charles for web debugging.

We asked Stefan about where to find the actual code that makes the HttpRequest to the remote server. The ultimate goal of all this code we're writing is to make an HttpRequest (well, one of the goals), yet the code we're writing seems to dance around that very topic while never actually making the call to the remote server. So this helped clarify things a bit!

Continued working on Constructor. Currently, up to step 15 is compiling successfully. A draft up to step 24 is written.

Things we learned:

There are different types of references in Rust. one of them is &, but you can also have "user-defined custom smart pointers" or wrappers with particular behavior for references, like Ref and RefCell. A helpful explanation is here and here.

You can customize the type name in a use statement. For example, instead of writing use hyper and writing hyper::header::Headers throughout the code, you can use use hyper::header::Headers as HyperHeaders and use HyperHeaders in the code body.

July 28, 2016

Things we did:

Wrote a couple helper methods for finding associated and current url, given a url list.

Started writing constructor step 13.

Headers API

Finished up the remaining functions defined in the webidl. My job was made easier because I don't need to implement iterable<ByteString, ByteString> just quite yet.

Things we learned:

Even though the result of the two code blocks below are the same in practice, it's only due to the rust optimizer.

This first version only ever deals with one memory location on the stack
let mut valid_name = something;
valid_name = something_else;

This second version instructs Rust to create two memory locations for each valid_name. Only due to the Rust optimizer does the computer realize that it can reuse the same spot.
let valid_name = something;
let valid_name = something_else;

When returning a reference to a RefCell, wrap the content with Ref which can be done through Ref::map.

July 26, 2016

Things we did:

Realized that the hyper::header::Headersset_raw() and get_raw() act as though there is only one entry for a given unique header name.

Spent much of the day understanding the consequences of this (do we re-write our Headers append() method or re-write hyper::header::Headers?), piecing together instructions from various specs, and planning the next steps --> Decided to go with the current hyper::header::Headers implementation.

Currently re-working the append() method and other Header API functions.

Things we learned:

if let is handy if you want to match for only certain cases. For example, following code snippets are the same.

July 22, 2016

Things we did:

Request API

Turns out there is a Request struct already written in Servo. But the names it uses are different from what the codegen generates from the webidl. So I have to write Into implementation to allow translation between the two.

Completed writing Into implementation.

Headers API

Worked on filling in the constructor for the Headers API, following the spec.

Things we learned:

Trace Garbage Collection

In a garbage collected language (such as JavaScript and Python, but not Rust), GC manages the memory by freeing it when the memory occupant is no longer in use. Whenever a new object is created, it is done so through GC and GC will add to its set of objects created.

Once in a while, GC will be triggered, probably through the danger of memory running out. GC is expensive, and therefore, it should not be triggered too often. When GC is triggered, it traces memory, checking which objects are referenced, in other words, still in use. Tri-color marking is the one we learned about, and its wikipedia page provides an excellent summary.

Long story short, GC has the ability to compare the sets of objects created and objects that are still used. GC will free the memory occupied by whatever is in the difference.

July 20, 2016

Things we did:

Addressed the feedback that we missed yesterday, and new feedback we received today.

We got an approval from Josh! Woohoo!

Started working on our next goals. Malisa will continue working on headers, and Jeena will start working on request.

Things we learned:

git rebase -i <remote>/<branch> allows you to squash the commits between the current HEAD and the HEAD of <remote>/<branch>. If you are on local features branch and know that local master is untouched, you can git rebase -i master.

July 15, 2016

Things we did:

Submitted PR#2 for code review, the append method for the Headers API. The code compiles on our machines locally but seems to fail Travis CI on github. Our coach @jdm also gave us a lot of good feedback which we are working through.

Spent the afternoon brushing up on Rust!

Things we learned:

Debugging: Rust is a compiled language, so code needs to be built before running it. This means that you can get errors at two different stages, compile-time and runtime. As opposed to an interpreted language like Python where errors are found as each line of code is executed in order (top-to-bottom), Rust code is parsed in its entirety during compilation and different types of errors are found in stages. Python debugging is like a straight celery stick, and Rust debugging is more like an onion, with layers. One side-effect of this is that when we build Servo, the errors do not appear in a "linear" fashion, and fixing one bug at line 20 does not mean that lines 1-19 are perfect.

Reflectors! For the past two weeks we have been mystified by the presence of Reflectors in Servo DOM objects. Today we learned that Reflectors are JS objects allocated by SpiderMonkey (Mozilla's JS engine), that "reflect" the containing Rust object. An example of its use is here. This concept is hard to digest at first because it is circular: the JS reflector is embedded within the Rust DOM object, yet has a reference to the DOM object.

TODO:

Address all the feedback from PR#2, including a lot of refactoring and adding a new_inherited method (somewhat related to Reflectors).

Should we write tests for our append method and associated helper functions?

Come to a conclusion regarding the field-content production, i.e. here.

Things we did:

Ran into a lot of incompatible type issues. And we are still learning! :) :) :)

We decided to be more aware of each other when pair programming. :D

Used DOMRefCell instead of RefCell because DOMRefCell implements JSTraceable. With RefCell, the compiler threw an error saying it requires JSTraceable implementation.

The reason we need RefCell is that it allows interior mutability to immutable borrowed content. The header_list needs to be mutated while auto-generated HeadersBindings.rs will borrow Headers immutably.

Things we learned:

return can only return from the current function, i.e. you can't return from an enclosing function in a closure.

match doesn't introduce a new function or closure, so it is fine to return from a match arm

Things we learned:

How to add crate dependencies (assuming script is the root directory of our files):

In components/script/lib.rs, add extern crate unicase;.

In components/script/Cargo.toml, add use unicase="1.4.0".

Cow automatically handles copy and writing when you have a borrowed immutable reference.

Emacs tip "defining macro":

C-x (C-x )C-e

String is guaranteed to be UTF8 and is heap-allocated (and therefore growable). &str is a string-slice. dom::bindings::str::ByteString is not guaranteed to be UTF8.

If Result only returns an error, use Result<(), Error>.

For Boolean matching in Rust, use &&.

Because the Headers API interacts with JS, JS garbage collector must be able to trace Headers API's elements. In order to allow that, above a struct or enum that declares, add #[derive(JSTraceable, HeapSizeOf)].

Crate regex supports pattern matching on bytes. Add use regex::bytes to the code.

TODO:

Finish writing field name and field content parsers.

Figure out how to wrap our Headers struct around hyper::headers::Headers. Ask jdm!

July 08, 2016

Things we did:

After reviewing, went through each line of the normalize function from yesterday.

Started writing test for normalize function.

Things we learned:

In Rust, only one thing can own a mutable reference at a time.

Many things can have a reference to another thing, but only if it's an immutable reference.

Dereferencing is a tricky concept. It can also be done in a couple different ways. For example two code snippets below would do the same thing:
for byte in &value[first_index..last_index + 1] {
normalized_value.push(*byte); // dereferencing here
}

Yesterday we attended the PDX Rust meet-up and saw Andy Grover give a presentation on his project Froyo.

Today we worked at the Portland Mozilla office to program on a really easy Servo issue just to get used to the workflow. With the help of our coach Nick we were able to submit our first pull request, which was accepted. :)

Things we did:

Re-factored some code related to Interval Profiling, specifically the calculation of the mean, median, minimum, and maximum of the time spent on various events. (Not related to the Fetch API, which is our main project.) The PR: here.

Upgraded Emacs configuration, e.g. rust-mode, and learned some best practices for using Emacs

Implemented step one of Headers.append() for the Fetch API (normalize), together with Nick.

To-Do:

July 07, 2016

Things we did:

Had a kick-off call to say hi, discuss various logistics, and the best way to ramp up to speed on Servo

We are planning on spending Thursday working on an E-Easy tagged Servo issue with our coaches, just to get used to the workflow

In terms of dividing our time between learning Rust and working on Servo, the consensus was that it is good to know enough Rust to understand basic Servo code, but it is also important to dive into the issues!

Decided to do work on our own Servo forks as opposed to a team fork. Learned how to reset our working repo to a particular fork, branch, or commit.

Ran into more build issues. Oddly, the build that worked for us yesterday didn't work for us this morning. After some troubleshooting we got it to run again. In the process we learned:

Learned that we need to add #[dom_struct] before our headers.rsstruct declaration, and the first field of the struct has to either be a Reflector or the object it inherits

To-Do:

Go to the Rust PDX meet-up tonight!

Learn more Rust

Ask Josh how often to pull from Servo (pulling and re-building every day might result in a significant amount of our time spent dealing with build failures)