mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 13:44:15 +00:00
Use a custom sandbox to avoid OOM
This commit is contained in:
parent
a37637a49f
commit
6c8b467958
4 changed files with 109 additions and 3 deletions
|
@ -23,3 +23,5 @@ handlebars = "0.20.0"
|
|||
handlebars-iron = "0.18.0"
|
||||
staticfile = "0.3.0"
|
||||
mount = "0.2.1"
|
||||
ipc-channel = "0.5.1"
|
||||
libc = "0.2.14"
|
||||
|
|
|
@ -10,6 +10,10 @@ extern crate handlebars;
|
|||
extern crate handlebars_iron;
|
||||
extern crate staticfile;
|
||||
extern crate mount;
|
||||
extern crate ipc_channel;
|
||||
extern crate libc;
|
||||
|
||||
pub mod worker;
|
||||
|
||||
use iron::prelude::*;
|
||||
use iron::status;
|
||||
|
@ -21,6 +25,8 @@ use mount::Mount;
|
|||
use staticfile::Static;
|
||||
use std::collections::BTreeMap;
|
||||
use params::{Params, Value};
|
||||
use std::env;
|
||||
use worker::eval;
|
||||
|
||||
fn root(req: &mut Request) -> IronResult<Response> {
|
||||
let mut data = BTreeMap::new();
|
||||
|
@ -28,7 +34,7 @@ fn root(req: &mut Request) -> IronResult<Response> {
|
|||
let map = req.get_ref::<Params>().unwrap();
|
||||
match map.find(&["q"]) {
|
||||
Some(&Value::String(ref query)) => {
|
||||
let reply = rink::one_line_sandbox(query);
|
||||
let reply = eval(query);
|
||||
data.insert("content".to_owned(), reply);
|
||||
},
|
||||
_ => (),
|
||||
|
@ -46,12 +52,20 @@ fn api(req: &mut Request) -> IronResult<Response> {
|
|||
_ => return Ok(Response::with((acao, status::BadRequest))),
|
||||
};
|
||||
|
||||
let reply = rink::one_line_sandbox(query);
|
||||
let reply = eval(query);
|
||||
|
||||
Ok(Response::with((acao, status::Ok, reply)))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args();
|
||||
args.next();
|
||||
if args.next().map(|x| x == "--sandbox").unwrap_or(false) {
|
||||
let server = args.next().unwrap();
|
||||
let query = args.next().unwrap();
|
||||
worker::worker(&server, &query);
|
||||
}
|
||||
|
||||
let mut mount = Mount::new();
|
||||
|
||||
let mut router = Router::new();
|
||||
|
|
88
web/src/worker.rs
Normal file
88
web/src/worker.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use libc;
|
||||
use std::io::Error;
|
||||
use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::env;
|
||||
use rink;
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
pub fn worker(server_name: &str, query: &str) -> ! {
|
||||
let tx = IpcSender::connect(server_name.to_owned()).unwrap();
|
||||
|
||||
tx.send("".to_owned()).unwrap();
|
||||
|
||||
unsafe {
|
||||
let limit = libc::rlimit {
|
||||
// 100 megabytes
|
||||
rlim_cur: 100_000_000,
|
||||
rlim_max: 100_000_000,
|
||||
};
|
||||
let res = libc::setrlimit(libc::RLIMIT_AS, &limit);
|
||||
if res == -1 {
|
||||
panic!("Setrlimit RLIMIT_AS failed: {}", Error::last_os_error())
|
||||
}
|
||||
let limit = libc::rlimit {
|
||||
// 15 seconds
|
||||
rlim_cur: 15,
|
||||
rlim_max: 15
|
||||
};
|
||||
let res = libc::setrlimit(libc::RLIMIT_CPU, &limit);
|
||||
if res == -1 {
|
||||
panic!("Setrlimit RLIMIT_AS failed: {}", Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
let mut ctx = rink::load().unwrap();
|
||||
ctx.short_output = true;
|
||||
let reply = match rink::one_line(&mut ctx, query) {
|
||||
Ok(v) => v,
|
||||
Err(e) => e
|
||||
};
|
||||
tx.send(reply).unwrap();
|
||||
|
||||
::std::process::exit(0)
|
||||
}
|
||||
|
||||
pub fn eval(query: &str) -> String {
|
||||
let (server, server_name) = IpcOneShotServer::new().unwrap();
|
||||
|
||||
let res = Command::new(env::current_exe().unwrap())
|
||||
.arg("--sandbox")
|
||||
.arg(server_name)
|
||||
.arg(query)
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.env("RUST_BACKTRACE", "1")
|
||||
.spawn()
|
||||
.map_err(|x| format!("{}", x));
|
||||
let child = match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => return format!("Failed to run sandbox: {}", e)
|
||||
};
|
||||
let (rx, _) = server.accept().unwrap();
|
||||
|
||||
match rx.recv() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
let output = match child.wait_with_output() {
|
||||
Ok(v) => v,
|
||||
Err(e) => return format!("{}", e)
|
||||
};
|
||||
match output.status.signal() {
|
||||
Some(libc::SIGXCPU) => return format!("Calculation went over time limit"),
|
||||
_ => ()
|
||||
};
|
||||
format!(
|
||||
"Receiving reply from sandbox failed: {}\n\
|
||||
Signal: {}\n\
|
||||
Sandbox stdout: {}\n\
|
||||
Sandbox stderr: {}",
|
||||
e,
|
||||
output.status.signal().map(|x| format!("{}", x)).unwrap_or("None".to_owned()),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,9 @@
|
|||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<pre>
|
||||
{{content}}
|
||||
</pre>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue