|
39 | 39 |
|
40 | 40 | use crate::http_util::compute_encrypted_sha256_token; |
41 | 41 | use crate::settings::Settings; |
| 42 | +use crate::streaming_processor::StreamProcessor; |
42 | 43 | use crate::tsjs; |
43 | 44 | use lol_html::{element, html_content::ContentType, text, HtmlRewriter, Settings as HtmlSettings}; |
| 45 | +use std::io; |
44 | 46 |
|
45 | 47 | // Helper: normalize to absolute URL if http/https or protocol-relative. Otherwise None. |
46 | 48 | // Checks against the rewrite blacklist to exclude configured domains/patterns from proxying. |
@@ -478,6 +480,84 @@ pub fn rewrite_creative_html(markup: &str, settings: &Settings) -> String { |
478 | 480 | String::from_utf8(out).unwrap_or_else(|_| markup.to_string()) |
479 | 481 | } |
480 | 482 |
|
| 483 | +/// Stream processor for creative HTML that rewrites URLs to first-party proxy. |
| 484 | +/// |
| 485 | +/// This processor buffers input chunks and processes the complete HTML document |
| 486 | +/// when the stream ends, using `rewrite_creative_html` internally. |
| 487 | +pub struct CreativeHtmlProcessor { |
| 488 | + settings: Settings, |
| 489 | + buffer: Vec<u8>, |
| 490 | +} |
| 491 | + |
| 492 | +impl CreativeHtmlProcessor { |
| 493 | + /// Create a new HTML processor with the given settings. |
| 494 | + pub fn new(settings: &Settings) -> Self { |
| 495 | + Self { |
| 496 | + settings: settings.clone(), |
| 497 | + buffer: Vec::new(), |
| 498 | + } |
| 499 | + } |
| 500 | +} |
| 501 | + |
| 502 | +impl StreamProcessor for CreativeHtmlProcessor { |
| 503 | + fn process_chunk(&mut self, chunk: &[u8], is_last: bool) -> Result<Vec<u8>, io::Error> { |
| 504 | + self.buffer.extend_from_slice(chunk); |
| 505 | + |
| 506 | + if is_last { |
| 507 | + let markup = String::from_utf8(std::mem::take(&mut self.buffer)) |
| 508 | + .map_err(|e| io::Error::other(format!("Invalid UTF-8 in HTML: {}", e)))?; |
| 509 | + |
| 510 | + let rewritten = rewrite_creative_html(&markup, &self.settings); |
| 511 | + Ok(rewritten.into_bytes()) |
| 512 | + } else { |
| 513 | + Ok(Vec::new()) |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + fn reset(&mut self) { |
| 518 | + self.buffer.clear(); |
| 519 | + } |
| 520 | +} |
| 521 | + |
| 522 | +/// Stream processor for CSS that rewrites url() references to first-party proxy. |
| 523 | +/// |
| 524 | +/// This processor buffers input chunks and processes the complete CSS |
| 525 | +/// when the stream ends, using `rewrite_css_body` internally. |
| 526 | +pub struct CreativeCssProcessor { |
| 527 | + settings: Settings, |
| 528 | + buffer: Vec<u8>, |
| 529 | +} |
| 530 | + |
| 531 | +impl CreativeCssProcessor { |
| 532 | + /// Create a new CSS processor with the given settings. |
| 533 | + pub fn new(settings: &Settings) -> Self { |
| 534 | + Self { |
| 535 | + settings: settings.clone(), |
| 536 | + buffer: Vec::new(), |
| 537 | + } |
| 538 | + } |
| 539 | +} |
| 540 | + |
| 541 | +impl StreamProcessor for CreativeCssProcessor { |
| 542 | + fn process_chunk(&mut self, chunk: &[u8], is_last: bool) -> Result<Vec<u8>, io::Error> { |
| 543 | + self.buffer.extend_from_slice(chunk); |
| 544 | + |
| 545 | + if is_last { |
| 546 | + let css = String::from_utf8(std::mem::take(&mut self.buffer)) |
| 547 | + .map_err(|e| io::Error::other(format!("Invalid UTF-8 in CSS: {}", e)))?; |
| 548 | + |
| 549 | + let rewritten = rewrite_css_body(&css, &self.settings); |
| 550 | + Ok(rewritten.into_bytes()) |
| 551 | + } else { |
| 552 | + Ok(Vec::new()) |
| 553 | + } |
| 554 | + } |
| 555 | + |
| 556 | + fn reset(&mut self) { |
| 557 | + self.buffer.clear(); |
| 558 | + } |
| 559 | +} |
| 560 | + |
481 | 561 | #[cfg(test)] |
482 | 562 | mod tests { |
483 | 563 | use super::{rewrite_creative_html, rewrite_srcset, rewrite_style_urls, to_abs}; |
|
0 commit comments