Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong flash message when name is numeric #1263

Closed
ThibaudDauce opened this issue Mar 31, 2020 · 4 comments
Closed

Wrong flash message when name is numeric #1263

ThibaudDauce opened this issue Mar 31, 2020 · 4 comments
Labels
bug Deviation from the specification or expected behavior

Comments

@ThibaudDauce
Copy link

ThibaudDauce commented Mar 31, 2020

Hi,

I'm using Rocket v0.4.4. My code is available in https://gitlab.com/thibauddauce/youtube-rust-rocket/-/commit/ae858382ac3b85b51fa9c77d04febffe73829f43.

When I set the flash name as an integer, the flash message is split in the following request.

#[get("/create_flash")]
fn create_flash() -> Flash<Redirect> {
    let id = 1;

    let flash = Flash::new(Redirect::to("/show_flash"), id.to_string(), "Some very long text");

    dbg!(&flash);

    flash
}

#[get("/show_flash")]
fn show_flash(flash: Option<FlashMessage>) {
    let flash_content = flash.unwrap();

    dbg!(flash_content.name());
    dbg!(flash_content.msg());
}

The result:

GET /create_flash text/html:
    => Matched: GET /create_flash (create_flash)
[src/main.rs:77] &flash = Flash {
    name: "1",
    message: "Some really long text",
    consumed: false,
    inner: Redirect(
        Status {
            code: 303,
            reason: "See Other",
        },
        Some(
            Origin(
                Origin {
                    source: Some(
                        "/show_flash",
                    ),
                    path: (
                        0,
                        11,
                    ),
                    query: None,
                    segment_count: [uninitialized storage],
                },
            ),
        ),
    ),
}
    => Outcome: Success
    => Response succeeded.
GET /show_flash text/html:
    => Matched: GET /show_flash (show_flash)
[src/main.rs:86] flash_content.name() = "Some really"
[src/main.rs:87] flash_content.msg() = " long text"
    => Outcome: Success
    => Response succeeded.

If the flash message is shorter like "Some text", the flash is not set.

GET /create_flash text/html:
    => Matched: GET /create_flash (create_flash)
[src/main.rs:77] &flash = Flash {
    name: "1",
    message: "Some text",
…
}
    => Outcome: Success
    => Response succeeded.
GET /show_flash text/html:
    => Matched: GET /show_flash (show_flash)
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:84:25
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

If the name is 9 the split happen later:

GET /create_flash text/html:
    => Matched: GET /create_flash (create_flash)
[src/main.rs:77] &flash = Flash {
    name: "9",
    message: "Some really really really long text Some really really really long text",
…
}
    => Outcome: Success
    => Response succeeded.
GET /show_flash text/html:
    => Matched: GET /show_flash (show_flash)
[src/main.rs:86] flash_content.name() = "Some really really "
[src/main.rs:87] flash_content.msg() = "really long text Some really really really long text"
    => Outcome: Success
    => Response succeeded.

If the name is 10 the flash is not set:

GET /create_flash text/html:
    => Matched: GET /create_flash (create_flash)
[src/main.rs:77] &flash = Flash {
    name: "10",
    message: "Some really really really long text Some really really really long text",
…
    => Outcome: Success
    => Response succeeded.
GET /show_flash text/html:
    => Matched: GET /show_flash (show_flash)
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:84:25
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

If the name is "1a" (not numeric) the split is even weirder:

GET /create_flash text/html:
    => Matched: GET /create_flash (create_flash)
[src/main.rs:75] &flash = Flash {
    name: "1a",
    message: "Some really really really long text Some really really really long text",
…
}
    => Outcome: Success
    => Response succeeded.
GET /show_flash text/html:
    => Matched: GET /show_flash (show_flash)
[src/main.rs:84] flash_content.name() = "aSome really really r"
[src/main.rs:85] flash_content.msg() = "eally long text Some really really really long text"
    => Outcome: Success
    => Response succeeded.

I really don't understand the problem. Don't hesitate if you need me to do additional checks.

My real problem is that I have multiple forms on my page, and I want to associate an ID to my flash message to show the message near the corresponding form. I don't know how to do that in Rocket. I thought using the name part to store the ID but it's not working :-D

@jebrosen
Copy link
Collaborator

This is a deficiency in the encoding scheme for the flash message cookie: <name_length><name><msg>. ("1", "Some really long text") encodes as 11Some really long text but decodes as 11 (length of name), Some really (the next 11 characters) in name, followed by the rest in msg.

The workaround is to start the name with non-digits.

To fix, we should change the flash message encoding. For example, adding a delimiter character to end the length field: 1;1Some really long text

@jebrosen jebrosen added the bug Deviation from the specification or expected behavior label Mar 31, 2020
@ThibaudDauce
Copy link
Author

ThibaudDauce commented Mar 31, 2020

Thanks a lot for the explanation. By the way, is there a cleaner way to flash a struct (ID of the form + message) with Rocket? Maybe just use JSON serialization in the message field?

@jebrosen
Copy link
Collaborator

Sure! If the message you are storing is structlike, you can serialize it with something like serde_json::to_string and serde_json::from_str to deserialize it.

But if you only need ID + text, you could use a dummy name like "message" and something like "4:Text for form 4" as the msg, splitting the msg field at the : when you read it.

@ThibaudDauce
Copy link
Author

Yes it's even easier :-D Thanks for the tip!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Deviation from the specification or expected behavior
Projects
None yet
Development

No branches or pull requests

2 participants