Skip to content

Commit

Permalink
feat(devserver/http): naively check content type for compression
Browse files Browse the repository at this point in the history
  • Loading branch information
kwonoj committed Mar 2, 2023
1 parent 9cbcd8d commit a88aefb
Showing 1 changed file with 46 additions and 14 deletions.
60 changes: 46 additions & 14 deletions crates/turbopack-dev-server/src/http.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use std::io::{Error, ErrorKind};

use anyhow::Result;
use futures::{StreamExt, TryStreamExt};
use hyper::{
header::{HeaderName, CONTENT_ENCODING},
header::{HeaderName, CONTENT_ENCODING, CONTENT_LENGTH},
http::HeaderValue,
Request, Response,
};
use mime::Mime;
use mime_guess::mime;
use tokio_util::io::{ReaderStream, StreamReader};
use turbo_tasks::TransientInstance;
use turbo_tasks_fs::{FileContent, FileContentReadRef};
use turbopack_core::{asset::AssetContent, issue::IssueReporterVc, version::VersionedContent};
Expand Down Expand Up @@ -96,14 +100,32 @@ pub async fn process_request_with_content_source(
);
}

// naively checking if content is `compressible`.
let mut should_compress = false;
let should_compress_predicate =
|mime: &Mime| match (mime.type_(), mime.subtype(), mime.suffix()) {
(_, mime::PLAIN, _)
| (_, mime::JSON, _)
| (mime::TEXT, _, _)
| (mime::APPLICATION, mime::XML, _)
| (mime::APPLICATION, mime::JAVASCRIPT, _)
| (_, _, Some(mime::XML))
| (_, _, Some(mime::JSON))
| (_, _, Some(mime::TEXT)) => true,
_ => false,
};

if let Some(content_type) = file.content_type() {
header_map.append(
"content-type",
hyper::header::HeaderValue::try_from(content_type.to_string())?,
);

should_compress = should_compress_predicate(content_type);
} else if let hyper::header::Entry::Vacant(entry) = header_map.entry("content-type")
{
let guess = mime_guess::from_path(&original_path).first_or_octet_stream();
should_compress = should_compress_predicate(&guess);
// If a text type, application/javascript, or application/json was
// guessed, use a utf-8 charset as we most likely generated it as
// such.
Expand All @@ -121,21 +143,31 @@ pub async fn process_request_with_content_source(
}

let content = file.content();
// Grab ropereader stream, coerce anyhow::Error to std::io::Error
let stream_ext = content
.read()
.into_stream()
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err));

let gzipped_stream = tokio_util::io::ReaderStream::new(
async_compression::tokio::bufread::GzipEncoder::new(
tokio_util::io::StreamReader::new(stream_ext),
),
);
let response = if should_compress {
header_map.insert(CONTENT_ENCODING, HeaderValue::from_static("gzip"));

// Grab ropereader stream, coerce anyhow::Error to std::io::Error
let stream_ext = content
.read()
.into_stream()
.map_err(|err| Error::new(ErrorKind::Other, err));

let gzipped_stream =
ReaderStream::new(async_compression::tokio::bufread::GzipEncoder::new(
StreamReader::new(stream_ext),
));

response.body(hyper::Body::wrap_stream(gzipped_stream))?
} else {
header_map.insert(
CONTENT_LENGTH,
hyper::header::HeaderValue::try_from(content.len().to_string())?,
);

header_map.insert(CONTENT_ENCODING, HeaderValue::from_static("gzip"));
response.body(hyper::Body::wrap_stream(content.read()))?
};

return Ok(response.body(hyper::Body::wrap_stream(gzipped_stream))?);
return Ok(response);
}
}
GetFromSourceResult::HttpProxy(proxy_result) => {
Expand Down

0 comments on commit a88aefb

Please sign in to comment.