Skip to content

Improve the Fetch API #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ jobs:
with:
toolchain: stable
profile: minimal
components: clippy
override: true
target: wasm32-unknown-unknown

- name: Install wasm-pack
Expand All @@ -106,16 +106,27 @@ jobs:
restore-keys: |
cargo-${{ runner.os }}-test-
cargo-${{ runner.os }}-

- name: Run browser tests
env:
HTTPBIN_URL: "http://localhost:8080"
ECHO_SERVER_URL: "ws://localhost:8081"
run: wasm-pack test --chrome --firefox --headless
run: |
cd crates/net
wasm-pack test --chrome --firefox --headless --all-features

- name: Run browser tests
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: wasm32-unknown-unknown

- name: Run native tests
env:
HTTPBIN_URL: "http://localhost:8080"
ECHO_SERVER_URL: "ws://localhost:8081"
uses: actions-rs/cargo@v1
with:
command: test
args: -p gloo-net --all-features
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ features = ["futures"]
members = [
"crates/timers",
"crates/events",
"crates/net",
"crates/file",
"crates/dialogs",
"crates/storage",
Expand Down
4 changes: 3 additions & 1 deletion crates/net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ version = "0.1.0"
authors = ["Rust and WebAssembly Working Group", "Muhammad Hamza <[email protected]>"]
edition = "2018"
license = "MIT OR Apache-2.0"
repository = "https://github.com/hamza1311/reqwasm"
repository = "https://github.com/rustwasm/gloo"
description = "HTTP requests library for WASM Apps"
readme = "README.md"
keywords = ["requests", "http", "wasm", "websockets"]
categories = ["wasm", "web-programming::http-client", "api-bindings"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
wasm-bindgen = "0.2"
Expand Down Expand Up @@ -62,6 +63,7 @@ http = [
'web-sys/RequestInit',
'web-sys/RequestMode',
'web-sys/Response',
'web-sys/ResponseType',
'web-sys/Window',
'web-sys/RequestCache',
'web-sys/RequestCredentials',
Expand Down
2 changes: 1 addition & 1 deletion crates/net/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ assert_eq!(resp.status(), 200);
### WebSocket

```rust
use reqwasm::websocket::{Message, futures::WebSocket};
use gloo_net::websocket::{Message, futures::WebSocket};
use wasm_bindgen_futures::spawn_local;
use futures::{SinkExt, StreamExt};

Expand Down
120 changes: 120 additions & 0 deletions crates/net/src/http/headers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use js_sys::{Array, Map};
use std::fmt;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};

// I experimented with using `js_sys::Object` for the headers, since this object is marked
// experimental in MDN. However it's in the fetch spec, and it's necessary for appending headers.
/// A wrapper around `web_sys::Headers`.
pub struct Headers {
raw: web_sys::Headers,
}

impl Default for Headers {
fn default() -> Self {
Self::new()
}
}

impl Headers {
/// Create a new empty headers object.
pub fn new() -> Self {
// pretty sure this will never throw.
Self {
raw: web_sys::Headers::new().unwrap_throw(),
}
}

/// Build [Headers] from [web_sys::Headers].
pub fn from_raw(raw: web_sys::Headers) -> Self {
Self { raw }
}

/// Covert [Headers] to [web_sys::Headers].
pub fn into_raw(self) -> web_sys::Headers {
self.raw
}

/// This method appends a new value onto an existing header, or adds the header if it does not
/// already exist.
pub fn append(&self, name: &str, value: &str) {
// XXX Can this throw? WEBIDL says yes, my experiments with forbidden headers and MDN say
// no.
self.raw.append(name, value).unwrap_throw()
}

/// Deletes a header if it is present.
pub fn delete(&self, name: &str) {
self.raw.delete(name).unwrap_throw()
}

/// Gets a header if it is present.
pub fn get(&self, name: &str) -> Option<String> {
self.raw.get(name).unwrap_throw()
}

/// Whether a header with the given name exists.
pub fn has(&self, name: &str) -> bool {
self.raw.has(name).unwrap_throw()
}

/// Overwrites a header with the given name.
pub fn set(&self, name: &str, value: &str) {
self.raw.set(name, value).unwrap_throw()
}

/// Iterate over (header name, header value) pairs.
pub fn entries(&self) -> impl Iterator<Item = (String, String)> {
// Here we cheat and cast to a map even though `self` isn't, because the method names match
// and everything works. Is there a better way? Should there be a `MapLike` or
// `MapIterator` type in `js_sys`?
let fake_map: &Map = self.raw.unchecked_ref();
UncheckedIter(fake_map.entries()).map(|entry| {
let entry: Array = entry.unchecked_into();
let key = entry.get(0);
let value = entry.get(1);
(
key.as_string().unwrap_throw(),
value.as_string().unwrap_throw(),
)
})
}

/// Iterate over the names of the headers.
pub fn keys(&self) -> impl Iterator<Item = String> {
let fake_map: &Map = self.raw.unchecked_ref();
UncheckedIter(fake_map.keys()).map(|key| key.as_string().unwrap_throw())
}

/// Iterate over the values of the headers.
pub fn values(&self) -> impl Iterator<Item = String> {
let fake_map: &Map = self.raw.unchecked_ref();
UncheckedIter(fake_map.values()).map(|v| v.as_string().unwrap_throw())
}
}

impl fmt::Debug for Headers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut dbg = f.debug_struct("Headers");
for (key, value) in self.entries() {
dbg.field(&key, &value);
}
dbg.finish()
}
}

struct UncheckedIter(js_sys::Iterator);

impl Iterator for UncheckedIter {
type Item = JsValue;

fn next(&mut self) -> Option<Self::Item> {
// we don't check for errors. Only use this type on things we know conform to the iterator
// interface.
let next = self.0.next().unwrap_throw();
if next.done() {
None
} else {
Some(next.value())
}
}
}
Loading