gecko-dev/third_party/rust/viaduct
Mark Hammond 6c3e1b850d Bug 1675190 - Vendor new application-services into mozilla-central. r=extension-reviewers,janerik,eoger,dmose,rpl
Differential Revision: https://phabricator.services.mozilla.com/D95829
2020-11-09 04:25:14 +00:00
..
src Bug 1675190 - Vendor new application-services into mozilla-central. r=extension-reviewers,janerik,eoger,dmose,rpl 2020-11-09 04:25:14 +00:00
.cargo-checksum.json Bug 1675190 - Vendor new application-services into mozilla-central. r=extension-reviewers,janerik,eoger,dmose,rpl 2020-11-09 04:25:14 +00:00
Cargo.toml Bug 1675190 - Vendor new application-services into mozilla-central. r=extension-reviewers,janerik,eoger,dmose,rpl 2020-11-09 04:25:14 +00:00
README.md Bug 1628068 p1 - Vendor viaduct crate. r=lina 2020-05-12 21:36:17 +00:00

README.md

Viaduct

Viaduct is our HTTP request library, which can make requests either via a rust-based (reqwest) networking stack (used on iOS and for local desktop use, for tests and the like), or using a stack that calls a function passed into it over the FFI (on android).

For usage info, you can run cargo +nightly doc -p viaduct (the +nightly is optional, however some intra-doc links require it), it has several examples.

Android/FFI Backend overview

On Android, the backend works as follows:

  1. During megazord initialization, we are passed a Lazy<Client> (Client comes from the concept-fetch android component, and Lazy is from the Kotlin stdlib).

    • It also sets a flag that indicates that even if the FFI backend never gets fully initialized (e.g. with a callback), we should error rather than use the reqwest backend (which should not be compiled in, however we've had trouble ensuring this in the past, although at this point we have checks in CI to ensure it is not present).
  2. At this point, a JNA Callback instance is created and passed into Rust.

    • This serves to proxy the request made by Rust to the Client.
    • The Callback instance is never allowed to be GCed.
    • To Rust, it's just a extern "C" function pointer that get's stored in an atomic variable and never can be unset.
  3. When Rust makes a request:

    1. We serialize the request info into a protobuf record
    2. This record is passed into the function pointer we should have by this point (erroring if it has not been set yet).
    3. The callback (on the Java side now) deserializes the protobuf record, converts it to a concept-fetch Request instance, and passes it to the client.
    4. The response (or error) is then converted into a protobuf record. The java code then asks Rust for a buffer big enough to hold the serialized response (or error).
    5. The response is written to the buffer, and returned to Rust.
    6. Rust then decodes the protobuf, and converts it to a viaduct::Response object that it returns to the caller.

Some notes:

  • This "request flow" is entirely synchronous, simplifying the implementation considerably.

  • Cookies are explicitely not supported at the moment, adding them would require a separate security review.

  • Generally, this is the way the FFI backend is expected to work on any platform, but for concreteness (and because it's the only one currently using the FFI backend), we explained it for Android.

  • Most of the code in viaduct is defining a ergonomic HTTP facade, and is unrelated to this (or to the reqwest backend). This code is more or less entirely (in the Kotlin layer and) in src/backend/ffi.rs.