jsonrpc_http_server/
utils.rs

1use hyper::{self, header};
2
3use crate::server_utils::{cors, hosts};
4
5/// Extracts string value of a single header in request.
6fn read_header<'a>(req: &'a hyper::Request<hyper::Body>, header_name: &str) -> Option<&'a str> {
7	req.headers().get(header_name).and_then(|v| v.to_str().ok())
8}
9
10/// Returns `true` if Host header in request matches a list of allowed hosts.
11pub fn is_host_allowed(request: &hyper::Request<hyper::Body>, allowed_hosts: &Option<Vec<hosts::Host>>) -> bool {
12	hosts::is_host_valid(read_header(request, "host"), allowed_hosts)
13}
14
15/// Returns a CORS AllowOrigin header that should be returned with that request.
16pub fn cors_allow_origin(
17	request: &hyper::Request<hyper::Body>,
18	cors_domains: &Option<Vec<cors::AccessControlAllowOrigin>>,
19) -> cors::AllowCors<header::HeaderValue> {
20	cors::get_cors_allow_origin(
21		read_header(request, "origin"),
22		read_header(request, "host"),
23		cors_domains,
24	)
25	.map(|origin| {
26		use self::cors::AccessControlAllowOrigin::*;
27		match origin {
28			Value(ref val) => {
29				header::HeaderValue::from_str(val).unwrap_or_else(|_| header::HeaderValue::from_static("null"))
30			}
31			Null => header::HeaderValue::from_static("null"),
32			Any => header::HeaderValue::from_static("*"),
33		}
34	})
35}
36
37/// Returns the CORS AllowHeaders header that should be returned with that request.
38pub fn cors_allow_headers(
39	request: &hyper::Request<hyper::Body>,
40	cors_allow_headers: &cors::AccessControlAllowHeaders,
41) -> cors::AllowCors<Vec<header::HeaderValue>> {
42	let headers = request.headers().keys().map(|name| name.as_str());
43	let requested_headers = request
44		.headers()
45		.get_all("access-control-request-headers")
46		.iter()
47		.filter_map(|val| val.to_str().ok())
48		.flat_map(|val| val.split(", "))
49		.flat_map(|val| val.split(','));
50
51	cors::get_cors_allow_headers(headers, requested_headers, cors_allow_headers, |name| {
52		header::HeaderValue::from_str(name).unwrap_or_else(|_| header::HeaderValue::from_static("unknown"))
53	})
54}
55
56/// Returns an optional value of `Connection` header that should be included in the response.
57/// The second parameter defines if server is configured with keep-alive option.
58/// Return value of `true` indicates that no `Connection` header should be returned,
59/// `false` indicates `Connection: close`.
60pub fn keep_alive(request: &hyper::Request<hyper::Body>, keep_alive: bool) -> bool {
61	read_header(request, "connection")
62		.map(|val| !matches!((keep_alive, val), (false, _) | (_, "close")))
63		// if the client header is not present, close connection if we don't keep_alive
64		.unwrap_or(keep_alive)
65}