Skip to content

Commit

Permalink
refactor: Custom protcol request/response (#387)
Browse files Browse the repository at this point in the history
* refactor: Custom protcol request/response

Signed-off-by: David Lemarier <david@lemarier.ca>

* fix tests

Signed-off-by: David Lemarier <david@lemarier.ca>

* make clippy happy

Signed-off-by: David Lemarier <david@lemarier.ca>

* implement windows

Signed-off-by: David Lemarier <david@lemarier.ca>

* WIP linux implementation

Signed-off-by: David Lemarier <david@lemarier.ca>

* add request method for windows

Signed-off-by: David Lemarier <david@lemarier.ca>

* fix examples for windows

Signed-off-by: David Lemarier <david@lemarier.ca>

* better doc and add form post handler

Signed-off-by: David Lemarier <david@lemarier.ca>

* implement body on request for windows and fix fmt

Signed-off-by: David Lemarier <david@lemarier.ca>

* fix test and fmt

Signed-off-by: David Lemarier <david@lemarier.ca>

* remove `#[non_exhaustive]`

Signed-off-by: David Lemarier <david@lemarier.ca>

* make mimetype optional and finalize tauri integration

Signed-off-by: David Lemarier <david@lemarier.ca>

* use a string for URI as it doesnt support `file:///`

Signed-off-by: David Lemarier <david@lemarier.ca>

* fmt

Signed-off-by: David Lemarier <david@lemarier.ca>

* fix examples

Signed-off-by: David Lemarier <david@lemarier.ca>

* convert mimetype to `&str`

Signed-off-by: David Lemarier <david@lemarier.ca>

* make clippy happy

Signed-off-by: David Lemarier <david@lemarier.ca>

* remove unwanted logging

Signed-off-by: David Lemarier <david@lemarier.ca>
  • Loading branch information
lemarier committed Aug 22, 2021
1 parent 80b0919 commit d202573
Show file tree
Hide file tree
Showing 21 changed files with 997 additions and 134 deletions.
10 changes: 10 additions & 0 deletions .changes/custom-protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"wry": patch
---

The custom protocol now return a `Request` and expect a `Response`.

- This allow us to get the complete request from the Webview. (Method, GET, POST, PUT etc..)
Read the complete header.

- And allow us to be more flexible in the future without bringing breaking changes.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ target
Cargo.lock
gh-pages
.DS_Store
examples/test_video.mp4
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ serde_json = "1.0"
thiserror = "1.0"
url = "2.2"
tao = { version = "0.5.2", default-features = false, features = [ "serde" ] }
http = "0.2.4"

[dev-dependencies]
anyhow = "1.0.43"
chrono = "0.4.19"
tempfile = "3.2.0"
http-range = "0.1.4"

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
webkit2gtk = { version = "0.14", features = [ "v2_18" ] }
Expand Down
20 changes: 10 additions & 10 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

Run the `cargo run --example <file_name>` to see how each example works.

- `hello_world`: the basic example to show the types and methods to create an application.
- `fullscreen`: full screen example demonstrates how to configure the window with attributes.
- `transparent`: transparent example that also show how to create a valid data URI.
- `rpc`: A RPC example to explain how to use the RPC handler and interact with it.
- `multi_window`: create the window dynamically even after the application is running.
- `dragndrop`: example for file drop handler.
- `custom_titlebar`: A frameless window with custom title-bar to show `drag-region` class in action.
- `custom_protocol`: uses a custom protocol to load files from bytes.
- `html`: load the html string and load other assets with custom protocol.
- `custom_titlebar`: A frameless window with custom title-bar to show `drag-region` class in action.
- `detect_js_ecma`: detects which versions of ECMAScript is supported by the webview.
- `dragndrop`: example for file drop handler.
- `form_post`: submit form POST and get data in rust without any web server.
- `fullscreen`: full screen example demonstrates how to configure the window with attributes.
- `hello_world`: the basic example to show the types and methods to create an application.
- `menu_bar`: uses a custom menu for the application in macOS and the Window and Linux/Windows.
- `system_tray`: sample tray application with different behaviours.
- `multi_window`: create the window dynamically even after the application is running.
- `rpc`: A RPC example to explain how to use the RPC handler and interact with it.
- `stream_range`: read the incoming header from the custom protocol and return part of the data. [RFC7233](https://httpwg.org/specs/rfc7233.html#header.range)
- `system_tray_no_menu`: open window on tray icon left click.

- `system_tray`: sample tray application with different behaviours.
- `transparent`: transparent example that also show how to create a valid data URI.
17 changes: 10 additions & 7 deletions examples/custom_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ fn main() -> wry::Result<()> {
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
},
http::ResponseBuilder,
webview::WebViewBuilder,
};

Expand All @@ -22,24 +23,26 @@ fn main() -> wry::Result<()> {

let _webview = WebViewBuilder::new(window)
.unwrap()
.with_custom_protocol("wry".into(), move |requested_asset_path| {
.with_custom_protocol("wry".into(), move |request| {
// Remove url scheme
let path = requested_asset_path.replace("wry://", "");
let path = request.uri().replace("wry://", "");
// Read the file content from file path
let content = read(canonicalize(&path)?)?;

// Return asset contents and mime types based on file extentions
// If you don't want to do this manually, there are some crates for you.
// Such as `infer` and `mime_guess`.
if path.ends_with(".html") {
Ok((content, String::from("text/html")))
let (data, meta) = if path.ends_with(".html") {
(content, "text/html")
} else if path.ends_with(".js") {
Ok((content, String::from("text/javascript")))
(content, "text/javascript")
} else if path.ends_with(".png") {
Ok((content, String::from("image/png")))
(content, "image/png")
} else {
unimplemented!();
}
};

ResponseBuilder::new().mimetype(meta).body(data)
})
// tell the webview to load the custom protocol
.with_url("wry://examples/index.html")?
Expand Down
22 changes: 22 additions & 0 deletions examples/form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<h1>Welcome to WRY!</h1>
<form action="#" method="POST">
<label for="fname">First name:</label><br />
<input type="text" id="fname" name="fname" value="John" /><br />
<label for="lname">Last name:</label><br />
<input type="text" id="lname" name="lname" value="Doe" /><br /><br />
<input type="submit" value="Submit" />
</form>
<p>
If you click the "Submit" button, the form-data will be sent to the custom
protocol.
</p>
</body>
</html>
55 changes: 55 additions & 0 deletions examples/form_post.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

fn main() -> wry::Result<()> {
use std::fs::{canonicalize, read};

use wry::{
application::{
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
},
http::{method::Method, ResponseBuilder},
webview::WebViewBuilder,
};

let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Hello World")
.build(&event_loop)
.unwrap();

let _webview = WebViewBuilder::new(window)
.unwrap()
.with_custom_protocol("wry".into(), move |request| {
if request.method() == Method::POST {
let body_string = String::from_utf8_lossy(request.body());
for body in body_string.split('&') {
println!("Value sent; {:?}", body);
}
}
// Remove url scheme
let path = request.uri().replace("wry://", "");
ResponseBuilder::new()
.mimetype("text/html")
.body(read(canonicalize(&path)?)?)
})
// tell the webview to load the custom protocol
.with_url("wry://examples/form.html")?
.build()?;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::NewEvents(StartCause::Init) => println!("Wry application started!"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
_ => (),
}
});
}
77 changes: 0 additions & 77 deletions examples/html.rs

This file was deleted.

30 changes: 30 additions & 0 deletions examples/stream.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<video
id="video_source"
style="width: 90vw; height: 90vh"
controls=""
autoplay=""
name="media"
>
<source src="wry://examples/test_video.mp4" type="video/mp4" />
</video>

<script>
(function () {
if (navigator.userAgent.includes("Windows")) {
const video = document.getElementById("video_source");
const sources = video.getElementsByTagName("source");
sources[0].src = "https://wry.examples/test_video.mp4";
video.load();
}
})();
</script>
</body>
</html>
Loading

0 comments on commit d202573

Please sign in to comment.