vmm: http: Convert to micro_http HttpServer

The new micro_http package provides a built-in HttpServer wrapper for
running a more robust HTTP server based on the package HTTP API.

Switching to this implementation allows us to, among other things,
handle HTTP requests that are larger than 1024 bytes.

Fixes: #423

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2019-11-08 22:59:08 +01:00
parent f34ace7673
commit 96aa2441ad
3 changed files with 41 additions and 88 deletions

29
Cargo.lock generated
View File

@ -302,14 +302,6 @@ name = "glob"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hermit-abi"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ipnetwork"
version = "0.14.0"
@ -439,15 +431,6 @@ dependencies = [
"vmm-sys-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.9.52"
@ -922,14 +905,6 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "threadpool"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.6"
@ -1084,7 +1059,6 @@ dependencies = [
"serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"signal-hook 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vfio 0.0.1",
"vm-allocator 0.1.0",
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
@ -1183,7 +1157,6 @@ dependencies = [
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
"checksum ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3d862c86f7867f19b693ec86765e0252d82e53d4240b9b629815675a0714ad1"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
@ -1198,7 +1171,6 @@ dependencies = [
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum micro_http 0.1.0 (git+https://github.com/firecracker-microvm/firecracker)" = "<none>"
"checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5"
"checksum openssl-sys 0.9.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c977d08e1312e2f7e4b86f9ebaa0ed3b19d1daff75fae88bbb88108afbd801fc"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum pnet 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d693c84430248366146e3181ff9d330243464fa9e6146c372b2f3eb2e2d8e7"
@ -1249,7 +1221,6 @@ dependencies = [
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

View File

@ -33,7 +33,6 @@ vm-allocator = { path = "../vm-allocator" }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = ">=0.1.1"
signal-hook = "0.1.10"
threadpool = "1.0"
[dependencies.linux-loader]
git = "https://github.com/rust-vmm/linux-loader"

View File

@ -3,22 +3,17 @@
// SPDX-License-Identifier: Apache-2.0
//
extern crate threadpool;
use crate::api::http_endpoint::{VmActionHandler, VmCreate, VmInfo, VmmShutdown};
use crate::api::{ApiRequest, VmAction};
use crate::{Error, Result};
use micro_http::{HttpConnection, MediaType, Request, Response, StatusCode, Version};
use micro_http::{HttpServer, MediaType, Request, Response, StatusCode, Version};
use std::collections::HashMap;
use std::io::{Read, Write};
use std::os::unix::net::UnixListener;
use std::path::PathBuf;
use std::sync::mpsc::Sender;
use std::thread;
use threadpool::ThreadPool;
use vmm_sys_util::eventfd::EventFd;
const HTTP_ROOT: &str = "/api/v1";
const NUM_THREADS: usize = 4;
/// An HTTP endpoint handler interface
pub trait EndpointHandler: Sync + Send {
@ -68,35 +63,23 @@ lazy_static! {
};
}
fn http_serve<T: Read + Write>(
http_connection: &mut HttpConnection<T>,
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
) {
if http_connection.try_read().is_err() {
http_connection.enqueue_response(Response::new(
Version::Http11,
StatusCode::InternalServerError,
));
fn handle_http_request(
request: &Request,
api_notifier: &EventFd,
api_sender: &Sender<ApiRequest>,
) -> Response {
let path = request.uri().get_abs_path().to_string();
let mut response = match HTTP_ROUTES.routes.get(&path) {
Some(route) => match api_notifier.try_clone() {
Ok(notifier) => route.handle_request(&request, notifier, api_sender.clone()),
Err(_) => Response::new(Version::Http11, StatusCode::InternalServerError),
},
None => Response::new(Version::Http11, StatusCode::NotFound),
};
return;
}
while let Some(request) = http_connection.pop_parsed_request() {
let sender = api_sender.clone();
let path = request.uri().get_abs_path().to_string();
let mut response = match HTTP_ROUTES.routes.get(&path) {
Some(route) => match api_notifier.try_clone() {
Ok(notifier) => route.handle_request(&request, notifier, sender),
Err(_) => Response::new(Version::Http11, StatusCode::InternalServerError),
},
None => Response::new(Version::Http11, StatusCode::NotFound),
};
response.set_server("Cloud Hypervisor API");
response.set_content_type(MediaType::ApplicationJson);
http_connection.enqueue_response(response);
}
response.set_server("Cloud Hypervisor API");
response.set_content_type(MediaType::ApplicationJson);
response
}
pub fn start_http_thread(
@ -104,36 +87,36 @@ pub fn start_http_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
) -> Result<thread::JoinHandle<Result<()>>> {
let listener = UnixListener::bind(path).map_err(Error::Bind)?;
let pool = ThreadPool::new(NUM_THREADS);
std::fs::remove_file(path).unwrap_or_default();
let socket_path = PathBuf::from(path);
thread::Builder::new()
.name("http-server".to_string())
.spawn(move || {
for stream in listener.incoming() {
match stream {
Ok(s) => {
let sender = api_sender.clone();
let notifier = api_notifier.try_clone().map_err(Error::EventFdClone)?;
pool.execute(move || {
let mut http_connection = HttpConnection::new(s);
http_serve(&mut http_connection, notifier, sender);
// It's ok to panic from a threadpool managed thread,
// it won't make parent threads crash.
http_connection.try_write().unwrap();
});
let mut server = HttpServer::new(socket_path).unwrap();
server.start_server().unwrap();
loop {
match server.requests() {
Ok(request_vec) => {
for server_request in request_vec {
server
.respond(server_request.process(|request| {
handle_http_request(request, &api_notifier, &api_sender)
}))
.or_else(|e| {
error!("HTTP server error on response: {}", e);
Ok(())
})?;
}
}
Err(e) => {
error!(
"HTTP server error on retrieving incoming request. Error: {}",
e
);
}
Err(_) => continue,
}
}
pool.join();
Ok(())
})
.map_err(Error::HttpThreadSpawn)
}