1use bytes::Bytes;
2use futures_core::Stream;
3use futures_util::{future::Ready, stream::Iter};
4use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
5use http::{HeaderMap, StatusCode};
6use servio_http::http::{HttpEvent, ResponseChunk, ResponseStart, EVENT_HTTP};
7use servio_service::{Event, Scope, Service};
8use std::borrow::Cow;
9use std::convert::Infallible;
10use std::vec::IntoIter;
11
12#[derive(Default, Clone)]
13pub struct StaticResponse {
14 events: Vec<Event>,
15}
16
17impl StaticResponse {
18 pub fn new(
19 status_code: StatusCode,
20 content: Bytes,
21 media_type: Cow<'static, str>,
22 headers: HeaderMap,
23 ) -> Self {
24 let mut resp = ResponseChunk::default();
25 resp.body = content;
26
27 let mut response_start = ResponseStart::default();
28 response_start.status = status_code;
29 response_start.headers = headers;
30
31 let headers = &mut response_start.headers;
32 headers.insert(CONTENT_LENGTH, resp.body.len().into());
33 headers.insert(CONTENT_TYPE, media_type.as_ref().parse().unwrap());
34
35 Self {
36 events: vec![
37 Event::new(EVENT_HTTP.into(), HttpEvent::ResponseStart(response_start)),
38 Event::new(EVENT_HTTP.into(), HttpEvent::ResponseChunk(resp)),
39 ],
40 }
41 }
42}
43
44impl<ServerStream> Service<ServerStream> for StaticResponse
45where
46 ServerStream: Stream<Item = Event>,
47{
48 type AppStream = Iter<IntoIter<Event>>;
49 type Error = Infallible;
50 type Future = Ready<Result<Self::AppStream, Self::Error>>;
51
52 fn call(&mut self, _scope: Scope, _server_events: ServerStream) -> Self::Future {
53 let stream = futures_util::stream::iter(self.events.clone());
54 futures_util::future::ok(stream)
55 }
56}
57
58macro_rules! simple_pass {
59 ($srv:ident) => {
60 #[derive(Default, Clone)]
61 pub struct $srv {
62 inner: StaticResponse,
63 }
64
65 impl<ServerStream> Service<ServerStream> for $srv
66 where
67 ServerStream: Stream<Item = Event>,
68 {
69 type AppStream = <StaticResponse as Service<ServerStream>>::AppStream;
70 type Error = <StaticResponse as Service<ServerStream>>::Error;
71 type Future = <StaticResponse as Service<ServerStream>>::Future;
72
73 fn call(&mut self, scope: Scope, server_events: ServerStream) -> Self::Future {
74 self.inner.call(scope, server_events)
75 }
76 }
77 };
78}
79
80simple_pass!(HtmlResponse);
81impl HtmlResponse {
82 pub fn new(status_code: StatusCode, content: Bytes, headers: HeaderMap) -> Self {
83 Self {
84 inner: StaticResponse::new(status_code, content, "text/html".into(), headers),
85 }
86 }
87}
88
89simple_pass!(PlainTextResponse);
90impl PlainTextResponse {
91 pub fn new(status_code: StatusCode, content: Cow<'static, str>, headers: HeaderMap) -> Self {
92 Self {
93 inner: StaticResponse::new(
94 status_code,
95 content.to_string().into(),
96 "text/plain".into(),
97 headers,
98 ),
99 }
100 }
101}
102
103#[cfg(feature = "serde")]
104simple_pass!(JsonResponse);
105#[cfg(feature = "serde")]
106impl JsonResponse {
107 pub fn new<S: serde::Serialize>(
108 status_code: StatusCode,
109 content: &S,
110 headers: HeaderMap,
111 ) -> Self {
112 Self {
113 inner: StaticResponse::new(
114 status_code,
115 serde_json::to_vec(content).unwrap().into(),
116 "application/json".into(),
117 headers,
118 ),
119 }
120 }
121}