diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 124 |
1 files changed, 70 insertions, 54 deletions
diff --git a/src/main.rs b/src/main.rs index 276a3e2..7313a6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,24 @@ mod get_routes; mod post_routes; mod shares; -pub(crate) type Response = hyper::Response<hyper::Body>; +pub enum Response { + Raw(HyperResponse), + Page(Page), +} + +impl From<Page> for Response { + fn from(page: Page) -> Self { + Self::Page(page) + } +} + +impl From<HyperResponse> for Response { + fn from(resp: HyperResponse) -> Self { + Self::Raw(resp) + } +} + +pub(crate) type HyperResponse = hyper::Response<hyper::Body>; pub(crate) type Request = hyper::Request<hyper::Body>; #[derive(Clap, Debug)] @@ -194,11 +211,18 @@ async fn service<C: Controller>( controller: Arc<C>, args: Arc<Args>, request: Request, -) -> Result<Response, Infallible> { - let (parts, body) = request.into_parts(); +) -> Result<HyperResponse, Infallible> { + let (mut parts, body) = request.into_parts(); - let mut resp = build_response(args, &*controller, parts, body) + let mut resp = build_response(args, &*controller, &mut parts, body) .await + .map(|resp| match resp { + Response::Raw(resp) => resp, + Response::Page(page) => Builder::new() + .content_type(mime::TEXT_HTML) + .body(render_page(&page, &*controller, &parts).into()) + .unwrap(), + }) .unwrap_or_else(|err| { let (status, message) = match err { Error::BadRequest(msg) => (400, msg), @@ -243,48 +267,35 @@ async fn service<C: Controller>( Ok(resp) } -pub struct Page<'a> { +pub struct Page { title: String, header: Option<String>, body: String, - controller: &'a dyn Controller, - parts: &'a Parts, -} - -impl From<Page<'_>> for Response { - fn from(page: Page) -> Self { - Builder::new() - .content_type(mime::TEXT_HTML) - .body(page.render().into()) - .unwrap() - } } const CSS: &str = include_str!("static/style.css"); -impl Page<'_> { - fn render(&self) -> String { - format!( - "<!doctype html>\ - <html>\ - <head>\ - <meta charset=utf-8>\ - <title>{}</title>\ - <meta name=viewport content=\"width=device-width, initial-scale=1\">\ - <style>{}</style>\ - </head>\ - <body><header id=header>{}{}</header>{}</body></html>\ - ", - html_escape(&self.title), - CSS, - self.header.as_deref().unwrap_or_default(), - self.controller - .user_info_html(self.parts) - .map(|h| format!("<div class=user-info>{}</div>", h)) - .unwrap_or_default(), - self.body, - ) - } +fn render_page<C: Controller>(page: &Page, controller: &C, parts: &Parts) -> String { + format!( + "<!doctype html>\ + <html>\ + <head>\ + <meta charset=utf-8>\ + <title>{}</title>\ + <meta name=viewport content=\"width=device-width, initial-scale=1\">\ + <style>{}</style>\ + </head>\ + <body><header id=header>{}{}</header>{}</body></html>\ + ", + html_escape(&page.title), + CSS, + page.header.as_deref().unwrap_or_default(), + controller + .user_info_html(parts) + .map(|h| format!("<div class=user-info>{}</div>", h)) + .unwrap_or_default(), + page.body, + ) } #[derive(Deserialize)] @@ -309,7 +320,7 @@ impl Branch { async fn build_response<C: Controller>( args: Arc<Args>, controller: &C, - parts: Parts, + parts: &mut Parts, body: Body, ) -> Result<Response, Error> { let unsanitized_path = percent_decode_str(parts.uri.path()) @@ -346,17 +357,16 @@ async fn build_response<C: Controller>( repo, path: url_path, branch: rev, - parts, }; - if !controller.may_read_path(&ctx) { + if !controller.may_read_path(&ctx, parts) { return Err(Error::Unauthorized( "you are not authorized to view this file".into(), )); } - if ctx.parts.method == Method::POST { - return post_routes::build_response(&args, ¶ms, controller, ctx, body).await; + if parts.method == Method::POST { + return post_routes::build_response(&args, ¶ms, controller, ctx, body, parts).await; } let mut tree = ctx @@ -372,17 +382,18 @@ async fn build_response<C: Controller>( return Err(Error::NotFound("directory not found".into())); } - if controller.may_write_path(&ctx) { + if controller.may_write_path(&ctx, parts) { if params.action == "edit" { return Ok(forms::edit_text_form( &forms::EditForm::default(), None, controller, &ctx, + parts, ) .into()); } else if params.action == "upload" { - return Ok(forms::upload_form(false, controller, &ctx).into()); + return Ok(forms::upload_form(false, controller, &ctx, parts).into()); } else { return Err(Error::NotFound( "file not found, but <a href=?action=edit>you can write it</a> or <a href=?action=upload>upload it</a>".into(), @@ -404,18 +415,19 @@ async fn build_response<C: Controller>( .build_url_path(&ctx.branch, unsanitized_path.trim_end_matches('/')), ) .body("redirecting".into()) - .unwrap()); + .unwrap() + .into()); } - return get_routes::get_blob(entr, params, controller, ctx); + return get_routes::get_blob(entr, params, controller, ctx, &parts); } tree = ctx.repo.find_tree(entr.id()); if !unsanitized_path.ends_with('/') { - return Err(Error::MissingTrailingSlash(ctx.parts.uri.path().to_owned())); + return Err(Error::MissingTrailingSlash(parts.uri.path().to_owned())); } } - get_routes::view_tree(tree, controller, &ctx) + get_routes::view_tree(tree, controller, &ctx, &parts) } fn render_link(name: &str, label: &str, active_action: &str) -> String { @@ -435,18 +447,23 @@ fn render_link(name: &str, label: &str, active_action: &str) -> String { ) } -fn action_links<C: Controller>(active_action: &str, controller: &C, ctx: &Context) -> String { +fn action_links<C: Controller>( + active_action: &str, + controller: &C, + ctx: &Context, + parts: &Parts, +) -> String { let mut out = String::new(); out.push_str("<div class=actions>"); out.push_str("<a href=. title='list parent directory'>ls</a>"); out.push_str(&render_link("view", "view", active_action)); - if controller.may_write_path(ctx) { + if controller.may_write_path(ctx, parts) { out.push_str(&render_link("edit", "edit", active_action)); } out.push_str(&render_link("log", "log", active_action)); out.push_str(&render_link("raw", "raw", active_action)); - if controller.may_move_path(ctx) { + if controller.may_move_path(ctx, parts) { out.push_str(&render_link("move", "mv", active_action)); out.push_str(&render_link("remove", "rm", active_action)); } @@ -456,7 +473,6 @@ fn action_links<C: Controller>(active_action: &str, controller: &C, ctx: &Contex pub struct Context { repo: Repository, - parts: Parts, branch: Branch, path: PathBuf, } |