mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-22 19:08:51 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd807693e9 |
No files matched your search
@@ -111,7 +111,13 @@ fn serve(mut out: TcpStream, queue: Queue, ctx: CtxSlot, timeout: Duration) -> s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => json!({"id": null, "ok": false, "error": format!("bad JSON: {e}")}),
|
Err(e) => {
|
||||||
|
// A line that isn't JSON ends the connection: a web page can make the browser send
|
||||||
|
// an HTTP request here, and its header lines must not let the JSON lines of its body
|
||||||
|
// through as commands.
|
||||||
|
writeln!(out, "{}", json!({"id": null, "ok": false, "error": format!("bad JSON: {e}")}))?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
writeln!(out, "{reply}")?;
|
writeln!(out, "{reply}")?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,8 @@ fn valid_frames_keep_their_order_ids_and_parameters() {
|
|||||||
let pending = queue();
|
let pending = queue();
|
||||||
let q = pending.clone();
|
let q = pending.clone();
|
||||||
let worker = std::thread::spawn(move || serve(server, q, context(), Duration::from_secs(5)));
|
let worker = std::thread::spawn(move || serve(server, q, context(), Duration::from_secs(5)));
|
||||||
client.write_all(b"\r\n{bad JSON}\n{\"id\":\"test\",\"method\":\"engine.execute\",\"params\":{\"command\":\"shape.rectangle\"}}\r\n").unwrap();
|
client.write_all(b"\r\n{\"id\":\"test\",\"method\":\"engine.execute\",\"params\":{\"command\":\"shape.rectangle\"}}\r\n").unwrap();
|
||||||
let mut reader = BufReader::new(client);
|
let mut reader = BufReader::new(client);
|
||||||
assert_eq!(reply(&mut reader)["ok"], false);
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let r = loop {
|
let r = loop {
|
||||||
if let Some(r) = pending.lock().unwrap().pop() {
|
if let Some(r) = pending.lock().unwrap().pop() {
|
||||||
@@ -73,6 +72,23 @@ fn valid_frames_keep_their_order_ids_and_parameters() {
|
|||||||
worker.join().unwrap().unwrap();
|
worker.join().unwrap().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_line_that_is_not_json_ends_the_connection_before_anything_after_it_runs() {
|
||||||
|
// What a browser sends when a web page posts to the port: the JSON line in its body never runs.
|
||||||
|
let (mut client, server) = pair();
|
||||||
|
let pending = queue();
|
||||||
|
let q = pending.clone();
|
||||||
|
let worker = std::thread::spawn(move || serve(server, q, context(), Duration::from_secs(5)));
|
||||||
|
let body = "{\"id\":1,\"method\":\"engine.execute\",\"params\":{\"command\":\"file.save\"}}\n";
|
||||||
|
let http = format!("POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\r\n{body}", body.len());
|
||||||
|
client.write_all(http.as_bytes()).unwrap();
|
||||||
|
let mut reader = BufReader::new(client);
|
||||||
|
assert_eq!(reply(&mut reader)["ok"], false);
|
||||||
|
assert_eq!(reader.read(&mut [0]).unwrap(), 0, "the connection is closed");
|
||||||
|
worker.join().unwrap().unwrap();
|
||||||
|
assert!(pending.lock().unwrap().is_empty(), "nothing was dispatched");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn full_queue_rejects_before_dispatch_and_ui_queue_stays_bounded() {
|
fn full_queue_rejects_before_dispatch_and_ui_queue_stays_bounded() {
|
||||||
let (mut client, server) = pair();
|
let (mut client, server) = pair();
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ reply: {"id": 1, "ok": true, "result": ...}
|
|||||||
|
|
||||||
Requests are queued and run on the UI thread at the start of the next frame, so replies reflect the
|
Requests are queued and run on the UI thread at the start of the next frame, so replies reflect the
|
||||||
real UI state. A request that the UI doesn't answer within 60 s gets a timeout error. A line that is
|
real UI state. A request that the UI doesn't answer within 60 s gets a timeout error. A line that is
|
||||||
not JSON gets `{"id": null, "ok": false, "error": "bad JSON: …"}`. The implementation is in
|
not JSON gets `{"id": null, "ok": false, "error": "bad JSON: …"}` and ends the connection (so an
|
||||||
|
HTTP request a web page makes the browser send here never runs). The implementation is in
|
||||||
`crates/ui-egui/src/control.rs` (methods) and `apps/figcraft/src/control_server.rs` (socket).
|
`crates/ui-egui/src/control.rs` (methods) and `apps/figcraft/src/control_server.rs` (socket).
|
||||||
|
|
||||||
A request line is limited to **32 MiB before the newline**, including whitespace. The reader stops
|
A request line is limited to **32 MiB before the newline**, including whitespace. The reader stops
|
||||||
|
|||||||
Reference in new issue
Block a user