axum-flash icon indicating copy to clipboard operation
axum-flash copied to clipboard

Seeing inconsistent behaviour for different routes

Open 66OJ66 opened this issue 3 years ago • 17 comments

Hi, I'm encountering odd behaviour when flashing messages for different routes in my Axum server and I'm not quite sure what the issue is.

For example, I have these routes for registering new users (under /register):

pub async fn get_register(flash: IncomingFlashes, Extension(tera): Extension<Tera>) -> Html<String> {
   let mut context = tera::Context::new();
   if flash.len() == 1{
       context.insert("message", flash.iter().nth(0).unwrap().1);
   }

   Html(tera.render("register.html.tera", &context).unwrap())
}

pub async fn post_register(
    form: Form<Register>,
    mut flash: Flash,
    DatabaseConnection(conn): DatabaseConnection,
) -> Redirect {
// Try to register the user
// [......]
   Ok(_) => Redirect::to("/login"),

   Err(e) => {
      flash.error("Unable to register user");
      Redirect::to("/register")
   }
}

The flashing functionality works as expected for these routes (i.e. if there's an error during registration, the user is redirected and the flash message is shown. Upon refreshing the page, the flash message is cleared.

I then have some other routes (under /types/create) which are very similar to the above, but the flash message persists even after refreshing the page (and I can see the 'axum-flash' cookie stored in my browser after refreshing).

pub async fn get_create_type(flash: IncomingFlashes, Extension(tera): Extension<Tera>) -> Html<String>{
    let mut context = tera::Context::new();
    if flash.len() == 1{
        context.insert("message", flash.iter().nth(0).unwrap().1);
    }

    Html(tera.render("new_type.html.tera", &context).unwrap())
}

pub async fn post_create_type(
    form: Form<PostNewType>,
    mut flash: Flash,
    DatabaseConnection(conn): DatabaseConnection,
) -> Redirect {
   // Logic to create a new type
   // If a type with that name exists already, do:
   flash.error("Type already exists");
   Redirect::to("/types/create")
}

In these other routes, I've tried adding extra code to forcibly remove the 'axum-flash' cookie (I also tried using the other 2 types of CookieJar as well), but it still persists:

pub async fn get_create_type(flash: IncomingFlashes, jar: CookieJar, Extension(tera): Extension<Tera>) -> impl IntoResponse{
    let mut context = tera::Context::new();
    if flash.len() == 1{
        context.insert("message", flash.iter().nth(0).unwrap().1);
    }

    // Attempt to remove the 'axum-flash' cookie
    let updated_jar: CookieJar = jar.remove(Cookie::named("axum-flash"));

    (updated_jar, Html(tera.render("new_type.html.tera", &context).unwrap()))
}

From this page (/types/create) with the persistent cookie, if I then navigate back to the /register route and refresh the page, the cookie is cleared.

Can you think of any reason why in some instances the flash cookie is cleared, but in other cases it's not? Let me know if you need more details on anything

66OJ66 avatar May 03 '22 20:05 66OJ66

Hm that sounds pretty weird. Not sure what's going on.

Are you able to make a minimal example that I can cargo run?

davidpdrsn avatar May 03 '22 20:05 davidpdrsn

I've uploaded a minimal example here: https://github.com/66OJ66/flash_testing

I think the error is related to paths with multiple segments i.e. when creating this example, using /do_a_thing as the route didn't cause any issues, but using /do/a/thing yields the error I mentioned above. Possibly using SameSite = Strict in the flash cookie is causing this issue?

66OJ66 avatar May 03 '22 21:05 66OJ66

Hi, are you able to reproduce the example on your end using the code I linked to above?

66OJ66 avatar Jun 05 '22 17:06 66OJ66

I haven't had time to look more into it. Did you get it working?

davidpdrsn avatar Jun 05 '22 18:06 davidpdrsn

Getting the exact same issue here. My login route is /accounts/login and the flash cookie does not seem to be cleared properly, so the flash message stays there forever. It's also visible in the Firefox session storage:

image

Changing the login route to /login makes it work perfectly, and the cookie disappears before I even have the time to look at it.

Bauxitedev avatar Jun 29 '22 12:06 Bauxitedev

Update: I've found a consistent workaround for the problem, by manually clearing the cookie:


async fn your_route_here(
    cookies: Cookies,
    flashes: IncomingFlashes,
) -> impl IntoResponse {

    //TODO use `flashes` here
    
    //Manually delete the cookie
    let mut flash_killer = Cookie::named("axum-flash");
    flash_killer.make_removal();
    flash_killer.set_path("/");
    cookies.add(flash_killer);

    //TODO return your response here

}

You need to use the Cookies extractor, not CookieJar (since the former overrides the latter).

Also note there is a subtle difference between CookieJar::remove() and Cookie::make_removal(). The former doesn't actually delete the cookie, it just removes it from the server side cookie jar. You need to explicitly overwrite the cookie to modify/delete it on the client side.

~~Also ensure you've got the CookieManagerLayer added to your middleware stack, in addition to the axum_flash::layer. Even if you call with_cookie_manager(), the cookie manager will not be available to your own routes if you don't explicitly add it. For example:~~ Update: this is caused by having a version mismatch between tower-cookies 0.7.0 and 0.6.0 (the latter version is used by axum-flash 0.4.0). Downgrade your version of tower-cookies to 0.6.0 to fix it.

 Router::new()
   .layer(
            ServiceBuilder::new()
                .layer(axum_flash::layer(cookie_key).with_cookie_manager())
                .layer(CookieManagerLayer::new()) 
        );

Bauxitedev avatar Jun 29 '22 13:06 Bauxitedev

You need to use the Cookies extractor, not CookieJar (since the former overrides the latter).

You mean CookieJar from axum-extra? Yes those two are probably conflicting. I really should convert this library use axum-extra's CookieJar.

Also ensure you've got the CookieManagerLayer added to your middleware stack, in addition to the axum_flash::layer. Even if you call with_cookie_manager(), the cookie manager will not be available to your own routes if you don't explicitly add it. For example:

That doesn't sound right to me. The CookieManagerLayer is pushed here when you call with_cookie_manager so need need to add it twice. There must be something else going on.

davidpdrsn avatar Jun 29 '22 14:06 davidpdrsn

Whoops didn't mean to close this.

I would encourage you to pull this repo down and debug it. I dunno when I'll have time to look into it.

davidpdrsn avatar Jun 29 '22 14:06 davidpdrsn

@davidpdrsn If I don't explicitly add the CookieManagerLayer to my layer stack, I get this error...

Can't extract cookies. Is CookieManagerLayer enabled?

...in the your_route_here I defined above: https://github.com/davidpdrsn/axum-flash/issues/4#issuecomment-1170012587. Even if I call .with_cookie_manager() on the axum_flash::layer.

Maybe it has something to do with the order of the layers?

Bauxitedev avatar Jun 29 '22 14:06 Bauxitedev

Maybe it has something to do with the order of the layers?

Not sure 🤷

davidpdrsn avatar Jun 29 '22 14:06 davidpdrsn

@davidpdrsn Why did you close this issue?

Bauxitedev avatar Jun 29 '22 15:06 Bauxitedev

Huh I didn't do that knowingly.

davidpdrsn avatar Jun 29 '22 16:06 davidpdrsn

Lol either something happened on github or my computer. When I press command+enter to submit a comment it hits the "Close with comment" button and not the "Comment" button 🤦

davidpdrsn avatar Jun 29 '22 16:06 davidpdrsn

Can't extract cookies. Is CookieManagerLayer enabled?

I just got this error and it was caused by two incompatible tower-cookies versions.

ssendev avatar Aug 11 '22 18:08 ssendev

@ssendev Thank you, that turned out to be the issue! axum-flash 0.4.0 uses tower-cookies 0.6.0, even though 0.7.0 is available. I'll update my workaround.

Bauxitedev avatar Aug 19 '22 10:08 Bauxitedev

Oh I didn't realize. Are you up for submitting a PR that updates axum-flash?

davidpdrsn avatar Aug 19 '22 10:08 davidpdrsn

I've published axum-flash 0.5 which users tower-cookies 0.7.

davidpdrsn avatar Aug 23 '22 17:08 davidpdrsn