|
1 | 1 | use error_stack::{Report, ResultExt}; |
2 | 2 | use fastly::http::{header, StatusCode}; |
3 | 3 | use fastly::{Body, Request, Response}; |
4 | | -use std::io::Write; |
5 | 4 |
|
6 | 5 | use crate::backend::ensure_backend_from_url; |
7 | 6 | use crate::http_util::serve_static_with_etag; |
8 | 7 |
|
9 | 8 | use crate::constants::{HEADER_SYNTHETIC_TRUSTED_SERVER, HEADER_X_COMPRESS_HINT}; |
10 | 9 | use crate::cookies::create_synthetic_cookie; |
11 | 10 | use crate::error::TrustedServerError; |
12 | | -use crate::integrations::{IntegrationHtmlContext, IntegrationRegistry}; |
| 11 | +use crate::integrations::IntegrationRegistry; |
13 | 12 | use crate::rsc_flight::RscFlightUrlRewriter; |
14 | 13 | use crate::settings::Settings; |
15 | 14 | use crate::streaming_processor::{Compression, PipelineConfig, StreamProcessor, StreamingPipeline}; |
16 | 15 | use crate::streaming_replacer::create_url_replacer; |
17 | 16 | use crate::synthetic::get_or_generate_synthetic_id; |
18 | 17 |
|
19 | | -/// Compress data using the specified compression algorithm |
20 | | -fn compress_data( |
21 | | - data: &[u8], |
22 | | - compression: Compression, |
23 | | -) -> Result<Vec<u8>, Report<TrustedServerError>> { |
24 | | - match compression { |
25 | | - Compression::None => Ok(data.to_vec()), |
26 | | - Compression::Gzip => { |
27 | | - use flate2::write::GzEncoder; |
28 | | - use flate2::Compression as GzCompression; |
29 | | - let mut encoder = GzEncoder::new(Vec::new(), GzCompression::default()); |
30 | | - encoder |
31 | | - .write_all(data) |
32 | | - .change_context(TrustedServerError::Proxy { |
33 | | - message: "Failed to gzip compress data".to_string(), |
34 | | - })?; |
35 | | - encoder.finish().change_context(TrustedServerError::Proxy { |
36 | | - message: "Failed to finish gzip compression".to_string(), |
37 | | - }) |
38 | | - } |
39 | | - Compression::Deflate => { |
40 | | - use flate2::write::ZlibEncoder; |
41 | | - use flate2::Compression as ZlibCompression; |
42 | | - let mut encoder = ZlibEncoder::new(Vec::new(), ZlibCompression::default()); |
43 | | - encoder |
44 | | - .write_all(data) |
45 | | - .change_context(TrustedServerError::Proxy { |
46 | | - message: "Failed to deflate compress data".to_string(), |
47 | | - })?; |
48 | | - encoder.finish().change_context(TrustedServerError::Proxy { |
49 | | - message: "Failed to finish deflate compression".to_string(), |
50 | | - }) |
51 | | - } |
52 | | - Compression::Brotli => { |
53 | | - use brotli::enc::writer::CompressorWriter; |
54 | | - use brotli::enc::BrotliEncoderParams; |
55 | | - let params = BrotliEncoderParams { |
56 | | - quality: 4, // Balance speed and compression |
57 | | - ..Default::default() |
58 | | - }; |
59 | | - let mut output = Vec::new(); |
60 | | - { |
61 | | - let mut writer = CompressorWriter::with_params(&mut output, 4096, ¶ms); |
62 | | - writer |
63 | | - .write_all(data) |
64 | | - .change_context(TrustedServerError::Proxy { |
65 | | - message: "Failed to brotli compress data".to_string(), |
66 | | - })?; |
67 | | - } |
68 | | - Ok(output) |
69 | | - } |
70 | | - } |
71 | | -} |
72 | | - |
73 | 18 | /// Detects the request scheme (HTTP or HTTPS) using Fastly SDK methods and headers. |
74 | 19 | /// |
75 | 20 | /// Tries multiple methods in order of reliability: |
@@ -199,67 +144,14 @@ fn process_response_streaming( |
199 | 144 | params.integration_registry, |
200 | 145 | )?; |
201 | 146 |
|
202 | | - // Check if we have post-processors that need uncompressed HTML |
203 | | - let post_processors = params.integration_registry.html_post_processors(); |
204 | | - let needs_post_processing = !post_processors.is_empty(); |
205 | | - |
206 | | - // If we have post-processors, output uncompressed HTML so they can work with it, |
207 | | - // then compress only once at the end. This avoids double decompression/compression. |
208 | | - let output_compression = if needs_post_processing { |
209 | | - Compression::None |
210 | | - } else { |
211 | | - compression |
212 | | - }; |
213 | | - |
214 | 147 | let config = PipelineConfig { |
215 | 148 | input_compression: compression, |
216 | | - output_compression, |
| 149 | + output_compression: compression, |
217 | 150 | chunk_size: 8192, |
218 | 151 | }; |
219 | 152 |
|
220 | 153 | let mut pipeline = StreamingPipeline::new(config, processor); |
221 | 154 | pipeline.process(body, &mut output)?; |
222 | | - |
223 | | - // Post-process HTML through registered integration post-processors. |
224 | | - // This handles cross-script T-chunks for RSC and other integration-specific |
225 | | - // processing that requires the complete HTML document. |
226 | | - log::info!( |
227 | | - "HTML post-processors: count={}, output_len={}, needs_post_processing={}", |
228 | | - post_processors.len(), |
229 | | - output.len(), |
230 | | - needs_post_processing |
231 | | - ); |
232 | | - if needs_post_processing { |
233 | | - // Output is already uncompressed, convert to string for post-processing |
234 | | - if let Ok(html) = std::str::from_utf8(&output) { |
235 | | - log::info!( |
236 | | - "NextJs post-processor called with {} bytes of HTML", |
237 | | - html.len() |
238 | | - ); |
239 | | - let ctx = IntegrationHtmlContext { |
240 | | - request_host: params.request_host, |
241 | | - request_scheme: params.request_scheme, |
242 | | - origin_host: params.origin_host, |
243 | | - }; |
244 | | - let mut processed = html.to_string(); |
245 | | - for processor in post_processors { |
246 | | - processed = processor.post_process(&processed, &ctx); |
247 | | - } |
248 | | - |
249 | | - // Now compress if original content was compressed |
250 | | - if compression != Compression::None { |
251 | | - output = compress_data(processed.as_bytes(), compression)?; |
252 | | - } else { |
253 | | - output = processed.into_bytes(); |
254 | | - } |
255 | | - } else { |
256 | | - log::warn!("HTML post-processing skipped: content is not valid UTF-8"); |
257 | | - // If not valid UTF-8, recompress the output as-is |
258 | | - if compression != Compression::None { |
259 | | - output = compress_data(&output, compression)?; |
260 | | - } |
261 | | - } |
262 | | - } |
263 | 155 | } else if is_rsc_flight { |
264 | 156 | // RSC Flight responses are length-prefixed (T rows). A naive string replacement will |
265 | 157 | // corrupt the stream by changing byte lengths without updating the prefixes. |
|
0 commit comments