Skip to content

Commit

Permalink
fix(codegen): serialize template tags, closes #4410 (#5247)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Sep 28, 2022
1 parent 4c5a303 commit aec5537
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changes/fix-html-template.md
@@ -0,0 +1,6 @@
---
"tauri-utils": patch
"tauri-codegen": patch
---

Properly serialize HTML template tags.
12 changes: 7 additions & 5 deletions core/tauri-codegen/src/context.rs
Expand Up @@ -11,7 +11,9 @@ use sha2::{Digest, Sha256};

use tauri_utils::assets::AssetKey;
use tauri_utils::config::{AppUrl, Config, PatternKind, WindowUrl};
use tauri_utils::html::{inject_nonce_token, parse as parse_html};
use tauri_utils::html::{
inject_nonce_token, parse as parse_html, serialize_node as serialize_html_node,
};

#[cfg(feature = "shell-scope")]
use tauri_utils::config::{ShellAllowedArg, ShellAllowedArgs, ShellAllowlistScope};
Expand All @@ -37,10 +39,10 @@ fn map_core_assets(
options.dangerous_disable_asset_csp_modification.clone();
move |key, path, input, csp_hashes| {
if path.extension() == Some(OsStr::new("html")) {
let mut document = parse_html(String::from_utf8_lossy(input).into_owned());

#[allow(clippy::collapsible_if)]
if csp {
let mut document = parse_html(String::from_utf8_lossy(input).into_owned());

if target == Target::Linux {
::tauri_utils::html::inject_csp_token(&mut document);
}
Expand Down Expand Up @@ -77,9 +79,9 @@ fn map_core_assets(
.push(format!("'sha256-{}'", base64::encode(&hash)));
}
}
}

*input = document.to_string().as_bytes().to_vec();
*input = serialize_html_node(&document);
}
}
Ok(())
}
Expand Down
94 changes: 92 additions & 2 deletions core/tauri-utils/src/html.rs
Expand Up @@ -6,9 +6,15 @@

use std::path::{Path, PathBuf};

use html5ever::{interface::QualName, namespace_url, ns, tendril::TendrilSink, LocalName};
use html5ever::{
interface::QualName,
namespace_url, ns,
serialize::{HtmlSerializer, SerializeOpts, Serializer, TraversalScope},
tendril::TendrilSink,
LocalName,
};
pub use kuchiki::NodeRef;
use kuchiki::{Attribute, ExpandedName};
use kuchiki::{Attribute, ExpandedName, NodeData};
use serde::Serialize;
#[cfg(feature = "isolation")]
use serialize_to_javascript::DefaultTemplate;
Expand All @@ -24,6 +30,90 @@ pub const SCRIPT_NONCE_TOKEN: &str = "__TAURI_SCRIPT_NONCE__";
/// The token used for style nonces.
pub const STYLE_NONCE_TOKEN: &str = "__TAURI_STYLE_NONCE__";

// taken from https://github.com/kuchiki-rs/kuchiki/blob/57ee6920d835315a498e748ba4b07a851ae5e498/src/serializer.rs#L12
fn serialize_node_ref_internal<S: Serializer>(
node: &NodeRef,
serializer: &mut S,
traversal_scope: TraversalScope,
) -> crate::Result<()> {
match (traversal_scope, node.data()) {
(ref scope, &NodeData::Element(ref element)) => {
if *scope == TraversalScope::IncludeNode {
let attrs = element.attributes.borrow();

// Unfortunately we need to allocate something to hold these &'a QualName
let attrs = attrs
.map
.iter()
.map(|(name, attr)| {
(
QualName::new(attr.prefix.clone(), name.ns.clone(), name.local.clone()),
&attr.value,
)
})
.collect::<Vec<_>>();

serializer.start_elem(
element.name.clone(),
attrs.iter().map(|&(ref name, value)| (name, &**value)),
)?
}

let children = match element.template_contents.as_ref() {
Some(template_root) => template_root.children(),
None => node.children(),
};
for child in children {
serialize_node_ref_internal(&child, serializer, TraversalScope::IncludeNode)?
}

if *scope == TraversalScope::IncludeNode {
serializer.end_elem(element.name.clone())?
}
Ok(())
}

(_, &NodeData::DocumentFragment) | (_, &NodeData::Document(_)) => {
for child in node.children() {
serialize_node_ref_internal(&child, serializer, TraversalScope::IncludeNode)?
}
Ok(())
}

(TraversalScope::ChildrenOnly(_), _) => Ok(()),

(TraversalScope::IncludeNode, &NodeData::Doctype(ref doctype)) => {
serializer.write_doctype(&doctype.name).map_err(Into::into)
}
(TraversalScope::IncludeNode, &NodeData::Text(ref text)) => {
serializer.write_text(&text.borrow()).map_err(Into::into)
}
(TraversalScope::IncludeNode, &NodeData::Comment(ref text)) => {
serializer.write_comment(&text.borrow()).map_err(Into::into)
}
(TraversalScope::IncludeNode, &NodeData::ProcessingInstruction(ref contents)) => {
let contents = contents.borrow();
serializer
.write_processing_instruction(&contents.0, &contents.1)
.map_err(Into::into)
}
}
}

/// Serializes the node to HTML.
pub fn serialize_node(node: &NodeRef) -> Vec<u8> {
let mut u8_vec = Vec::new();
let mut ser = HtmlSerializer::new(
&mut u8_vec,
SerializeOpts {
traversal_scope: TraversalScope::IncludeNode,
..Default::default()
},
);
serialize_node_ref_internal(node, &mut ser, TraversalScope::IncludeNode).unwrap();
u8_vec
}

/// Parses the given HTML string.
pub fn parse(html: String) -> NodeRef {
kuchiki::parse_html().one(html)
Expand Down

0 comments on commit aec5537

Please sign in to comment.