1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! (Method, URL) => Code

use {
    crate::{asset, render, util, Request},
    atomicwrites::{AllowOverwrite, AtomicFile},
    std::{
        fs,
        io::{self, Write},
        path::Path,
    },
    tiny_http::Method::{Get, Post},
};

/// Route a Request to (Status Code, Body, Content-Type)
pub fn route(req: &mut Request) -> Result<(i32, String, &'static str), io::Error> {
    let mut status = 404;
    let mut body = "404 Not Found".to_string();
    let mut content_type = "text/html; charset=utf8";

    let full_url = req.url().to_string();
    let mut parts = full_url.splitn(2, "?");
    let (url, query) = (parts.next().unwrap_or("/"), parts.next().unwrap_or(""));

    match (req.method(), url) {
        (Get, "/") => {
            status = 200;
            body = render::index(&req)?;
        }
        (Get, "/new") => {
            status = 200;
            let name = req.param("name");

            body = render::layout(
                "new page",
                &asset::to_string("new.html")?.replace("{name}", &name),
                None,
            );
        }
        (Get, "/sleep") => {
            status = 200;
            body = "Zzzzz...".into();
            std::thread::sleep(std::time::Duration::from_secs(5));
        }
        (Get, "/search") => {
            status = 200;
            body = render::search(req.param("tag"))?;
        }
        (Get, "/404") => {
            status = 404;
            body = asset::to_string("404.html")?;
        }
        (Post, "/new") => {
            let path = render::pathify(&req.param("name"));
            if !req.page_names().contains(&path) {
                if let Some(disk_path) = render::new_page_path(&path) {
                    if disk_path.contains('/') {
                        if let Some(dir) = Path::new(&disk_path).parent() {
                            fs::create_dir_all(&dir.display().to_string())?;
                        }
                    }
                    let mut file = fs::File::create(disk_path)?;
                    let mdown = req.param("markdown");
                    write!(file, "{}", mdown)?;
                    status = 302;
                    body = path.to_string();
                }
            }
        }
        (Post, path) => {
            if query.is_empty() {
                status = 404;
                body = asset::to_string("404.html")?;
            } else {
                if let Some(disk_path) = render::page_path(path) {
                    let mut content = String::new();
                    req.as_reader().read_to_string(&mut content)?;
                    let mdown = content.split("markdown=").last().unwrap_or("");
                    let af = AtomicFile::new(disk_path, AllowOverwrite);
                    af.write(|f| f.write_all(util::decode_form_value(mdown).as_bytes()))?;
                    status = 302;
                    body = path.to_string();
                } else {
                    status = 404;
                    body = asset::to_string("404.html")?;
                }
            }
        }

        (Get, path) => {
            if let Some(disk_path) = render::page_path(path) {
                status = 200;
                if query.is_empty() {
                    body = render::page(req, path).unwrap_or_else(|_| "".into());
                } else if query == "edit" {
                    body = render::layout(
                        "Edit",
                        &asset::to_string("edit.html")?
                            .replace("{markdown}", &fs::read_to_string(disk_path)?),
                        None,
                    )
                }
            } else if asset::exists(path) {
                status = 200;
                body = asset::to_string(path)?;
                content_type = util::get_content_type(path);
            } else {
                status = 404;
                body = asset::to_string("404.html")?;
            }
        }

        (x, y) => println!("x: {:?}, y: {:?}", x, y),
    }
    Ok((status, body, content_type))
}