Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
95bffc221b
commit
db89ea6400
+41
-1
@@ -1310,6 +1310,12 @@ fn AlternativeCard(
|
||||
};
|
||||
let Some(files) = input.files() else { continue };
|
||||
let Some(file) = files.get(0) else { continue };
|
||||
// Too big is known before a byte is sent.
|
||||
if file.size() > MAX_UPLOAD_BYTES as f64 {
|
||||
send_error.set(Some(t(&lang().get_untracked(), "upload_too_large").to_string()));
|
||||
sending.set(false);
|
||||
return;
|
||||
}
|
||||
match upload_file(&file, &question_id_for_submit, &alt_name_for_submit).await {
|
||||
Ok(key) => {
|
||||
map.insert(name.clone(), serde_json::Value::String(key));
|
||||
@@ -1319,7 +1325,8 @@ fn AlternativeCard(
|
||||
// say so.
|
||||
Err(e) => {
|
||||
leptos::logging::error!("upload of {name} failed: {e:?}");
|
||||
send_error.set(Some(t(&lang().get_untracked(), "upload_failed").to_string()));
|
||||
let status = e.as_string().and_then(|m| m.rsplit(' ').next().and_then(|n| n.parse().ok()));
|
||||
send_error.set(Some(t(&lang().get_untracked(), upload_refusal(status)).to_string()));
|
||||
sending.set(false);
|
||||
return;
|
||||
}
|
||||
@@ -2283,6 +2290,24 @@ pub fn uploaded_filename(value: &str) -> Option<&str> {
|
||||
rest.strip_prefix('-').filter(|name| shaped && !name.is_empty())
|
||||
}
|
||||
|
||||
/// The largest file one upload may carry. Here, not in `upload.rs`,
|
||||
/// so the browser checks the same number before it sends anything.
|
||||
pub const MAX_UPLOAD_BYTES: usize = 20 * 1024 * 1024;
|
||||
|
||||
/// Why an upload did not arrive, in words a person can act on, from
|
||||
/// the status `POST /upload` answered with (see `upload.rs`): too big,
|
||||
/// a site that takes no files, a page they may not send from, or
|
||||
/// anything else.
|
||||
#[cfg_attr(not(feature = "hydrate"), allow(dead_code))]
|
||||
fn upload_refusal(status: Option<u16>) -> &'static str {
|
||||
match status {
|
||||
Some(413) => "upload_too_large",
|
||||
Some(503) => "upload_unavailable",
|
||||
Some(403) => "upload_forbidden",
|
||||
_ => "upload_failed",
|
||||
}
|
||||
}
|
||||
|
||||
/// What a refused server call says, without the wrapping a person
|
||||
/// has no use for.
|
||||
fn server_message(e: &ServerFnError) -> String {
|
||||
@@ -3241,6 +3266,21 @@ mod responsible_tests {
|
||||
mod picture_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn an_upload_refusal_says_which_it_was() {
|
||||
assert_eq!(upload_refusal(Some(413)), "upload_too_large");
|
||||
assert_eq!(upload_refusal(Some(503)), "upload_unavailable");
|
||||
assert_eq!(upload_refusal(Some(403)), "upload_forbidden");
|
||||
assert_eq!(upload_refusal(Some(502)), "upload_failed");
|
||||
assert_eq!(upload_refusal(None), "upload_failed");
|
||||
for lang in ["en", "no"] {
|
||||
for status in [Some(413), Some(503), Some(403), None] {
|
||||
let key = upload_refusal(status);
|
||||
assert_ne!(crate::i18n::t(lang, key), key, "{lang} has words for {key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_record_with_a_picture_is_shown_by_it() {
|
||||
assert!(is_picture("Portrett.JPG") && is_picture("a.webp") && !is_picture("rapport.pdf"));
|
||||
|
||||
Reference in New Issue
Block a user