Skip to content

Commit 3220419

Browse files
authored
fix issue with redirects in server fns creating multiple Location headers (leptos-rs#550)
1 parent a2eaf9b commit 3220419

File tree

4 files changed

+40
-26
lines changed

4 files changed

+40
-26
lines changed

integrations/axum/src/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,6 @@ async fn handle_server_fns_inner(
251251
res_options_inner.headers.clone(),
252252
);
253253

254-
if let Some(header_ref) = res.headers_mut()
255-
{
256-
header_ref.extend(res_headers.drain());
257-
};
258-
259254
if accept_header == Some("application/json")
260255
|| accept_header
261256
== Some(
@@ -285,6 +280,12 @@ async fn handle_server_fns_inner(
285280
Some(status) => res.status(status),
286281
None => res,
287282
};
283+
// This must be after the default referrer
284+
// redirect so that it overwrites the one above
285+
if let Some(header_ref) = res.headers_mut()
286+
{
287+
header_ref.extend(res_headers.drain());
288+
};
288289
match serialized {
289290
Payload::Binary(data) => res
290291
.header(

leptos_server/src/action.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ where
100100

101101
/// Updates whether the action is currently pending.
102102
pub fn set_pending(&self, pending: bool) {
103-
self.0.with_value(|a| a.pending.set(pending))
103+
self.0.try_with_value(|a| a.pending.set(pending));
104104
}
105105

106106
/// The URL associated with the action (typically as part of a server function.)

router/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ description = "Router for the Leptos web framework."
1212
leptos = { workspace = true }
1313
cfg-if = "1"
1414
common_macros = "0.1"
15-
gloo-net = "0.2"
15+
gloo-net = { version = "0.2", features = ["http"] }
1616
lazy_static = "1"
1717
linear-map = "1"
1818
log = "0.4"

router/src/components/form.rs

+32-19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use crate::{use_navigate, use_resolved_path, ToHref};
1+
use crate::{use_navigate, use_resolved_path, ToHref, Url};
22
use leptos::*;
33
use std::{error::Error, rc::Rc};
44
use wasm_bindgen::{JsCast, UnwrapThrowExt};
55
use wasm_bindgen_futures::JsFuture;
6+
use web_sys::RequestRedirect;
67

78
type OnFormData = Rc<dyn Fn(&web_sys::FormData)>;
89
type OnResponse = Rc<dyn Fn(&web_sys::Response)>;
@@ -90,12 +91,13 @@ where
9091
let res = gloo_net::http::Request::post(&action)
9192
.header("Accept", "application/json")
9293
.header("Content-Type", &enctype)
94+
.redirect(RequestRedirect::Follow)
9395
.body(params)
9496
.send()
9597
.await;
9698
match res {
9799
Err(e) => {
98-
log::error!("<Form/> error while POSTing: {e:#?}");
100+
error!("<Form/> error while POSTing: {e:#?}");
99101
if let Some(error) = error {
100102
error.set(Some(Box::new(e)));
101103
}
@@ -110,15 +112,22 @@ where
110112
if let Some(on_response) = on_response.clone() {
111113
on_response(resp.as_raw());
112114
}
113-
114-
if resp.status() == 303 {
115-
if let Some(redirect_url) =
116-
resp.headers().get("Location")
117-
{
118-
_ = navigate(
119-
&redirect_url,
120-
Default::default(),
121-
);
115+
// Check all the logical 3xx responses that might
116+
// get returned from a server function
117+
if resp.redirected() {
118+
let resp_url = &resp.url();
119+
match Url::try_from(resp_url.as_str()) {
120+
Ok(url) => {
121+
request_animation_frame(move || {
122+
if let Err(e) = navigate(
123+
&url.pathname,
124+
Default::default(),
125+
) {
126+
warn!("{}", e);
127+
}
128+
});
129+
}
130+
Err(e) => warn!("{}", e),
122131
}
123132
}
124133
}
@@ -207,7 +216,7 @@ where
207216
input.set(Some(data));
208217
action.set_pending(true);
209218
}
210-
Err(e) => log::error!("{e}"),
219+
Err(e) => error!("{e}"),
211220
}
212221
});
213222

@@ -225,15 +234,19 @@ where
225234
.as_string()
226235
.expect("couldn't get String from JsString"),
227236
) {
228-
Ok(res) => value.set(Some(Ok(res))),
229-
Err(e) => value.set(Some(Err(
230-
ServerFnError::Deserialization(e.to_string()),
231-
))),
237+
Ok(res) => {
238+
value.try_set(Some(Ok(res)));
239+
}
240+
Err(e) => {
241+
value.try_set(Some(Err(
242+
ServerFnError::Deserialization(e.to_string()),
243+
)));
244+
}
232245
}
233246
}
234-
Err(e) => log::error!("{e:?}"),
247+
Err(e) => error!("{e:?}"),
235248
};
236-
input.set(None);
249+
input.try_set(None);
237250
action.set_pending(false);
238251
});
239252
});
@@ -293,7 +306,7 @@ where
293306
let form_data = web_sys::FormData::new_with_form(&form).unwrap_throw();
294307
let data = action_input_from_form_data(&form_data);
295308
match data {
296-
Err(e) => log::error!("{e}"),
309+
Err(e) => error!("{e}"),
297310
Ok(input) => {
298311
ev.prevent_default();
299312
multi_action.dispatch(input);

0 commit comments

Comments
 (0)