Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions scripts/build/deps/lolhtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
import type { Dependency } from "../source.ts";

// oven-sh/lol-html is cloudflare/lol-html plus content-handler suspension
// (`HtmlRewriter::resume()`), maintained on the `bun` branch. The upstream
// (`HtmlRewriter::resume()`), `:not()` matching that follows De Morgan's laws
// (oven-sh/lol-html#9) and open-name counts that exist only on a deep stack
// (oven-sh/lol-html#11), maintained on the `bun` branch. The upstream
// base commit is recorded here so a rebase onto a new upstream tag is
// `git rebase --onto <new-tag> <LOLHTML_UPSTREAM_BASE> bun` in the fork.
const LOLHTML_UPSTREAM_BASE = "77127cd2b8545998756e8d64e36ee2313c4bb312"; // v2.7.2
const LOLHTML_COMMIT = "725ce499aa9b71e38b7a2d0a9fbb6d7294a4079e";
const LOLHTML_UPSTREAM_BASE = "608cc4a66b7ab4fcbe1bbdeb25df8f265572b11c"; // v3.0.1
const LOLHTML_COMMIT = "0e6a4b19c483b9897a57986973b4424788dc5a2a";
void LOLHTML_UPSTREAM_BASE;

export const lolhtml: Dependency = {
Expand Down
29 changes: 12 additions & 17 deletions src/bundler/HTMLScanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,12 @@
// TagHandler::new("iframe[src]", "src", ImportKind::Url),
];

const SELECTOR_CAP: usize = TAG_HANDLERS.len() + 3;

#[inline]
fn lol_err<E>(_: E) -> Error {
crate::Error::Fail
}

/// `element_content_handlers` entry with only the element slot populated —
/// `append_element_content_handler` entry with only the element slot populated —
/// the only shape this processor registers (leaving the comment/text slots
/// empty lets lol-html skip lexing that content).
fn element_entry<'h>(
Expand All @@ -304,13 +302,20 @@
impl<T: HTMLProcessorHandler, const VISIT_DOCUMENT_TAGS: bool>
HTMLProcessor<T, VISIT_DOCUMENT_TAGS>
{
pub(crate) fn run(this: &mut T, input: &[u8]) -> Result<(), Error> {

Check warning on line 305 in src/bundler/HTMLScanner.rs

View workflow job for this annotation

GitHub Actions / mordant

`HTMLScanner::HTMLProcessor::<T, VISIT_DOCUMENT_TAGS>::run` is generic over `T` and `VISIT_DOCUMENT_TAGS` and is compiled 2 times in this crate, but one part of it, 28 of its 160 statements (as MIR), does not use `T` or `VISIT_DOCUMENT_TAGS`
// Every handler closure and the output sink capture this raw pointer
// so one `&mut T` can service them all; `this` is not reborrowed
// until the rewriter holding those closures is gone.
let this_ptr: *mut T = this;

let mut element_content_handlers = Vec::with_capacity(SELECTOR_CAP);
let mut settings = lol_html::Settings::new()
.with_encoding(lol_html::AsciiCompatibleEncoding::utf_8())
.with_memory_settings(
lol_html::MemorySettings::new()
.with_preallocated_parsing_buffer_size((input.len() / 4).max(1024))
.with_max_allowed_memory_usage(1024 * 1024 * 10),
Comment thread
robobun marked this conversation as resolved.
)
.with_strict(false);

for tag_info in TAG_HANDLERS {
let on_element: lol_html::ElementHandler<'_> = Box::new(
Expand Down Expand Up @@ -339,7 +344,8 @@
Ok(())
},
);
element_content_handlers.push(element_entry(tag_info.selector, on_element)?);
settings = settings
.append_element_content_handler(element_entry(tag_info.selector, on_element)?);
}

if VISIT_DOCUMENT_TAGS {
Expand All @@ -363,21 +369,10 @@
}
},
);
element_content_handlers.push(element_entry(tag, on_element)?);
settings = settings.append_element_content_handler(element_entry(tag, on_element)?);
}
}

let settings = lol_html::Settings {
element_content_handlers,
encoding: lol_html::AsciiCompatibleEncoding::utf_8(),
memory_settings: lol_html::MemorySettings {
preallocated_parsing_buffer_size: (input.len() / 4).max(1024),
max_allowed_memory_usage: 1024 * 1024 * 10,
},
strict: false,
..lol_html::Settings::new()
};

