Fetch artwork offered only over http for the https page (#90)
Through ipodderx.sdf1.net the page is https, the browser upgrades an http:// image to https, and a host with no https, such as The Secret Cabal's CDN, answers nothing, so no artwork. On an https page, the page now asks /api/art for those, and ipx fetches them. It only fetches an address some feed or entry names as its artwork, and only an image, up to 5 MB, so the route cannot be pointed at anything else on the network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
33
src/web.rs
33
src/web.rs
@@ -64,6 +64,7 @@ pub fn router(state: WebState) -> Router {
|
||||
.route("/admin", get(admin_page))
|
||||
.route("/admin.js", get(admin_js))
|
||||
.route("/media/{id}", get(media))
|
||||
.route("/api/art", get(art))
|
||||
.layer(middleware::from_fn_with_state(state.clone(), auth))
|
||||
// Signing in cannot require being signed in, so these sit outside the auth layer.
|
||||
.route("/login", get(login_page))
|
||||
@@ -1676,6 +1677,38 @@ async fn media(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ArtQuery {
|
||||
u: String,
|
||||
}
|
||||
|
||||
/// Artwork a feed names on plain http, fetched here for the https page. The browser upgrades an
|
||||
/// http image on an https page to https, and a host with no https, such as The Secret Cabal's
|
||||
/// CDN, then answers nothing (issue #90).
|
||||
async fn art(State(state): State<WebState>, Query(q): Query<ArtQuery>) -> Response {
|
||||
const MAX: usize = 5 << 20;
|
||||
if !q.u.starts_with("http://") || !state.ctx.db.names_image(&q.u).await.unwrap_or(false) {
|
||||
return (StatusCode::NOT_FOUND, "no feed names that artwork").into_response();
|
||||
}
|
||||
let got = async {
|
||||
let mut r = state.ctx.client.get(&q.u).send().await?.error_for_status()?;
|
||||
let kind = r.headers().get(header::CONTENT_TYPE).and_then(|v| v.to_str().ok()).unwrap_or("").to_owned();
|
||||
anyhow::ensure!(kind.starts_with("image/"), "not an image: {kind}");
|
||||
let mut body = Vec::new();
|
||||
while let Some(c) = r.chunk().await? {
|
||||
body.extend_from_slice(&c);
|
||||
anyhow::ensure!(body.len() <= MAX, "larger than {MAX} bytes");
|
||||
}
|
||||
anyhow::Ok((kind, body))
|
||||
};
|
||||
match got.await {
|
||||
Ok((kind, body)) => {
|
||||
([(header::CONTENT_TYPE, kind), (header::CACHE_CONTROL, "private, max-age=86400".into())], body).into_response()
|
||||
}
|
||||
Err(e) => (StatusCode::BAD_GATEWAY, format!("{e:#}")).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Position {
|
||||
secs: i64,
|
||||
|
||||
Reference in New Issue
Block a user