fix issue with redirects in server fns creating multiple Location headers (#550)

This commit is contained in:
Ben Wishovich 2023-02-20 05:55:47 -08:00 committed by GitHub
parent a2eaf9b3ee
commit 322041917d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 26 deletions

View file

@ -251,11 +251,6 @@ async fn handle_server_fns_inner(
res_options_inner.headers.clone(),
);
if let Some(header_ref) = res.headers_mut()
{
header_ref.extend(res_headers.drain());
};
if accept_header == Some("application/json")
|| accept_header
== Some(
@ -285,6 +280,12 @@ async fn handle_server_fns_inner(
Some(status) => res.status(status),
None => res,
};
// This must be after the default referrer
// redirect so that it overwrites the one above
if let Some(header_ref) = res.headers_mut()
{
header_ref.extend(res_headers.drain());
};
match serialized {
Payload::Binary(data) => res
.header(

View file

@ -100,7 +100,7 @@ where
/// Updates whether the action is currently pending.
pub fn set_pending(&self, pending: bool) {
self.0.with_value(|a| a.pending.set(pending))
self.0.try_with_value(|a| a.pending.set(pending));
}
/// The URL associated with the action (typically as part of a server function.)

View file

@ -12,7 +12,7 @@ description = "Router for the Leptos web framework."
leptos = { workspace = true }
cfg-if = "1"
common_macros = "0.1"
gloo-net = "0.2"
gloo-net = { version = "0.2", features = ["http"] }
lazy_static = "1"
linear-map = "1"
log = "0.4"

View file

@ -1,8 +1,9 @@
use crate::{use_navigate, use_resolved_path, ToHref};
use crate::{use_navigate, use_resolved_path, ToHref, Url};
use leptos::*;
use std::{error::Error, rc::Rc};
use wasm_bindgen::{JsCast, UnwrapThrowExt};
use wasm_bindgen_futures::JsFuture;
use web_sys::RequestRedirect;
type OnFormData = Rc<dyn Fn(&web_sys::FormData)>;
type OnResponse = Rc<dyn Fn(&web_sys::Response)>;
@ -90,12 +91,13 @@ where
let res = gloo_net::http::Request::post(&action)
.header("Accept", "application/json")
.header("Content-Type", &enctype)
.redirect(RequestRedirect::Follow)
.body(params)
.send()
.await;
match res {
Err(e) => {
log::error!("<Form/> error while POSTing: {e:#?}");
error!("<Form/> error while POSTing: {e:#?}");
if let Some(error) = error {
error.set(Some(Box::new(e)));
}
@ -110,15 +112,22 @@ where
if let Some(on_response) = on_response.clone() {
on_response(resp.as_raw());
}
if resp.status() == 303 {
if let Some(redirect_url) =
resp.headers().get("Location")
{
_ = navigate(
&redirect_url,
Default::default(),
);
// Check all the logical 3xx responses that might
// get returned from a server function
if resp.redirected() {
let resp_url = &resp.url();
match Url::try_from(resp_url.as_str()) {
Ok(url) => {
request_animation_frame(move || {
if let Err(e) = navigate(
&url.pathname,
Default::default(),
) {
warn!("{}", e);
}
});
}
Err(e) => warn!("{}", e),
}
}
}
@ -207,7 +216,7 @@ where
input.set(Some(data));
action.set_pending(true);
}
Err(e) => log::error!("{e}"),
Err(e) => error!("{e}"),
}
});
@ -225,15 +234,19 @@ where
.as_string()
.expect("couldn't get String from JsString"),
) {
Ok(res) => value.set(Some(Ok(res))),
Err(e) => value.set(Some(Err(
ServerFnError::Deserialization(e.to_string()),
))),
Ok(res) => {
value.try_set(Some(Ok(res)));
}
Err(e) => {
value.try_set(Some(Err(
ServerFnError::Deserialization(e.to_string()),
)));
}
}
}
Err(e) => log::error!("{e:?}"),
Err(e) => error!("{e:?}"),
};
input.set(None);
input.try_set(None);
action.set_pending(false);
});
});
@ -293,7 +306,7 @@ where
let form_data = web_sys::FormData::new_with_form(&form).unwrap_throw();
let data = action_input_from_form_data(&form_data);
match data {
Err(e) => log::error!("{e}"),
Err(e) => error!("{e}"),
Ok(input) => {
ev.prevent_default();
multi_action.dispatch(input);