2018-03-05 22:33:44 +03:00
|
|
|
// Copyright 2018 The Grin Developers
|
2017-03-08 04:00:34 +03:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
//! RESTful API server to easily expose services as RESTful JSON/HTTP endpoints.
|
|
|
|
//! Fairly constrained on what the service API must look like by design.
|
|
|
|
//!
|
|
|
|
//! To use it, just have your service(s) implement the ApiEndpoint trait and
|
|
|
|
//! register them on a ApiServer.
|
|
|
|
|
2018-12-08 02:59:40 +03:00
|
|
|
use crate::router::{Handler, HandlerObj, ResponseFuture, Router};
|
2019-03-18 21:34:35 +03:00
|
|
|
use crate::web::response;
|
2018-10-02 10:49:36 +03:00
|
|
|
use failure::{Backtrace, Context, Fail, ResultExt};
|
2018-09-21 14:33:23 +03:00
|
|
|
use futures::sync::oneshot;
|
|
|
|
use futures::Stream;
|
2018-08-01 12:44:07 +03:00
|
|
|
use hyper::rt::Future;
|
2019-03-18 21:34:35 +03:00
|
|
|
use hyper::{rt, Body, Request, Server, StatusCode};
|
2018-10-05 18:03:15 +03:00
|
|
|
use rustls;
|
|
|
|
use rustls::internal::pemfile;
|
2018-04-17 00:18:28 +03:00
|
|
|
use std::fmt::{self, Display};
|
2018-10-02 10:49:36 +03:00
|
|
|
use std::fs::File;
|
2018-08-01 12:44:07 +03:00
|
|
|
use std::net::SocketAddr;
|
2018-10-05 18:03:15 +03:00
|
|
|
use std::sync::Arc;
|
2018-09-21 14:33:23 +03:00
|
|
|
use std::{io, thread};
|
2018-10-05 18:03:15 +03:00
|
|
|
use tokio_rustls::ServerConfigExt;
|
|
|
|
use tokio_tcp;
|
2017-03-08 04:00:34 +03:00
|
|
|
|
|
|
|
/// Errors that can be returned by an ApiEndpoint implementation.
|
|
|
|
#[derive(Debug)]
|
2018-04-16 12:00:32 +03:00
|
|
|
pub struct Error {
|
|
|
|
inner: Context<ErrorKind>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
|
|
|
pub enum ErrorKind {
|
|
|
|
#[fail(display = "Internal error: {}", _0)]
|
2017-03-08 04:00:34 +03:00
|
|
|
Internal(String),
|
2018-04-16 12:00:32 +03:00
|
|
|
#[fail(display = "Bad arguments: {}", _0)]
|
2017-03-08 04:00:34 +03:00
|
|
|
Argument(String),
|
2018-04-16 12:00:32 +03:00
|
|
|
#[fail(display = "Not found.")]
|
2017-06-13 02:41:27 +03:00
|
|
|
NotFound,
|
2018-08-01 12:44:07 +03:00
|
|
|
#[fail(display = "Request error: {}", _0)]
|
|
|
|
RequestError(String),
|
|
|
|
#[fail(display = "ResponseError error: {}", _0)]
|
|
|
|
ResponseError(String),
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
|
2018-04-16 12:00:32 +03:00
|
|
|
impl Fail for Error {
|
2018-12-08 02:59:40 +03:00
|
|
|
fn cause(&self) -> Option<&dyn Fail> {
|
2018-04-16 12:00:32 +03:00
|
|
|
self.inner.cause()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn backtrace(&self) -> Option<&Backtrace> {
|
|
|
|
self.inner.backtrace()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 03:21:56 +03:00
|
|
|
impl Display for Error {
|
2018-12-08 02:59:40 +03:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2018-04-16 12:00:32 +03:00
|
|
|
Display::fmt(&self.inner, f)
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:00:32 +03:00
|
|
|
impl Error {
|
|
|
|
pub fn kind(&self) -> &ErrorKind {
|
|
|
|
self.inner.get_context()
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:00:32 +03:00
|
|
|
impl From<ErrorKind> for Error {
|
|
|
|
fn from(kind: ErrorKind) -> Error {
|
|
|
|
Error {
|
|
|
|
inner: Context::new(kind),
|
2017-06-13 02:41:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 12:00:32 +03:00
|
|
|
impl From<Context<ErrorKind>> for Error {
|
|
|
|
fn from(inner: Context<ErrorKind>) -> Error {
|
|
|
|
Error { inner: inner }
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-21 14:33:23 +03:00
|
|
|
/// TLS config
|
2018-12-06 15:04:02 +03:00
|
|
|
#[derive(Clone)]
|
2018-09-21 14:33:23 +03:00
|
|
|
pub struct TLSConfig {
|
2018-11-19 22:47:40 +03:00
|
|
|
pub certificate: String,
|
|
|
|
pub private_key: String,
|
2018-09-21 14:33:23 +03:00
|
|
|
}
|
|
|
|
|
2018-10-02 10:49:36 +03:00
|
|
|
impl TLSConfig {
|
2018-10-05 18:03:15 +03:00
|
|
|
pub fn new(certificate: String, private_key: String) -> TLSConfig {
|
|
|
|
TLSConfig {
|
|
|
|
certificate,
|
|
|
|
private_key,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_certs(&self) -> Result<Vec<rustls::Certificate>, Error> {
|
|
|
|
let certfile = File::open(&self.certificate).context(ErrorKind::Internal(format!(
|
|
|
|
"failed to open file {}",
|
|
|
|
self.certificate
|
2018-10-02 10:49:36 +03:00
|
|
|
)))?;
|
2018-10-05 18:03:15 +03:00
|
|
|
let mut reader = io::BufReader::new(certfile);
|
|
|
|
|
|
|
|
pemfile::certs(&mut reader)
|
|
|
|
.map_err(|_| ErrorKind::Internal("failed to load certificate".to_string()).into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_private_key(&self) -> Result<rustls::PrivateKey, Error> {
|
|
|
|
let keyfile = File::open(&self.private_key).context(ErrorKind::Internal(format!(
|
|
|
|
"failed to open file {}",
|
|
|
|
self.private_key
|
|
|
|
)))?;
|
|
|
|
let mut reader = io::BufReader::new(keyfile);
|
|
|
|
|
|
|
|
let keys = pemfile::pkcs8_private_keys(&mut reader)
|
|
|
|
.map_err(|_| ErrorKind::Internal("failed to load private key".to_string()))?;
|
|
|
|
if keys.len() != 1 {
|
|
|
|
return Err(ErrorKind::Internal(
|
|
|
|
"expected a single private key".to_string(),
|
|
|
|
))?;
|
|
|
|
}
|
|
|
|
Ok(keys[0].clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn build_server_config(&self) -> Result<Arc<rustls::ServerConfig>, Error> {
|
|
|
|
let certs = self.load_certs()?;
|
|
|
|
let key = self.load_private_key()?;
|
|
|
|
let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new());
|
|
|
|
cfg.set_single_cert(certs, key)
|
|
|
|
.context(ErrorKind::Internal(
|
|
|
|
"set single certificate failed".to_string(),
|
|
|
|
))?;
|
|
|
|
Ok(Arc::new(cfg))
|
2018-10-02 10:49:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 04:00:34 +03:00
|
|
|
/// HTTP server allowing the registration of ApiEndpoint implementations.
|
2018-09-21 14:33:23 +03:00
|
|
|
pub struct ApiServer {
|
|
|
|
shutdown_sender: Option<oneshot::Sender<()>>,
|
|
|
|
}
|
2017-03-08 04:00:34 +03:00
|
|
|
|
|
|
|
impl ApiServer {
|
|
|
|
/// Creates a new ApiServer that will serve ApiEndpoint implementations
|
|
|
|
/// under the root URL.
|
2018-08-01 12:44:07 +03:00
|
|
|
pub fn new() -> ApiServer {
|
2018-09-21 14:33:23 +03:00
|
|
|
ApiServer {
|
|
|
|
shutdown_sender: None,
|
|
|
|
}
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
|
2018-10-02 10:49:36 +03:00
|
|
|
/// Starts ApiServer at the provided address.
|
|
|
|
/// TODO support stop operation
|
2018-09-22 10:34:28 +03:00
|
|
|
pub fn start(
|
|
|
|
&mut self,
|
|
|
|
addr: SocketAddr,
|
|
|
|
router: Router,
|
2018-10-02 10:49:36 +03:00
|
|
|
conf: Option<TLSConfig>,
|
|
|
|
) -> Result<thread::JoinHandle<()>, Error> {
|
|
|
|
match conf {
|
|
|
|
Some(conf) => self.start_tls(addr, router, conf),
|
|
|
|
None => self.start_no_tls(addr, router),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the ApiServer at the provided address.
|
|
|
|
fn start_no_tls(
|
|
|
|
&mut self,
|
|
|
|
addr: SocketAddr,
|
|
|
|
router: Router,
|
2018-09-22 10:34:28 +03:00
|
|
|
) -> Result<thread::JoinHandle<()>, Error> {
|
2018-09-21 14:33:23 +03:00
|
|
|
if self.shutdown_sender.is_some() {
|
2018-09-22 10:34:28 +03:00
|
|
|
return Err(ErrorKind::Internal(
|
|
|
|
"Can't start HTTP API server, it's running already".to_string(),
|
|
|
|
))?;
|
2018-09-21 14:33:23 +03:00
|
|
|
}
|
|
|
|
let (tx, _rx) = oneshot::channel::<()>();
|
2018-09-22 10:34:28 +03:00
|
|
|
self.shutdown_sender = Some(tx);
|
|
|
|
thread::Builder::new()
|
2018-09-21 14:33:23 +03:00
|
|
|
.name("apis".to_string())
|
|
|
|
.spawn(move || {
|
|
|
|
let server = Server::bind(&addr)
|
|
|
|
.serve(router)
|
2018-11-19 22:47:40 +03:00
|
|
|
// TODO graceful shutdown is unstable, investigate
|
2018-09-21 14:33:23 +03:00
|
|
|
//.with_graceful_shutdown(rx)
|
|
|
|
.map_err(|e| eprintln!("HTTP API server error: {}", e));
|
|
|
|
|
|
|
|
rt::run(server);
|
2018-12-08 02:59:40 +03:00
|
|
|
})
|
|
|
|
.map_err(|_| ErrorKind::Internal("failed to spawn API thread".to_string()).into())
|
2018-09-21 14:33:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the TLS ApiServer at the provided address.
|
|
|
|
/// TODO support stop operation
|
2018-10-02 10:49:36 +03:00
|
|
|
fn start_tls(
|
2018-09-22 10:34:28 +03:00
|
|
|
&mut self,
|
|
|
|
addr: SocketAddr,
|
|
|
|
router: Router,
|
|
|
|
conf: TLSConfig,
|
|
|
|
) -> Result<thread::JoinHandle<()>, Error> {
|
2018-09-21 14:33:23 +03:00
|
|
|
if self.shutdown_sender.is_some() {
|
2018-09-22 10:34:28 +03:00
|
|
|
return Err(ErrorKind::Internal(
|
|
|
|
"Can't start HTTPS API server, it's running already".to_string(),
|
|
|
|
))?;
|
2018-09-21 14:33:23 +03:00
|
|
|
}
|
2018-10-05 18:03:15 +03:00
|
|
|
|
|
|
|
let tls_conf = conf.build_server_config()?;
|
|
|
|
|
2018-09-22 10:34:28 +03:00
|
|
|
thread::Builder::new()
|
2018-09-21 14:33:23 +03:00
|
|
|
.name("apis".to_string())
|
|
|
|
.spawn(move || {
|
2018-10-05 18:03:15 +03:00
|
|
|
let listener = tokio_tcp::TcpListener::bind(&addr).expect("failed to bind");
|
|
|
|
let tls = listener
|
|
|
|
.incoming()
|
|
|
|
.and_then(move |s| tls_conf.accept_async(s))
|
|
|
|
.then(|r| match r {
|
|
|
|
Ok(x) => Ok::<_, io::Error>(Some(x)),
|
2018-09-21 14:33:23 +03:00
|
|
|
Err(e) => {
|
2018-11-01 18:03:32 +03:00
|
|
|
error!("accept_async failed: {}", e);
|
|
|
|
Ok(None)
|
2018-09-21 14:33:23 +03:00
|
|
|
}
|
2018-12-08 02:59:40 +03:00
|
|
|
})
|
|
|
|
.filter_map(|x| x);
|
2018-10-05 18:03:15 +03:00
|
|
|
let server = Server::builder(tls)
|
|
|
|
.serve(router)
|
|
|
|
.map_err(|e| eprintln!("HTTP API server error: {}", e));
|
2018-09-21 14:33:23 +03:00
|
|
|
|
|
|
|
rt::run(server);
|
2018-12-08 02:59:40 +03:00
|
|
|
})
|
|
|
|
.map_err(|_| ErrorKind::Internal("failed to spawn API thread".to_string()).into())
|
2017-06-16 19:47:29 +03:00
|
|
|
}
|
|
|
|
|
2018-09-21 14:33:23 +03:00
|
|
|
/// Stops the API server, it panics in case of error
|
|
|
|
pub fn stop(&mut self) -> bool {
|
|
|
|
if self.shutdown_sender.is_some() {
|
|
|
|
// TODO re-enable stop after investigation
|
|
|
|
//let tx = mem::replace(&mut self.shutdown_sender, None).unwrap();
|
|
|
|
//tx.send(()).expect("Failed to stop API server");
|
2018-10-21 23:30:56 +03:00
|
|
|
info!("API server has been stoped");
|
2018-09-21 14:33:23 +03:00
|
|
|
true
|
|
|
|
} else {
|
2018-10-21 23:30:56 +03:00
|
|
|
error!("Can't stop API server, it's not running or doesn't spport stop operation");
|
2018-09-21 14:33:23 +03:00
|
|
|
false
|
|
|
|
}
|
2017-03-08 04:00:34 +03:00
|
|
|
}
|
|
|
|
}
|
2018-09-19 18:10:52 +03:00
|
|
|
|
2018-09-21 20:57:59 +03:00
|
|
|
pub struct LoggingMiddleware {}
|
2018-09-19 18:10:52 +03:00
|
|
|
|
|
|
|
impl Handler for LoggingMiddleware {
|
2018-09-21 20:57:59 +03:00
|
|
|
fn call(
|
|
|
|
&self,
|
|
|
|
req: Request<Body>,
|
2018-12-08 02:59:40 +03:00
|
|
|
mut handlers: Box<dyn Iterator<Item = HandlerObj>>,
|
2018-09-21 20:57:59 +03:00
|
|
|
) -> ResponseFuture {
|
2018-10-21 23:30:56 +03:00
|
|
|
debug!("REST call: {} {}", req.method(), req.uri().path());
|
2019-03-18 21:34:35 +03:00
|
|
|
match handlers.next() {
|
|
|
|
Some(handler) => handler.call(req, handlers),
|
|
|
|
None => response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"),
|
|
|
|
}
|
2018-09-19 18:10:52 +03:00
|
|
|
}
|
|
|
|
}
|