Now handling pictures, using raw bytes

This commit is contained in:
Justine 2023-01-09 16:05:19 +01:00
parent da6d94e1f3
commit 0cc2d8cbb6
11 changed files with 80 additions and 456 deletions

51
Cargo.lock generated
View File

@ -13,15 +13,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "async-trait"
version = "0.1.61"
@ -114,24 +105,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
[[package]]
name = "file-matcher"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54a429ce9698e7d0de61e7f570477cc2d2f8b3f48f976b2edcfdbd797c085eb"
dependencies = [
"fs_extra",
"regex",
"serde",
"wildmatch",
]
[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "generic-array"
version = "0.14.6"
@ -167,7 +140,6 @@ name = "hello"
version = "0.1.0"
dependencies = [
"config",
"file-matcher",
]
[[package]]
@ -311,23 +283,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "ron"
version = "0.7.1"
@ -467,12 +422,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wildmatch"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86"
[[package]]
name = "yaml-rust"
version = "0.4.5"

View File

@ -7,4 +7,3 @@ edition = "2021"
[dependencies]
config = "0.13.3"
file-matcher = "0.7.0"

View File

@ -3,5 +3,6 @@
This is a simple web server expanding on the example given in the Rust book. At the present time, it answers with static html.
TODO:
* Also answer css requests
* Also answer css requests, pictures, etc => OK
* Fully integrate the config path => More or less
* Gather info about the client (IP, User-Agent, etc) to do funny stuff with it

1
html/css/main.css Normal file
View File

@ -0,0 +1 @@
Hello

View File

@ -1,361 +1,14 @@
<!DOCTYPE HTML>
<!--
Dimension by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Welcome</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
<!--[if lte IE 9]><link rel="stylesheet" href="assets/css/ie9.css" /><![endif]-->
<noscript><link rel="stylesheet" href="assets/css/noscript.css" /></noscript>
<meta charset="utf-8">
<title>Hi!</title>
</head>
<body>
<!-- Wrapper -->
<div id="wrapper">
<!-- Header -->
<header id="header">
<div class="logo">
<span class="icon fa-diamond"></span>
</div>
<div class="content">
<div class="inner">
<h1>Dimension</h1>
<p><!--[-->A fully responsive site template designed by <a href="https://html5up.net">HTML5 UP</a> and released<!--]--><br />
<!--[-->for free under the <a href="https://html5up.net/license">Creative Commons</a> license.<!--]--></p>
</div>
</div>
<nav>
<ul>
<li><a href="#intro">Intro</a></li>
<li><a href="#work">Work</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<!--<li><a href="#elements">Elements</a></li>-->
</ul>
</nav>
</header>
<!-- Main -->
<div id="main">
<!-- Intro -->
<article id="intro">
<h2 class="major">Intro</h2>
<span class="image main"><img src="images/pic01.jpg" alt="" /></span>
<p>Aenean ornare velit lacus, ac varius enim ullamcorper eu. Proin aliquam facilisis ante interdum congue. Integer mollis, nisl amet convallis, porttitor magna ullamcorper, amet egestas mauris. Ut magna finibus nisi nec lacinia. Nam maximus erat id euismod egestas. By the way, check out my <a href="#work">awesome work</a>.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dapibus rutrum facilisis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam tristique libero eu nibh porttitor fermentum. Nullam venenatis erat id vehicula viverra. Nunc ultrices eros ut ultricies condimentum. Mauris risus lacus, blandit sit amet venenatis non, bibendum vitae dolor. Nunc lorem mauris, fringilla in aliquam at, euismod in lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non lorem sit amet elit placerat maximus. Pellentesque aliquam maximus risus, vel sed vehicula.</p>
</article>
<!-- Work -->
<article id="work">
<h2 class="major">Work</h2>
<span class="image main"><img src="images/pic02.jpg" alt="" /></span>
<p>Adipiscing magna sed dolor elit. Praesent eleifend dignissim arcu, at eleifend sapien imperdiet ac. Aliquam erat volutpat. Praesent urna nisi, fringila lorem et vehicula lacinia quam. Integer sollicitudin mauris nec lorem luctus ultrices.</p>
<p>Nullam et orci eu lorem consequat tincidunt vivamus et sagittis libero. Mauris aliquet magna magna sed nunc rhoncus pharetra. Pellentesque condimentum sem. In efficitur ligula tate urna. Maecenas laoreet massa vel lacinia pellentesque lorem ipsum dolor. Nullam et orci eu lorem consequat tincidunt. Vivamus et sagittis libero. Mauris aliquet magna magna sed nunc rhoncus amet feugiat tempus.</p>
</article>
<!-- About -->
<article id="about">
<h2 class="major">About</h2>
<span class="image main"><img src="images/pic03.jpg" alt="" /></span>
<p>Lorem ipsum dolor sit amet, consectetur et adipiscing elit. Praesent eleifend dignissim arcu, at eleifend sapien imperdiet ac. Aliquam erat volutpat. Praesent urna nisi, fringila lorem et vehicula lacinia quam. Integer sollicitudin mauris nec lorem luctus ultrices. Aliquam libero et malesuada fames ac ante ipsum primis in faucibus. Cras viverra ligula sit amet ex mollis mattis lorem ipsum dolor sit amet.</p>
</article>
<!-- Contact -->
<article id="contact">
<h2 class="major">Contact</h2>
<form method="post" action="#">
<div class="field half first">
<label for="name">Name</label>
<input type="text" name="name" id="name" />
</div>
<div class="field half">
<label for="email">Email</label>
<input type="text" name="email" id="email" />
</div>
<div class="field">
<label for="message">Message</label>
<textarea name="message" id="message" rows="4"></textarea>
</div>
<ul class="actions">
<li><input type="submit" value="Send Message" class="special" /></li>
<li><input type="reset" value="Reset" /></li>
</ul>
</form>
<ul class="icons">
<li><a href="#" class="icon fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon fa-github"><span class="label">GitHub</span></a></li>
</ul>
</article>
<!-- Elements -->
<article id="elements">
<h2 class="major">Elements</h2>
<section>
<h3 class="major">Text</h3>
<p>This is <b>bold</b> and this is <strong>strong</strong>. This is <i>italic</i> and this is <em>emphasized</em>.
This is <sup>superscript</sup> text and this is <sub>subscript</sub> text.
This is <u>underlined</u> and this is code: <code>for (;;) { ... }</code>. Finally, <a href="#">this is a link</a>.</p>
<hr />
<h2>Heading Level 2</h2>
<h3>Heading Level 3</h3>
<h4>Heading Level 4</h4>
<h5>Heading Level 5</h5>
<h6>Heading Level 6</h6>
<hr />
<h4>Blockquote</h4>
<blockquote>Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan faucibus. Vestibulum ante ipsum primis in faucibus lorem ipsum dolor sit amet nullam adipiscing eu felis.</blockquote>
<h4>Preformatted</h4>
<pre><code>i = 0;
while (!deck.isInOrder()) {
print 'Iteration ' + i;
deck.shuffle();
i++;
}
print 'It took ' + i + ' iterations to sort the deck.';</code></pre>
</section>
<section>
<h3 class="major">Lists</h3>
<h4>Unordered</h4>
<ul>
<li>Dolor pulvinar etiam.</li>
<li>Sagittis adipiscing.</li>
<li>Felis enim feugiat.</li>
</ul>
<h4>Alternate</h4>
<ul class="alt">
<li>Dolor pulvinar etiam.</li>
<li>Sagittis adipiscing.</li>
<li>Felis enim feugiat.</li>
</ul>
<h4>Ordered</h4>
<ol>
<li>Dolor pulvinar etiam.</li>
<li>Etiam vel felis viverra.</li>
<li>Felis enim feugiat.</li>
<li>Dolor pulvinar etiam.</li>
<li>Etiam vel felis lorem.</li>
<li>Felis enim et feugiat.</li>
</ol>
<h4>Icons</h4>
<ul class="icons">
<li><a href="#" class="icon fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon fa-github"><span class="label">Github</span></a></li>
</ul>
<h4>Actions</h4>
<ul class="actions">
<li><a href="#" class="button special">Default</a></li>
<li><a href="#" class="button">Default</a></li>
</ul>
<ul class="actions vertical">
<li><a href="#" class="button special">Default</a></li>
<li><a href="#" class="button">Default</a></li>
</ul>
</section>
<section>
<h3 class="major">Table</h3>
<h4>Default</h4>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Item One</td>
<td>Ante turpis integer aliquet porttitor.</td>
<td>29.99</td>
</tr>
<tr>
<td>Item Two</td>
<td>Vis ac commodo adipiscing arcu aliquet.</td>
<td>19.99</td>
</tr>
<tr>
<td>Item Three</td>
<td> Morbi faucibus arcu accumsan lorem.</td>
<td>29.99</td>
</tr>
<tr>
<td>Item Four</td>
<td>Vitae integer tempus condimentum.</td>
<td>19.99</td>
</tr>
<tr>
<td>Item Five</td>
<td>Ante turpis integer aliquet porttitor.</td>
<td>29.99</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2"></td>
<td>100.00</td>
</tr>
</tfoot>
</table>
</div>
<h4>Alternate</h4>
<div class="table-wrapper">
<table class="alt">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Item One</td>
<td>Ante turpis integer aliquet porttitor.</td>
<td>29.99</td>
</tr>
<tr>
<td>Item Two</td>
<td>Vis ac commodo adipiscing arcu aliquet.</td>
<td>19.99</td>
</tr>
<tr>
<td>Item Three</td>
<td> Morbi faucibus arcu accumsan lorem.</td>
<td>29.99</td>
</tr>
<tr>
<td>Item Four</td>
<td>Vitae integer tempus condimentum.</td>
<td>19.99</td>
</tr>
<tr>
<td>Item Five</td>
<td>Ante turpis integer aliquet porttitor.</td>
<td>29.99</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2"></td>
<td>100.00</td>
</tr>
</tfoot>
</table>
</div>
</section>
<section>
<h3 class="major">Buttons</h3>
<ul class="actions">
<li><a href="#" class="button special">Special</a></li>
<li><a href="#" class="button">Default</a></li>
</ul>
<ul class="actions">
<li><a href="#" class="button">Default</a></li>
<li><a href="#" class="button small">Small</a></li>
</ul>
<ul class="actions">
<li><a href="#" class="button special icon fa-download">Icon</a></li>
<li><a href="#" class="button icon fa-download">Icon</a></li>
</ul>
<ul class="actions">
<li><span class="button special disabled">Disabled</span></li>
<li><span class="button disabled">Disabled</span></li>
</ul>
</section>
<section>
<h3 class="major">Form</h3>
<form method="post" action="#">
<div class="field half first">
<label for="demo-name">Name</label>
<input type="text" name="demo-name" id="demo-name" value="" placeholder="Jane Doe" />
</div>
<div class="field half">
<label for="demo-email">Email</label>
<input type="email" name="demo-email" id="demo-email" value="" placeholder="jane@untitled.tld" />
</div>
<div class="field">
<label for="demo-category">Category</label>
<div class="select-wrapper">
<select name="demo-category" id="demo-category">
<option value="">-</option>
<option value="1">Manufacturing</option>
<option value="1">Shipping</option>
<option value="1">Administration</option>
<option value="1">Human Resources</option>
</select>
</div>
</div>
<div class="field half first">
<input type="radio" id="demo-priority-low" name="demo-priority" checked>
<label for="demo-priority-low">Low</label>
</div>
<div class="field half">
<input type="radio" id="demo-priority-high" name="demo-priority">
<label for="demo-priority-high">High</label>
</div>
<div class="field half first">
<input type="checkbox" id="demo-copy" name="demo-copy">
<label for="demo-copy">Email me a copy</label>
</div>
<div class="field half">
<input type="checkbox" id="demo-human" name="demo-human" checked>
<label for="demo-human">Not a robot</label>
</div>
<div class="field">
<label for="demo-message">Message</label>
<textarea name="demo-message" id="demo-message" placeholder="Enter your message" rows="6"></textarea>
</div>
<ul class="actions">
<li><input type="submit" value="Send Message" class="special" /></li>
<li><input type="reset" value="Reset" /></li>
</ul>
</form>
</section>
</article>
</div>
<!-- Footer -->
<footer id="footer">
<p class="copyright">&copy; Untitled. Design: <a href="https://html5up.net">HTML5 UP</a>.</p>
</footer>
</div>
<!-- BG -->
<div id="bg"></div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/skel.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
<h1>Hello</h1>
<img src="pictures/ferris.jpg" alt="Ferris" style="width:200px;">
<p>Hi from Rust</p>
<a href="/test/crabe">NSFW ?</a>
<img src="pictures/modes.png" alt="Mode" style="width:200px;">
</body>
</html>

BIN
html/pictures/bondage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 MiB

BIN
html/pictures/ferris.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
html/pictures/modes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -2,10 +2,11 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>CRAB!</title>
<title>Naughty!</title>
</head>
<body>
<h1>I'm a crab</h1>
<h1>NSFW</h1>
<p>Hi from Rust</p>
<img src="../pictures/bondage.jpg" style="width:400px;">
</body>
</html>

View File

@ -1,6 +1,3 @@
extern crate file_matcher;
use file_matcher::FileNamed;
use hello::{
ThreadPool,
};
@ -9,15 +6,18 @@ use std::{
io::{prelude::*, BufReader},
net::{TcpListener, TcpStream},
collections::HashMap,
path::Path,
};
use config::Config;
//CONSTS
static ROOT_FOLDER: &str = "./html";
static CONF_FILE: &str = "websrv_conf";
fn main() {
//building config
let cfg = Config::builder()
.add_source(config::File::with_name("websrv_conf"))
.add_source(config::File::with_name(CONF_FILE))
.build()
.unwrap();
@ -39,52 +39,46 @@ fn main() {
.unwrap_or(&default_bind_addr)
.to_string();
let default_webpage = String::from("index.html");
let webpage = cfg
.get("webpage")
.unwrap_or(&default_webpage)
.to_string();
let listener = TcpListener::bind(bind_addr).unwrap();
let pool = ThreadPool::new(nbr_of_threads);
for stream in listener.incoming() {
let stream = stream.unwrap();
let webp = webpage.clone();
pool.execute(move || {
handle_connection(stream, webp);
handle_connection(stream);
});
}
println!("Shutting down.");
}
fn search_page(page: &String) -> Option<String> {
if page == "/" {
match FileNamed::regex(r"index\.htm.*").within("./html").find() {
Ok(f) => {
return Some(fs::read_to_string(f).unwrap());
},
Err(_) => return None,
};
fn search_page(page: &String) -> Option<Vec<u8>> {
println!("Looking for {page} in {ROOT_FOLDER}");
//regular page
if !page.contains('.') {
let possible_pagenames = vec![format!("{page}.html"), format!("{page}.htm")];
for p in possible_pagenames {
match fs::read(format!("{ROOT_FOLDER}/{p}")) {
Ok(c) => return Some(c),
Err(_) => (),
}
}
return None;
//css, jpg, etc
} else {
match FileNamed::regex(format!(r"{}\.htm.*", page)).within("./html").find() {
Ok(f) => {
let fpath = format!("./html/{:?}", f);
return Some(fs::read_to_string(f).unwrap());
},
match fs::read(format!("{ROOT_FOLDER}/{page}")) {
Ok(c) => return Some(c),
Err(_) => return None,
};
}
}
///Analyze the request and answer it
///Returns the complete answer
fn analyze_request_line(line: Vec<&str>) -> String {
let req = String::from(line[0]);
///Returns the complete answer, as a vector of bytes
fn analyze_request_line(line: Vec<&str>) -> Vec<u8> {
let _req = String::from(line[0]);
let mut page = String::from(line[1]);
let proto = String::from(line[2]);
let mut ret_code = "404 NOT FOUND";
@ -92,34 +86,59 @@ fn analyze_request_line(line: Vec<&str>) -> String {
//Removing the leading / from the page if need be
if &page != "/" {
page.remove(0);
} else {
page = String::from("index");
}
let content = match search_page(&page) {
let mut content = match search_page(&page) {
Some(c) => {
*&mut ret_code = "200 OK";
c
},
None => {
fs::read_to_string("./html/err_pages/404.html").unwrap_or(String::from("404 not found"))
fs::read("./html/err_pages/404.html").unwrap_or(String::from("404 NOT FOUND GET LOST").as_bytes().to_vec())
},
};
let length = content.len();
let returned_line = format!(
"{proto} {ret_code}\r\nContent-Length: {length}\r\n\r\n{content}"
);
return returned_line;
//Try to read content
match String::from_utf8(content.clone()) {
Ok(c) => {
let length = c.len();
let returned_line = format!(
"{proto} {ret_code}\r\nContent-Length: {length}\r\n\r\n{c}"
);
let returned_line = returned_line.as_bytes().to_vec();
return returned_line;
},
Err(_e) => {
println!("Got {_e} since we are sending a picture");
},
};
let img_format = if page.ends_with(".jpg") || page.ends_with(".jpeg") {
"jpg"
} else {
"png"
};
let returned_line = format!(
"{proto} {ret_code}\r\ncontent-type: image/{img_format}\r\ncontent-length: {length}\r\n\r\n"
);
let mut returned_line = returned_line.as_bytes().to_vec();
returned_line.append(&mut content);
return returned_line;
}
fn handle_connection(mut stream: TcpStream, webpage: String) {
fn handle_connection(mut stream: TcpStream) {
let buf_reader = BufReader::new(&mut stream);
//for i in buf_reader.lines() {
// println!("{:?}", i);
//}
let mut req_lines = buf_reader.lines();
let mut request = match req_lines.next() {
let request = match req_lines.next() {
Some(c) => c,
None => Ok(String::from("RIEN")),
};
@ -132,7 +151,8 @@ fn handle_connection(mut stream: TcpStream, webpage: String) {
let request_analyze: Vec<&str> = request.split_whitespace().collect();
let ret_line = analyze_request_line(request_analyze);
stream.write_all(ret_line.as_bytes()).unwrap();
let payload: &[u8] = &ret_line;
stream.write_all(payload).unwrap();
}
}

View File

@ -1,3 +1,3 @@
threads = 10
webpage = "index.html"
bind_addr = "0.0.0.0:7878"
root_folder = "/home/justine/Sandbox/Rust/websrv/html"