mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-02 01:45:21 +00:00
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:
parent
f34ace7673
commit
96aa2441ad
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user