Improve render lifecycle, geometry, and PDF parity
This commit is contained in:
1 parent
50b2ea14ff
commit
68f20cf525
12 files changed
+3279
-411
No files matched your search
@@ -8,9 +8,15 @@ use std::io::{Read, Write};
|
||||
|
||||
use obscura::Browser;
|
||||
|
||||
/// Minimal HTTP/1.1 server returning HTML that wraps document.createElement to
|
||||
/// plant a non-configurable `src` on every <img>, then calls `new Image()`.
|
||||
/// Minimal HTTP/1.1 server returning the test page and a valid 1x1 PNG.
|
||||
fn spawn_server(html: &'static str) -> String {
|
||||
const PIXEL_PNG: &[u8] = &[
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48,
|
||||
0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00,
|
||||
0x00, 0x1f, 0x15, 0xc4, 0x89, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x44, 0x41, 0x54, 0x78,
|
||||
0xda, 0x63, 0xfc, 0xcf, 0xc0, 0x50, 0x0f, 0x00, 0x05, 0x83, 0x02, 0x7f, 0x94, 0xff,
|
||||
0x2f, 0x59, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
||||
];
|
||||
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
std::thread::spawn(move || {
|
||||
@@ -20,13 +26,19 @@ fn spawn_server(html: &'static str) -> String {
|
||||
Err(_) => continue,
|
||||
};
|
||||
let mut buf = [0u8; 2048];
|
||||
let _ = s.read(&mut buf);
|
||||
let resp = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
|
||||
html.len(),
|
||||
html
|
||||
let read = s.read(&mut buf).unwrap_or(0);
|
||||
let is_pixel = buf[..read].starts_with(b"GET /pixel.png ");
|
||||
let (content_type, body) = if is_pixel {
|
||||
("image/png", PIXEL_PNG)
|
||||
} else {
|
||||
("text/html", html.as_bytes())
|
||||
};
|
||||
let headers = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: {content_type}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
|
||||
body.len()
|
||||
);
|
||||
let _ = s.write_all(resp.as_bytes());
|
||||
let _ = s.write_all(headers.as_bytes());
|
||||
let _ = s.write_all(body);
|
||||
let _ = s.shutdown(std::net::Shutdown::Both);
|
||||
}
|
||||
});
|
||||
@@ -100,3 +112,39 @@ async fn new_image_still_emulates_load_when_src_is_configurable() {
|
||||
"load emulation regressed for the normal (configurable src) path"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_image_bytes_emit_error_like_chromium() {
|
||||
std::env::set_var("OBSCURA_ALLOW_PRIVATE_NETWORK", "1");
|
||||
let base = spawn_server(
|
||||
r#"<!doctype html><html><body><div id="r">waiting</div>
|
||||
<script>
|
||||
var img = new Image();
|
||||
img.onerror = function () {
|
||||
document.getElementById('r').textContent =
|
||||
'error complete=' + img.complete +
|
||||
' natural=' + img.naturalWidth + 'x' + img.naturalHeight;
|
||||
};
|
||||
img.src = '/broken.png';
|
||||
</script>
|
||||
</body></html>"#,
|
||||
);
|
||||
|
||||
let browser = Browser::new().unwrap();
|
||||
let mut page = browser.new_page().await.unwrap();
|
||||
page.goto(&base).await.unwrap();
|
||||
for _ in 0..10 {
|
||||
page.settle(500).await;
|
||||
let text = page.evaluate("document.getElementById('r').textContent");
|
||||
if text.as_str().unwrap_or("").starts_with("error") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let text = page.evaluate("document.getElementById('r').textContent");
|
||||
assert_eq!(
|
||||
text.as_str().unwrap_or(""),
|
||||
"error complete=true natural=0x0",
|
||||
"invalid image bytes must fail instead of being treated as a decoded image"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user