1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Contains common builders for hyper responses.

use crate::types::error::{ErrorCode, ErrorResponse};
use crate::types::Id;

const JSON: &str = "application/json; charset=utf-8";
const TEXT: &str = "text/plain";

/// Create a response for json internal error.
pub fn internal_error() -> hyper::Response<hyper::Body> {
	let error = serde_json::to_string(&ErrorResponse::new(ErrorCode::InternalError.into(), Id::Null))
		.expect("built from known-good data; qed");

	from_template(hyper::StatusCode::INTERNAL_SERVER_ERROR, error, JSON)
}

/// Create a text/plain response for not allowed hosts.
pub fn host_not_allowed() -> hyper::Response<hyper::Body> {
	from_template(hyper::StatusCode::FORBIDDEN, "Provided Host header is not whitelisted.\n".to_owned(), TEXT)
}

/// Create a text/plain response for disallowed method used.
pub fn method_not_allowed() -> hyper::Response<hyper::Body> {
	from_template(
		hyper::StatusCode::METHOD_NOT_ALLOWED,
		"Used HTTP Method is not allowed. POST or OPTIONS is required\n".to_owned(),
		TEXT,
	)
}

/// Create a text/plain response for invalid CORS "Origin" headers.
pub fn invalid_allow_origin() -> hyper::Response<hyper::Body> {
	from_template(
        hyper::StatusCode::FORBIDDEN,
        "Origin of the request is not whitelisted. CORS headers would not be sent and any side-effects were cancelled as well.\n".to_owned(),
		TEXT,
    )
}

/// Create a text/plain response for invalid CORS "Allow-*" headers.
pub fn invalid_allow_headers() -> hyper::Response<hyper::Body> {
	from_template(
        hyper::StatusCode::FORBIDDEN,
        "Requested headers are not allowed for CORS. CORS headers would not be sent and any side-effects were cancelled as well.\n".to_owned(),
		TEXT,
    )
}

/// Create a json response for oversized requests (413)
pub fn too_large() -> hyper::Response<hyper::Body> {
	let error = serde_json::to_string(&ErrorResponse::new(ErrorCode::OversizedRequest.into(), Id::Null))
		.expect("built from known-good data; qed");

	from_template(hyper::StatusCode::PAYLOAD_TOO_LARGE, error, JSON)
}

/// Create a json response for empty or malformed requests (400)
pub fn malformed() -> hyper::Response<hyper::Body> {
	let error = serde_json::to_string(&ErrorResponse::new(ErrorCode::ParseError.into(), Id::Null))
		.expect("built from known-good data; qed");

	from_template(hyper::StatusCode::BAD_REQUEST, error, JSON)
}

/// Create a response body.
fn from_template<S: Into<hyper::Body>>(
	status: hyper::StatusCode,
	body: S,
	content_type: &'static str,
) -> hyper::Response<hyper::Body> {
	hyper::Response::builder()
		.status(status)
		.header("content-type", hyper::header::HeaderValue::from_static(content_type))
		.body(body.into())
		// Parsing `StatusCode` and `HeaderValue` is infalliable but
		// parsing body content is not.
		.expect("Unable to parse response body for type conversion")
}

/// Create a valid JSON response.
pub fn ok_response(body: String) -> hyper::Response<hyper::Body> {
	from_template(hyper::StatusCode::OK, body, JSON)
}

/// Create a response for unsupported content type.
pub fn unsupported_content_type() -> hyper::Response<hyper::Body> {
	from_template(
		hyper::StatusCode::UNSUPPORTED_MEDIA_TYPE,
		"Supplied content type is not allowed. Content-Type: application/json is required\n".to_owned(),
		TEXT,
	)
}