Skip to content

Commit

Permalink
fix!: char ssr
Browse files Browse the repository at this point in the history
  • Loading branch information
EqualMa committed Apr 25, 2024
1 parent fd3b46c commit ac73bf0
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 6 deletions.
8 changes: 8 additions & 0 deletions crates/frender-ssr-html/src/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ mod html_children {
{
}

impl Sealed for crate::char::IterCharStringEncodeSafe {}
impl HtmlChildren for crate::char::IterCharStringEncodeSafe {}

macro_rules! impl_for_tuple {
($($iter:ident ($($field:ident),+) ,)+) => {$(
impl<$($field: Sealed + AsyncStrIterator),+> Sealed for async_str_iter::concat::$iter<$($field),+> {}
Expand Down Expand Up @@ -314,6 +317,9 @@ mod one_string_or_empty {
for async_str_iter::either::IterEither<L, R>
{
}

impl Sealed for crate::char::IterCharStringEncodeSafe {}
impl OneStringOrEmpty for crate::char::IterCharStringEncodeSafe {}
}

pub trait OneString: OneStringOrEmpty {}
Expand All @@ -324,4 +330,6 @@ mod one_string {
impl OneString for &str {}
impl<S: AsRef<str>> OneString for async_str_iter::any_str::IterAnyStr<S> {}
impl<L: OneString, R: OneString> OneString for async_str_iter::either::IterEither<L, R> {}

impl OneString for crate::char::IterCharStringEncodeSafe {}
}
57 changes: 57 additions & 0 deletions crates/frender-ssr-html/src/char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/// [`html_escape::encode_safe`]
fn char_encode_safe(c: char) -> Option<&'static str> {
match c {
'&' => Some("&amp;"),
'<' => Some("&lt;"),
'>' => Some("&gt;"),
'"' => Some("&quot;"),
'\'' => Some("&#x27;"),
'/' => Some("&#x2F;"),
_ => None,
}
}

struct CharString {
value: char,
buf: [u8; 4],
}

impl CharString {
fn new(value: char) -> Self {
Self { value, buf: [0; 4] }
}

fn encode_safe(&mut self) -> &str {
char_encode_safe(self.value).unwrap_or_else(|| self.value.encode_utf8(&mut self.buf))
}
}

pub struct IterCharStringEncodeSafe {
taken: bool,
char_string: CharString,
}

impl IterCharStringEncodeSafe {
pub fn new(c: char) -> Self {
Self {
taken: false,
char_string: CharString::new(c),
}
}
}

impl async_str_iter::AsyncStrIterator for IterCharStringEncodeSafe {
fn poll_next_str(
self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<&str>> {
let this = self.get_mut();
if this.taken {
return std::task::Poll::Ready(None);
}

this.taken = true;
let s = this.char_string.encode_safe();
std::task::Poll::Ready(Some(s))
}
}
1 change: 1 addition & 0 deletions crates/frender-ssr-html/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod assert;
pub mod attr;
pub mod attr_value;
pub mod char;
pub mod element;
pub mod encode;
pub mod escape_safe;
Expand Down
4 changes: 1 addition & 3 deletions crates/frender-ssr-html/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ macro_rules! impl_from {
}

impl_from!(
impl<__> From<i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64, char>
for Scalar
{
impl<__> From<i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64> for Scalar {
fn from(value: _) -> Self {
Scalar(AnyStr(value.to_string()).into_async_str_iterator())
}
Expand Down
11 changes: 11 additions & 0 deletions crates/frender-ssr/src/element/char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use frender_ssr_html::char::IterCharStringEncodeSafe;

use crate::SsrElement;

impl SsrElement for char {
type HtmlChildren = IterCharStringEncodeSafe;

fn into_html_children(self) -> Self::HtmlChildren {
IterCharStringEncodeSafe::new(self)
}
}
1 change: 1 addition & 0 deletions crates/frender-ssr/src/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ pub mod option;
pub mod str;
pub mod tuple;

mod char;
mod scalar;
4 changes: 1 addition & 3 deletions crates/frender-ssr/src/element/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ use crate::SsrElement;

frender_common::impl_many!(
impl<__> SsrElement
for each_of![
i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64, char,
]
for each_of![i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64]
{
type HtmlChildren = frender_ssr_html::scalar::Scalar;

Expand Down
29 changes: 29 additions & 0 deletions crates/frender/tests/safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use frender::prelude::*;

fn separated_html() -> impl Element {
("<", "script>alert('DANGER')</", "script>")
}

#[test]
fn separated_html_is_safe() {
let out = futures_lite::future::block_on(separated_html().render_to_string());

assert_eq!(
out,
"&lt;script&gt;alert(&#x27;DANGER&#x27;)&lt;&#x2F;script&gt;"
);
}

#[test]
fn chars_are_safe() {
let chars = [
'<', 's', 'c', 'r', 'i', 'p', 't', '>', 'a', 'l', 'e', 'r', 't', '(', '\'', 'D', 'A', 'N',
'G', 'E', 'R', '\'', ')', '<', '/', 's', 'c', 'r', 'i', 'p', 't', '>',
];
let out = futures_lite::future::block_on(chars.render_to_string());

assert_eq!(
out,
"&lt;script&gt;alert(&#x27;DANGER&#x27;)&lt;&#x2F;script&gt;"
);
}

0 comments on commit ac73bf0

Please sign in to comment.