jsonrpc_http_server/
response.rs

1//! Basic Request/Response structures used internally.
2
3pub use hyper::{self, header::HeaderValue, Body, Method, StatusCode};
4
5/// Simple server response structure
6#[derive(Debug)]
7pub struct Response {
8	/// Response code
9	pub code: StatusCode,
10	/// Response content type
11	pub content_type: HeaderValue,
12	/// Response body
13	pub content: String,
14}
15
16impl Response {
17	/// Create a response with empty body and 200 OK status code.
18	pub fn empty() -> Self {
19		Self::ok(String::new())
20	}
21
22	/// Create a response with given body and 200 OK status code.
23	pub fn ok<T: Into<String>>(response: T) -> Self {
24		Response {
25			code: StatusCode::OK,
26			content_type: HeaderValue::from_static("application/json; charset=utf-8"),
27			content: response.into(),
28		}
29	}
30
31	/// Create a response for plaintext internal error.
32	pub fn internal_error<T: Into<String>>(msg: T) -> Self {
33		Response {
34			code: StatusCode::INTERNAL_SERVER_ERROR,
35			content_type: plain_text(),
36			content: format!("Internal Server Error: {}", msg.into()),
37		}
38	}
39
40	/// Create a json response for service unavailable.
41	pub fn service_unavailable<T: Into<String>>(msg: T) -> Self {
42		Response {
43			code: StatusCode::SERVICE_UNAVAILABLE,
44			content_type: HeaderValue::from_static("application/json; charset=utf-8"),
45			content: msg.into(),
46		}
47	}
48
49	/// Create a response for not allowed hosts.
50	pub fn host_not_allowed() -> Self {
51		Response {
52			code: StatusCode::FORBIDDEN,
53			content_type: plain_text(),
54			content: "Provided Host header is not whitelisted.\n".to_owned(),
55		}
56	}
57
58	/// Create a response for unsupported content type.
59	pub fn unsupported_content_type() -> Self {
60		Response {
61			code: StatusCode::UNSUPPORTED_MEDIA_TYPE,
62			content_type: plain_text(),
63			content: "Supplied content type is not allowed. Content-Type: application/json is required\n".to_owned(),
64		}
65	}
66
67	/// Create a response for disallowed method used.
68	pub fn method_not_allowed() -> Self {
69		Response {
70			code: StatusCode::METHOD_NOT_ALLOWED,
71			content_type: plain_text(),
72			content: "Used HTTP Method is not allowed. POST or OPTIONS is required\n".to_owned(),
73		}
74	}
75
76	/// CORS invalid
77	pub fn invalid_allow_origin() -> Self {
78		Response {
79			code: StatusCode::FORBIDDEN,
80			content_type: plain_text(),
81			content: "Origin of the request is not whitelisted. CORS headers would not be sent and any side-effects were cancelled as well.\n".to_owned(),
82		}
83	}
84
85	/// CORS header invalid
86	pub fn invalid_allow_headers() -> Self {
87		Response {
88			code: StatusCode::FORBIDDEN,
89			content_type: plain_text(),
90			content: "Requested headers are not allowed for CORS. CORS headers would not be sent and any side-effects were cancelled as well.\n".to_owned(),
91		}
92	}
93
94	/// Create a response for bad request
95	pub fn bad_request<S: Into<String>>(msg: S) -> Self {
96		Response {
97			code: StatusCode::BAD_REQUEST,
98			content_type: plain_text(),
99			content: msg.into(),
100		}
101	}
102
103	/// Create a response for too large (413)
104	pub fn too_large<S: Into<String>>(msg: S) -> Self {
105		Response {
106			code: StatusCode::PAYLOAD_TOO_LARGE,
107			content_type: plain_text(),
108			content: msg.into(),
109		}
110	}
111
112	/// Create a 500 response when server is closing.
113	pub(crate) fn closing() -> Self {
114		Response {
115			code: StatusCode::SERVICE_UNAVAILABLE,
116			content_type: plain_text(),
117			content: "Server is closing.".into(),
118		}
119	}
120}
121
122fn plain_text() -> HeaderValue {
123	HeaderValue::from_static("text/plain; charset=utf-8")
124}
125
126// TODO: Consider switching to a `TryFrom` conversion once it stabilizes.
127impl From<Response> for hyper::Response<Body> {
128	/// Converts from a jsonrpc `Response` to a `hyper::Response`
129	///
130	/// ## Panics
131	///
132	/// Panics if the response cannot be converted due to failure to parse
133	/// body content.
134	///
135	fn from(res: Response) -> hyper::Response<Body> {
136		hyper::Response::builder()
137			.status(res.code)
138			.header("content-type", res.content_type)
139			.body(res.content.into())
140			// Parsing `StatusCode` and `HeaderValue` is infalliable but
141			// parsing body content is not.
142			.expect("Unable to parse response body for type conversion")
143	}
144}