// lol-html signals end-of-document with one zero-length chunk; the
// C-API sink routed that to a no-op `done()`, never to `on_write_html`.
let output_sink = OutputSink::Callback(Box::new(move |chunk: &[u8]| {
Expand Down
49 changes: 18 additions & 31 deletions src/runtime/api/html_rewriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,11 @@ fn handler_result(outcome: HandlerOutcome) -> lol_html::HandlerResult {
}
}

/// Build the [`lol_html::Settings`] handler vectors from `ctx`. The lifetime
/// Build the [`lol_html::Settings`] that carry `ctx`'s handlers. The lifetime
/// erasures below are sound because the consuming sink's `Rc` keeps `ctx` alive
/// and `handler_callback` detaches each JS wrapper before its handler returns.
fn build_settings(
ctx: &mut LOLHTMLContext,
) -> (
Vec<(
std::borrow::Cow<'static, lol_html::Selector>,
lol_html::ElementContentHandlers<'static>,
)>,
Vec<lol_html::DocumentContentHandlers<'static>>,
) {
let mut element_content_handlers = Vec::with_capacity(ctx.element_handlers.len());
fn build_settings(ctx: &mut LOLHTMLContext) -> lol_html::Settings<'static, 'static> {
let mut settings = lol_html::Settings::new();
for ElementHandlerEntry { selector, handler } in &mut ctx.element_handlers {
let has_element = handler.on_element_callback.is_some();
let has_comment = handler.on_comment_callback.is_some();
Expand Down Expand Up @@ -338,10 +330,10 @@ fn build_settings(
handler_result(ElementHandler::on_text(h, raw))
});
}
element_content_handlers.push((std::borrow::Cow::Owned(selector.clone()), handlers));
settings = settings
.append_element_content_handler((std::borrow::Cow::Owned(selector.clone()), handlers));
}

let mut document_content_handlers = Vec::with_capacity(ctx.document_handlers.len());
for handler in &mut ctx.document_handlers {
let has_doc_type = handler.on_doc_type_callback.is_some();
let has_comment = handler.on_comment_callback.is_some();
Expand Down Expand Up @@ -380,10 +372,10 @@ fn build_settings(
handler_result(DocumentHandler::on_end(h, raw))
});
}
document_content_handlers.push(handlers);
settings = settings.append_document_content_handler(handlers);
}

(element_content_handlers, document_content_handlers)
settings
}

// ───────────────────────────── HTMLRewriter ──────────────────────────────
Expand Down Expand Up @@ -1083,23 +1075,18 @@ impl RewriterPipe {

// The handler closures point into `Box`es owned by `(*pipe).context`,
// which `pipe` keeps alive for the rewriter's whole lifetime.
let (element_content_handlers, document_content_handlers) =
build_settings(&mut this.context.borrow_mut());
let settings = build_settings(&mut this.context.borrow_mut())
.with_encoding(lol_html::AsciiCompatibleEncoding::utf_8())
// Default parsing-buffer preallocation: it only ever holds the
// unparsed tail of one write (a token split across chunks).
Comment thread
robobun marked this conversation as resolved.
.with_memory_settings(
lol_html::MemorySettings::new().with_max_allowed_memory_usage(u32::MAX as usize),
)
.with_strict(false)
.with_enable_esi_tags(false)
.with_adjust_charset_on_meta_tag(false);
this.rewriter.set(Some(Box::new(lol_html::HtmlRewriter::new(
lol_html::Settings {
element_content_handlers,
document_content_handlers,
encoding: lol_html::AsciiCompatibleEncoding::utf_8(),
// Default parsing-buffer preallocation: it only ever holds the
// unparsed tail of one write (a token split across chunks).
memory_settings: lol_html::MemorySettings {
max_allowed_memory_usage: u32::MAX as usize,
..lol_html::MemorySettings::new()
},
strict: false,
enable_esi_tags: false,
adjust_charset_on_meta_tag: false,
},
settings,
// The pipe owns the `Box<LolRewriter>` that owns this sink, so the
// back-reference to `output_buffer` cannot outlive its pointee.
bun_bundler::HTMLScanner::OutputSink::Buffer(bun_ptr::BackRef::new(
Expand Down
Loading
Loading