diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/http/00_serve.js | 8 | ||||
-rw-r--r-- | ext/http/http_next.rs | 16 | ||||
-rw-r--r-- | ext/http/lib.rs | 1 | ||||
-rw-r--r-- | ext/http/response_body.rs | 17 | ||||
-rw-r--r-- | ext/http/slab.rs | 13 |
5 files changed, 53 insertions, 2 deletions
diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js index 9075ae651..7186da1fe 100644 --- a/ext/http/00_serve.js +++ b/ext/http/00_serve.js @@ -60,6 +60,7 @@ const { op_http_set_response_body_text, op_http_set_response_header, op_http_set_response_headers, + op_http_set_response_trailers, op_http_upgrade_raw, op_http_upgrade_websocket_next, op_http_wait, @@ -75,6 +76,7 @@ const { "op_http_set_response_body_text", "op_http_set_response_header", "op_http_set_response_headers", + "op_http_set_response_trailers", "op_http_upgrade_raw", "op_http_upgrade_websocket_next", "op_http_wait", @@ -125,6 +127,11 @@ function upgradeHttpRaw(req, conn) { throw new TypeError("upgradeHttpRaw may only be used with Deno.serve"); } +function addTrailers(resp, headerList) { + const inner = toInnerResponse(resp); + op_http_set_response_trailers(inner.slabId, headerList); +} + class InnerRequest { #slabId; #context; @@ -687,6 +694,7 @@ function serve(arg1, arg2) { return { finished }; } +internals.addTrailers = addTrailers; internals.upgradeHttpRaw = upgradeHttpRaw; export { serve, upgradeHttpRaw }; diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index 34281ee92..30a8c9d51 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -318,6 +318,22 @@ pub fn op_http_set_response_headers( } } +#[op] +pub fn op_http_set_response_trailers( + slab_id: SlabId, + trailers: Vec<(ByteString, ByteString)>, +) { + let mut http = slab_get(slab_id); + let mut trailer_map: HeaderMap = HeaderMap::with_capacity(trailers.len()); + for (name, value) in trailers { + // These are valid latin-1 strings + let name = HeaderName::from_bytes(&name).unwrap(); + let value = HeaderValue::from_bytes(&value).unwrap(); + trailer_map.append(name, value); + } + *http.trailers().borrow_mut() = Some(trailer_map); +} + fn is_request_compressible(headers: &HeaderMap) -> Compression { let Some(accept_encoding) = headers.get(ACCEPT_ENCODING) else { return Compression::None; diff --git a/ext/http/lib.rs b/ext/http/lib.rs index 2660f4653..7d37c53e1 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -116,6 +116,7 @@ deno_core::extension!( http_next::op_http_set_response_body_text, http_next::op_http_set_response_header, http_next::op_http_set_response_headers, + http_next::op_http_set_response_trailers, http_next::op_http_track, http_next::op_http_upgrade_websocket_next, http_next::op_http_upgrade_raw, diff --git a/ext/http/response_body.rs b/ext/http/response_body.rs index e30c917c3..ea6cc5ab8 100644 --- a/ext/http/response_body.rs +++ b/ext/http/response_body.rs @@ -158,7 +158,11 @@ impl std::fmt::Debug for ResponseBytesInner { /// required by hyper. As the API requires information about request completion (including a success/fail /// flag), we include a very lightweight [`CompletionHandle`] for interested parties to listen on. #[derive(Debug, Default)] -pub struct ResponseBytes(ResponseBytesInner, CompletionHandle); +pub struct ResponseBytes( + ResponseBytesInner, + CompletionHandle, + Rc<RefCell<Option<HeaderMap>>>, +); impl ResponseBytes { pub fn initialize(&mut self, inner: ResponseBytesInner) { @@ -170,6 +174,10 @@ impl ResponseBytes { self.1.clone() } + pub fn trailers(&self) -> Rc<RefCell<Option<HeaderMap>>> { + self.2.clone() + } + fn complete(&mut self, success: bool) -> ResponseBytesInner { if matches!(self.0, ResponseBytesInner::Done) { return ResponseBytesInner::Done; @@ -250,6 +258,9 @@ impl Body for ResponseBytes { let res = loop { let res = match &mut self.0 { ResponseBytesInner::Done | ResponseBytesInner::Empty => { + if let Some(trailers) = self.2.borrow_mut().take() { + return std::task::Poll::Ready(Some(Ok(Frame::trailers(trailers)))); + } unreachable!() } ResponseBytesInner::Bytes(..) => { @@ -271,6 +282,9 @@ impl Body for ResponseBytes { }; if matches!(res, ResponseStreamResult::EndOfStream) { + if let Some(trailers) = self.2.borrow_mut().take() { + return std::task::Poll::Ready(Some(Ok(Frame::trailers(trailers)))); + } self.complete(true); } std::task::Poll::Ready(res.into()) @@ -278,6 +292,7 @@ impl Body for ResponseBytes { fn is_end_stream(&self) -> bool { matches!(self.0, ResponseBytesInner::Done | ResponseBytesInner::Empty) + && self.2.borrow_mut().is_none() } fn size_hint(&self) -> SizeHint { diff --git a/ext/http/slab.rs b/ext/http/slab.rs index 24554d689..93a56e9ff 100644 --- a/ext/http/slab.rs +++ b/ext/http/slab.rs @@ -4,6 +4,7 @@ use crate::response_body::CompletionHandle; use crate::response_body::ResponseBytes; use deno_core::error::AnyError; use http::request::Parts; +use http::HeaderMap; use hyper1::body::Incoming; use hyper1::upgrade::OnUpgrade; @@ -11,6 +12,7 @@ use slab::Slab; use std::cell::RefCell; use std::cell::RefMut; use std::ptr::NonNull; +use std::rc::Rc; pub type Request = hyper1::Request<Incoming>; pub type Response = hyper1::Response<ResponseBytes>; @@ -23,6 +25,7 @@ pub struct HttpSlabRecord { // The response may get taken before we tear this down response: Option<Response>, promise: CompletionHandle, + trailers: Rc<RefCell<Option<HeaderMap>>>, been_dropped: bool, #[cfg(feature = "__zombie_http_tracking")] alive: bool, @@ -81,11 +84,14 @@ fn slab_insert_raw( ) -> SlabId { let index = SLAB.with(|slab| { let mut slab = slab.borrow_mut(); + let body = ResponseBytes::default(); + let trailers = body.trailers(); slab.insert(HttpSlabRecord { request_info, request_parts, request_body, - response: Some(Response::new(ResponseBytes::default())), + response: Some(Response::new(body)), + trailers, been_dropped: false, promise: CompletionHandle::default(), #[cfg(feature = "__zombie_http_tracking")] @@ -182,6 +188,11 @@ impl SlabEntry { self.self_mut().response.as_mut().unwrap() } + /// Get a mutable reference to the trailers. + pub fn trailers(&mut self) -> &RefCell<Option<HeaderMap>> { + &self.self_mut().trailers + } + /// Take the response. pub fn take_response(&mut self) -> Response { self.self_mut().response.take().unwrap() |