Home > database >  Adding length limit when deserializing a String, a Vec or an Array
Adding length limit when deserializing a String, a Vec or an Array

Time:11-21

How does one add a limit over length of a String (Vec or Array) when deserializing using serde ?

Best guess is:

use serde::Deserialize;
use arrayvec::ArrayString;

#[derive(Deserialize)]
pub struct Foo {
    #[serde(try_from = "ArrayString<4096>")] // FAILS!
    bar: String,
}

Which does not work because try_from attribute is only available for "containers" and not "fields".

If there is a way to make this solution work, the main concerns are efficiency and security. Is this solution fast (not dramatically slowing down the deserialization process for short String) and safe (does it prevents the memory from being used up by a malicious request), and is it idiomatic ?

CodePudding user response:

As pointed out by @cafce25, by the point your Deserialize impl gets the string, it is already fully parsed from the input stream. This is just how serde works, and thus this restriction will not provide any protection.

You must implement this kind of restriction at the request level, or with your own parser.

If you still wish to implement a restriction like this, it's pretty simple to do with a newtype that delegates to String::deserialize:

use std::ops::Deref;
use serde::de;
use serde::Deserialize;

struct LimitedString<const MAX_LENGTH: usize>(String);

impl<const MAX_LENGTH: usize> Deref for LimitedString<MAX_LENGTH> {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'de, const MAX_LENGTH: usize> de::Deserialize<'de> for LimitedString<MAX_LENGTH> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        <String as de::Deserialize>::deserialize(deserializer).and_then(|inner| {
            if inner.len() > MAX_LENGTH {
                Err(de::Error::invalid_length(inner.len(), &"an integer lower than the maximum"))
            } else {
                Ok(Self(inner))
            }
        })
    }
}

#[derive(Deserialize)]
pub struct Foo {
    bar: LimitedString<4096>,
}

playground

  • Related