#xml #escaping #writer #markup #html #string-literal

yanked xmlsafe

A streaming XML writer that protects you from XML injections through type safety

0.5.3 Aug 28, 2021
0.5.2 Aug 26, 2021
0.4.0 Aug 19, 2021
0.3.0 Aug 19, 2021
0.1.0 Aug 14, 2021

#14 in #escape

MIT license

25KB
410 lines

xmlsafe

A streaming XML writer that:

  • prevents accidental XML injections by requiring its arguments to implement specific traits

  • provides a tag! macro to structure your code (designed to play well with rustfmt)

If you forget to escape a string, your code just doesn't compile. To be safe from XML injections keep two things in mind:

  1. Whenever you supply a string literal (&'static str), take care that it is syntactically valid for the respective context.

  2. Whenever you implement one of the traits, take care that you fulfill its requirements.

Example

use std::fmt::Error;
use xmlsafe::{XmlWriter, format_text, escape_text, tag};

struct User {name: String, id: u8}

fn list_users(mut w: XmlWriter, users: Vec<User>) -> Result<(), Error> {
    tag!(w, "div", "class"="users", {
        w.write(format_text!("There are {} users:", users.len()))?;
        tag!(w, "ul", {
            for user in users {
                tag!(w, "li", "data-id"=user.id, {
                    w.write(escape_text(user.name))?;
                });
            }
        });
    });
    Ok(())
}

fn main() {
    let mut out = String::new();
    let users = vec![User{name: "Alice".into(), id: 3}, User{name: "Bob".into(), id: 5}];
    list_users(XmlWriter::new(&mut out), users).unwrap();
    assert_eq!(out, "<div class=\"users\">There are 2 users:\
        <ul><li data-id=\"3\">Alice</li><li data-id=\"5\">Bob</li></ul></div>");
}

Note how the XmlWriter acts as a protective layer between the actual write target (the String in our example) and the XML generation code. Also note that if we forgot the escape_text call, the example would not compile.

Safety

xmlsafe forbids unsafe code and does not panic.

No runtime deps