summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kjetil.orbekk@gmail.com>2017-06-18 12:41:14 -0400
committerKjetil Orbekk <kjetil.orbekk@gmail.com>2017-06-18 12:41:14 -0400
commit0b6e7c0ff2e67624a842125a3992b07cd4769e17 (patch)
tree0066febfa7305cd999ad0f0e9df97f647075858e
parent96cd53ca31da2eedf3ef38124cd8f07a79443c00 (diff)
Support base_url.
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/bin/main.rs22
-rw-r--r--src/lib.rs1
-rw-r--r--src/server.rs49
5 files changed, 57 insertions, 17 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4d907cb..949930f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,7 @@ dependencies = [
"rusqlite 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index f15b815..43e634c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,3 +19,4 @@ clap = "*"
rpassword = "*"
params = "*"
persistent = "*"
+url = "*"
diff --git a/src/bin/main.rs b/src/bin/main.rs
index 245416c..506eba4 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -38,8 +38,8 @@ fn create_admin_user(conn: &rusqlite::Connection) {
}
}
-fn serve(context: systemhttp::server::Context, port: u16) {
- let _server = systemhttp::server::serve(context, port).unwrap();
+fn serve(context: systemhttp::server::Context, state: systemhttp::server::State, port: u16) {
+ let _server = systemhttp::server::serve(context, state, port).unwrap();
println!("Serving on {}", port);
}
@@ -58,6 +58,10 @@ fn main() {
.long("db_file")
.takes_value(true)
.help("Path to sqlite database"))
+ .arg(Arg::with_name("base_url")
+ .long("base_url")
+ .takes_value(true)
+ .help("URL to prepend to links (useful with proxies)"))
.subcommand(SubCommand::with_name("serve")
.about("Start the systemhttpd server"))
.subcommand(SubCommand::with_name("create_admin_user")
@@ -72,19 +76,25 @@ fn main() {
let db_file = matches.value_of("db_file").unwrap();
+ let base_url = matches.value_of("base_url").unwrap_or("").to_string();
+
env_logger::init().unwrap();
let mut conn = rusqlite::Connection::open(db_file)
.expect(format!("opening sqlite database at {}", db_file).as_str());
systemhttp::db::init(&mut conn);
- let mut context = systemhttp::server::Context {
- base_url: "http://localhost:8080".to_string(),
+ let context = systemhttp::server::Context {
+ base_url: base_url,
+ };
+ info!("{:?}", context);
+ let state = systemhttp::server::State {
conn: conn,
};
+ info!("{:?}", state);
match matches.subcommand_name() {
- Some("serve") => serve(context, port),
- Some("create_admin_user") => create_admin_user(&context.conn),
+ Some("serve") => serve(context, state, port),
+ Some("create_admin_user") => create_admin_user(&state.conn),
x => panic!("Don't know about subcommand: {:?}", x),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 3fd5b67..70c942a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,6 +15,7 @@ extern crate staticfile;
extern crate regex;
extern crate params;
extern crate persistent;
+extern crate url;
pub mod systemd;
pub mod render;
diff --git a/src/server.rs b/src/server.rs
index c0e9028..4e5b6f3 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -16,19 +16,26 @@ use router::Router;
use staticfile::Static;
use systemd::journal;
use systemd::unit;
-use persistent::Write;
+use persistent::{Read, Write};
use rusqlite::Connection;
use db;
use auth;
+use url;
#[derive(Debug)]
pub struct Context {
pub base_url: String,
- pub conn: Connection,
}
impl iron::typemap::Key for Context {
type Value = Context;
}
+#[derive(Debug)]
+pub struct State {
+ pub conn: Connection,
+}
+impl iron::typemap::Key for State {
+ type Value = State;
+}
#[derive(Default, Debug, Clone)]
struct Login {
@@ -47,6 +54,22 @@ impl iron_sessionstorage::Value for Login {
}
}
+// Construct an absolute url from base_url if provided, or the request url
+// otherwise.
+fn url_for(r: &mut Request, path: &str) -> Url {
+ let context = r.get::<Read<Context>>().unwrap();
+ match context.base_url.as_ref() {
+ "" => {
+ let mut url: url::Url = r.url.clone().into();
+ url.set_path(path);
+ Url::from_generic_url(url).unwrap()
+ },
+ base_url => {
+ Url::parse(&format!("{}{}", base_url, path)).unwrap()
+ }
+ }
+}
+
fn overview(r: &mut Request) -> IronResult<Response> {
let mut _value = try!(r.session().get::<Login>());
@@ -139,16 +162,16 @@ fn authenticate(r: &mut Request) -> IronResult<Response> {
};
let hash = {
- let mutex = r.get::<Write<Context>>().unwrap();
- let context = mutex.lock().unwrap();
- db::lookup_user(&context.conn, &user).unwrap()
+ let mutex = r.get::<Write<State>>().unwrap();
+ let state = mutex.lock().unwrap();
+ db::lookup_user(&state.conn, &user).unwrap()
};
if let Some(true) = hash.map(|h| auth::validate(&password, &h)) {
let login = Login { user: user.to_string() }; // TODO Make a validated login type
info!("User logged in: {:?}", login);
r.session().set(login)?;
- let url = url_for!(r, "root");
+ let url = url_for(r, "");
Ok(Response::with((status::Found, Redirect(url))))
} else {
login(r)
@@ -157,14 +180,17 @@ fn authenticate(r: &mut Request) -> IronResult<Response> {
fn logout(r: &mut Request) -> IronResult<Response> {
r.session().set::<Login>(Default::default());
- let url = url_for!(r, "root");
+ let url = url_for(r, "");
Ok(Response::with((status::Found, Redirect(url))))
}
fn make_renderer(r: &mut Request) -> IronResult<render::Renderer> {
let user = get_logged_in_user(r)?.map(|u| u.user);
- let base_url = format!("{}", url_for!(r, "root"));
- Ok(render::Renderer { base_url: base_url, user: user })
+ let context = r.get::<Read<Context>>().unwrap();
+ Ok(render::Renderer {
+ base_url: context.base_url.to_string(),
+ user: user
+ })
}
fn static_file(r: &mut Request) -> IronResult<Response> {
@@ -180,7 +206,7 @@ fn static_file(r: &mut Request) -> IronResult<Response> {
})
}
-pub fn serve(context: Context, port: u16) -> HttpResult<Listening> {
+pub fn serve(context: Context, state: State, port: u16) -> HttpResult<Listening> {
// TODO: Use a real secret.
let secret = b"secret2".to_vec();
let router = router!(
@@ -194,7 +220,8 @@ pub fn serve(context: Context, port: u16) -> HttpResult<Listening> {
);
let mut chain = Chain::new(router);
chain.link_around(SessionStorage::new(SignedCookieBackend::new(secret)));
- chain.link(Write::<Context>::both(context));
+ chain.link(Read::<Context>::both(context));
+ chain.link(Write::<State>::both(state));
let bind_address = format!("{}:{}", "::", port);
Iron::new(chain).http(bind_address.as_str())
}