fix: incorrect place for, HTTP/1.1 + read desc
handle different body types
This commit is contained in:
parent
af18bf2ebe
commit
3d8837cdb1
3 changed files with 72 additions and 27 deletions
|
@ -1,13 +1,13 @@
|
||||||
use crate::http::{
|
use crate::http::{
|
||||||
requests::{Request, RequestStatus, URL},
|
requests::{Request, RequestStatus, URL},
|
||||||
responses::{Response, UnitOrBoxedError},
|
responses::{Body, Response, UnitOrBoxedError},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
net::{Shutdown, TcpListener},
|
net::{Shutdown, TcpListener},
|
||||||
};
|
};
|
||||||
|
|
||||||
type DynHandlerFn = dyn Fn(Request) -> Response<'static>;
|
type DynHandlerFn = dyn Fn(Request) -> Response;
|
||||||
type BoxedHandlerFn = Box<DynHandlerFn>;
|
type BoxedHandlerFn = Box<DynHandlerFn>;
|
||||||
|
|
||||||
// Collection of handlers for requests
|
// Collection of handlers for requests
|
||||||
|
@ -31,7 +31,7 @@ impl Handlers {
|
||||||
///
|
///
|
||||||
/// path: Path to match (no trailing /)
|
/// path: Path to match (no trailing /)
|
||||||
/// handler: Function to handle the request. Must return a Response
|
/// handler: Function to handle the request. Must return a Response
|
||||||
pub fn add_handler(&mut self, path: &str, handler: impl Fn(Request) -> Response<'static> + 'static) {
|
pub fn add_handler(&mut self, path: &str, handler: impl Fn(Request) -> Response + 'static) {
|
||||||
self.matchers.insert(path.to_string(), Box::from(handler));
|
self.matchers.insert(path.to_string(), Box::from(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ impl Handlers {
|
||||||
match self.match_handler(&req.url) {
|
match self.match_handler(&req.url) {
|
||||||
Some(handler) => handler(req).send()?,
|
Some(handler) => handler(req).send()?,
|
||||||
None => {
|
None => {
|
||||||
return Response::new(req, 404, "Not Found").send();
|
return Response::new(req, 404, Body::Static("Not Found")).send();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
use std::error::Error;
|
use std::{error::Error, io::prelude::*, net::TcpStream};
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use super::requests::Request;
|
use super::requests::Request;
|
||||||
|
|
||||||
pub struct Response<'a> {
|
pub enum Body {
|
||||||
|
String(String),
|
||||||
|
Static(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Response {
|
||||||
request: Request,
|
request: Request,
|
||||||
pub body: &'a str,
|
pub body: Body,
|
||||||
pub status: u16,
|
pub status: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Response<'a> {
|
impl Response {
|
||||||
pub fn new(request: Request, status: u16, body: &'a str) -> Self {
|
pub fn new(request: Request, status: u16, body: Body) -> Self {
|
||||||
Response { request, body, status }
|
Response {
|
||||||
|
request,
|
||||||
|
body,
|
||||||
|
status,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(self) -> UnitOrBoxedError {
|
pub fn send(self) -> UnitOrBoxedError {
|
||||||
|
@ -22,7 +29,7 @@ impl<'a> Response<'a> {
|
||||||
|
|
||||||
pub type UnitOrBoxedError = Result<(), Box<dyn Error>>;
|
pub type UnitOrBoxedError = Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
fn send_response(mut stream: TcpStream, status: u16, body: &str) -> UnitOrBoxedError {
|
fn send_response(mut stream: TcpStream, status: u16, body: Body) -> UnitOrBoxedError {
|
||||||
let status_line = match status {
|
let status_line = match status {
|
||||||
200 => "200 OK",
|
200 => "200 OK",
|
||||||
400 => "400 BAD REQUEST",
|
400 => "400 BAD REQUEST",
|
||||||
|
@ -31,12 +38,16 @@ fn send_response(mut stream: TcpStream, status: u16, body: &str) -> UnitOrBoxedE
|
||||||
_ => "500 INTERNAL SERVER ERROR",
|
_ => "500 INTERNAL SERVER ERROR",
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = format!(
|
let mut response = format!("HTTP/1.1 {}\r\nServer: luciders/0.1.0\r\n", status_line);
|
||||||
"{}\r\nContent-Length: {}\r\nServer: luciders/0.1.0\r\n\r\nHTTP/1.1 {}",
|
|
||||||
status_line,
|
response.push_str(&format!(
|
||||||
body.len(),
|
"Content-Length: {}\r\n",
|
||||||
body
|
match &body {
|
||||||
);
|
Body::String(s) => s.len(),
|
||||||
|
Body::Static(s) => s.len(),
|
||||||
|
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
match stream.write(response.as_bytes()) {
|
match stream.write(response.as_bytes()) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
|
46
src/main.rs
46
src/main.rs
|
@ -1,12 +1,29 @@
|
||||||
use std::{net::TcpListener, process};
|
use std::{env, ffi::OsString, fs, net::TcpListener, process};
|
||||||
|
|
||||||
use ctrlc;
|
use ctrlc;
|
||||||
use http::responses::Response;
|
use http::responses::{Response, Body};
|
||||||
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod http;
|
mod http;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println!("luciders starting...");
|
||||||
|
|
||||||
|
let icons_dir_arg = env::args_os()
|
||||||
|
.nth(1)
|
||||||
|
.unwrap_or(OsString::from("vendor/lucide/icons"));
|
||||||
|
|
||||||
|
println!("Using icons from: {:?}", icons_dir_arg);
|
||||||
|
|
||||||
|
let icon_filenames: Vec<_> = fs::read_dir(icons_dir_arg)
|
||||||
|
.unwrap_or_else(|_| fatal("Failed to read icons directory! Does the path exist?"))
|
||||||
|
.map(|entry| entry.unwrap_or_else(|_| fatal("Failed to read icon entry")))
|
||||||
|
.map(|entry| entry.file_name())
|
||||||
|
.filter(|entry| entry.to_str().unwrap_or("").ends_with(".svg"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
println!("Found {} icons", icon_filenames.len());
|
||||||
|
|
||||||
let listener =
|
let listener =
|
||||||
TcpListener::bind("[::]:7878").unwrap_or_else(|_| fatal("Failed to bind to address"));
|
TcpListener::bind("[::]:7878").unwrap_or_else(|_| fatal("Failed to bind to address"));
|
||||||
|
|
||||||
|
@ -19,11 +36,28 @@ fn main() {
|
||||||
let mut handlers = handlers::Handlers::new();
|
let mut handlers = handlers::Handlers::new();
|
||||||
|
|
||||||
handlers.add_handler("/", |req| {
|
handlers.add_handler("/", |req| {
|
||||||
if req.method == "GET" {
|
if req.method != "GET" {
|
||||||
Response::new(req, 200, "OK - luciders is running")
|
return Response::new(req, 405, Body::Static("Method Not Allowed"));
|
||||||
} else {
|
|
||||||
Response::new(req, 405, "Method Not Allowed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Response::new(req, 200, Body::Static("OK - luciders is running"))
|
||||||
|
});
|
||||||
|
|
||||||
|
handlers.add_handler("/icons/[icon].png", move |req| {
|
||||||
|
if req.method != "GET" {
|
||||||
|
return Response::new(req, 405, Body::Static("Method Not Allowed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon_name = match req.url.get_path_segment(1) {
|
||||||
|
Some(icon) => icon,
|
||||||
|
None => return Response::new(req, 404, Body::Static("Icon Not Found")),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !icon_filenames.contains(&OsString::from(&icon_name[..icon_name.len() - 4])) {
|
||||||
|
return Response::new(req, 404, Body::Static("Icon Not Found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response::new(req, 200, Body::Static("Icon Not Found"));
|
||||||
});
|
});
|
||||||
|
|
||||||
handlers.bind(listener);
|
handlers.bind(listener);
|
||||||
|
|
Loading…
Reference in a new issue