Merged server and client code into single repo
This commit is contained in:
parent
6884c6cee1
commit
2c96daefbc
11
client/index.html
Normal file
11
client/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Infinitum</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
43
client/login/login.html
Normal file
43
client/login/login.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Přihlášení | Infinitum</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://10.69.13.199:8000/" method="post">
|
||||
<div class="most_outer_form_border">
|
||||
<div class="outer_form_border">
|
||||
<div class="form_border">
|
||||
<h1>Přihlášení</h1>
|
||||
<br>
|
||||
<label for="username">Uživatelské jméno</label>
|
||||
<br>
|
||||
<input type="text" name="username" id="username" autofocus required minlength="3" maxlength="25"/>
|
||||
<br>
|
||||
<label for="password">Heslo</label>
|
||||
<br>
|
||||
<input type="password" name="password" id="password" required minlength="8" maxlength="40" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*]).{8,}$"/>
|
||||
<br>
|
||||
<button type="submit">Přihlásit se</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
const form = document.querySelector("form");
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
const passwordInput = this.querySelector("input[type=password]");
|
||||
crypto.subtle.digest("SHA-512", new TextEncoder().encode(passwordInput.value)).then(function (hashBuffer) {
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
||||
passwordInput.value = hashHex;
|
||||
form.submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
66
client/login/style.css
Normal file
66
client/login/style.css
Normal file
@ -0,0 +1,66 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,200&family=Source+Code+Pro:wght@300&display=swap');
|
||||
|
||||
body {
|
||||
background-image: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%);
|
||||
}
|
||||
|
||||
.form_border {
|
||||
border: 1px solid rgb(92, 92, 92);
|
||||
border-radius: 7px;
|
||||
background-color: rgb(160, 161, 182);
|
||||
width: 350px;
|
||||
text-align: center;
|
||||
height: 400px;
|
||||
justify-content: space-around;
|
||||
line-height: 200%;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
font-size: larger;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form_border > input {
|
||||
width: 95%;
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
outline: none;
|
||||
font-size: larger;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.form_border > input:focus {
|
||||
background-color: rgb(235, 235, 235);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.form_border > label {
|
||||
width: 97%;
|
||||
display: inline-block;
|
||||
line-height: 200%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.form_border > button {
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
font-size: larger;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
/*left: 117px;*/
|
||||
left: 0;
|
||||
background-color: rgba(255, 190, 78, 0.7);
|
||||
height: 12%;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.most_outer_form_border {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.outer_form_border {
|
||||
margin: auto;
|
||||
}
|
24
client/main/index.html
Normal file
24
client/main/index.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<title>Infinitum</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="cosiRandomCentered">
|
||||
<div class="chatHier">
|
||||
|
||||
</div>
|
||||
<div class="inputHier">
|
||||
<textarea id="textInput" autofocus name="textInput" rows="2" wrap="soft" >
|
||||
</textarea>
|
||||
<button type="button">Odeslat!</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
76
client/main/script.js
Normal file
76
client/main/script.js
Normal file
@ -0,0 +1,76 @@
|
||||
messages = [
|
||||
{
|
||||
messageid: 98568,
|
||||
timestamp: 1630000000000,
|
||||
author: {
|
||||
name: "Velecísař Empy",
|
||||
id: 1,
|
||||
},
|
||||
content: "Test message 01",
|
||||
},
|
||||
{
|
||||
messageid: 98868,
|
||||
timestamp: 1640000000000,
|
||||
author: {
|
||||
name: "Velecísař Empy 2",
|
||||
id: 2,
|
||||
},
|
||||
content: "Test message 02",
|
||||
},
|
||||
{
|
||||
messageid: 96666,
|
||||
timestamp: 1650000000000,
|
||||
author: {
|
||||
name: "Velecísař Empy",
|
||||
id: 1,
|
||||
},
|
||||
content: "Test message 03\n\n\n\n\nPokračování\ntest\na\na\n\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n\na\na\na\na\na\na\na\na\na\n\na\na\na\na\na\na\na\na\na\n\na\na\na\na\na\na\na\na\na\n",
|
||||
},
|
||||
];
|
||||
|
||||
const messagesDescending = messages.sort((a, b) => a.timestamp - b.timestamp);
|
||||
|
||||
let htmlString = "";
|
||||
|
||||
const currentUser = {
|
||||
name: "Velecísař Empy",
|
||||
id: 1,
|
||||
};
|
||||
|
||||
messagesDescending.forEach((obj) => {
|
||||
var meAuthor = obj.author.id == currentUser.id;
|
||||
var tempString = "";
|
||||
if (meAuthor) {
|
||||
tempString = '<div class="message left">';
|
||||
} else {
|
||||
tempString = '<div class="message right">';
|
||||
}
|
||||
|
||||
tempString += "<div class=\"firstLine\">"
|
||||
|
||||
// console.log(event.toLocaleString('cs-CZ', { weekday: "long", year: "numeric", month:"long", day: "numeric", era: "long", hour: "numeric", minute: "numeric", second: "numeric"}));
|
||||
const locale = "cs-CZ";
|
||||
const options = {
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
era: "long"
|
||||
};
|
||||
|
||||
|
||||
tempString += `<p class=\"author\">${ obj.author.name}</p>`;
|
||||
tempString += "<p class=\"spacer\"></p>"
|
||||
tempString += `<p class=\"time\">${ new Date(obj.timestamp).toLocaleString(locale, options)}</p>`;
|
||||
tempString += "</div>"
|
||||
//htmlString += `<p>ID: ${obj.messageid}, Timestamp: ${obj.timestamp}, Author Name: ${obj.author.name}, Author ID: ${obj.author.id}, Content: ${obj.content}</p>`;
|
||||
tempString += `<p class=\"content\">${obj.content.replaceAll("\n", "<br/>")}</p>`;
|
||||
|
||||
tempString += "</div>";
|
||||
htmlString += tempString;
|
||||
});
|
||||
|
||||
$(".chatHier").html(htmlString);
|
94
client/main/style.css
Normal file
94
client/main/style.css
Normal file
@ -0,0 +1,94 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,200&family=Source+Code+Pro:wght@300&display=swap");
|
||||
/*
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
*/
|
||||
|
||||
body,
|
||||
html {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
background-image: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%);
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cosiRandomCentered {
|
||||
height: 100vh;
|
||||
width: 60vw;
|
||||
background-color: rgba(240, 240, 240, 0.55);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.inputHier {
|
||||
margin-top: auto;
|
||||
background-color: #f0f0f0; /* Optional: Set a background color for better visibility */
|
||||
padding: 10px; /* Optional: Adjust padding as needed */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
/*grid-template-columns: 2fr 1fr;*/
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.inputHier > textarea {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
font-size: large;
|
||||
/*width: 1024px;*/
|
||||
width: 90%;
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.inputHier > button {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
font-size: larger;
|
||||
font-weight: 700;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.chatHier {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.message {
|
||||
border: #d57eeb solid 5px;
|
||||
border-radius: 20px;
|
||||
width: max-content;
|
||||
padding: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.author {
|
||||
font-size: x-small;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.firstLine {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.left {
|
||||
color: darkslategray;
|
||||
background-color: rgba(30, 215, 250, 0.8);
|
||||
margin-right: auto;
|
||||
}
|
||||
.right {
|
||||
color: darkslategray;
|
||||
background-color: rgba(250, 65, 30, 0.8);
|
||||
margin-left: auto;
|
||||
}
|
14
server/Makefile
Normal file
14
server/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
all: server
|
||||
|
||||
clean:
|
||||
rm -rf *.o
|
||||
@rm -rf server
|
||||
|
||||
server: main.o httpd.o
|
||||
gcc -o server $^ -lssl -lcrypto
|
||||
|
||||
main.o: main.c httpd.h
|
||||
gcc -c -o main.o main.c -lssl -lcrypto
|
||||
|
||||
httpd.o: httpd.c httpd.h
|
||||
gcc -c -o httpd.o httpd.c
|
231
server/httpd.c
Normal file
231
server/httpd.c
Normal file
@ -0,0 +1,231 @@
|
||||
#include "httpd.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_CONNECTIONS 1000
|
||||
#define BUF_SIZE 65535
|
||||
#define QUEUE_SIZE 1000000
|
||||
|
||||
static int listenfd;
|
||||
int *clients;
|
||||
static void start_server(const char *);
|
||||
static void respond(int);
|
||||
|
||||
static char *buf;
|
||||
|
||||
// Client request
|
||||
char *method, // "GET" or "POST"
|
||||
*uri, // "/index.html" things before '?'
|
||||
*qs, // "a=1&b=2" things after '?'
|
||||
*prot, // "HTTP/1.1"
|
||||
*payload; // for POST
|
||||
|
||||
int payload_size;
|
||||
|
||||
void serve_forever(const char *PORT) {
|
||||
struct sockaddr_in clientaddr;
|
||||
socklen_t addrlen;
|
||||
|
||||
int slot = 0;
|
||||
|
||||
printf("Server started %shttp://127.0.0.1:%s%s\n", "\033[92m", PORT,
|
||||
"\033[0m");
|
||||
|
||||
// create shared memory for client slot array
|
||||
clients = mmap(NULL, sizeof(*clients) * MAX_CONNECTIONS,
|
||||
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
||||
|
||||
// Setting all elements to -1: signifies there is no client connected
|
||||
int i;
|
||||
for (i = 0; i < MAX_CONNECTIONS; i++)
|
||||
clients[i] = -1;
|
||||
start_server(PORT);
|
||||
|
||||
// Ignore SIGCHLD to avoid zombie threads
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
// ACCEPT connections
|
||||
while (1) {
|
||||
addrlen = sizeof(clientaddr);
|
||||
clients[slot] = accept(listenfd, (struct sockaddr *)&clientaddr, &addrlen);
|
||||
|
||||
if (clients[slot] < 0) {
|
||||
perror("accept() error");
|
||||
exit(1);
|
||||
} else {
|
||||
if (fork() == 0) {
|
||||
close(listenfd);
|
||||
respond(slot);
|
||||
close(clients[slot]);
|
||||
clients[slot] = -1;
|
||||
exit(0);
|
||||
} else {
|
||||
close(clients[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
while (clients[slot] != -1)
|
||||
slot = (slot + 1) % MAX_CONNECTIONS;
|
||||
}
|
||||
}
|
||||
|
||||
// start server
|
||||
void start_server(const char *port) {
|
||||
struct addrinfo hints, *res, *p;
|
||||
|
||||
// getaddrinfo for host
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
if (getaddrinfo(NULL, port, &hints, &res) != 0) {
|
||||
perror("getaddrinfo() error");
|
||||
exit(1);
|
||||
}
|
||||
// socket and bind
|
||||
for (p = res; p != NULL; p = p->ai_next) {
|
||||
int option = 1;
|
||||
listenfd = socket(p->ai_family, p->ai_socktype, 0);
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
|
||||
if (listenfd == -1)
|
||||
continue;
|
||||
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
|
||||
break;
|
||||
}
|
||||
if (p == NULL) {
|
||||
perror("socket() or bind()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
// listen for incoming connections
|
||||
if (listen(listenfd, QUEUE_SIZE) != 0) {
|
||||
perror("listen() error");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// get request header by name
|
||||
char *request_header(const char *name) {
|
||||
header_t *h = reqhdr;
|
||||
while (h->name) {
|
||||
if (strcmp(h->name, name) == 0)
|
||||
return h->value;
|
||||
h++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get all request headers
|
||||
header_t *request_headers(void) { return reqhdr; }
|
||||
|
||||
// Handle escape characters (%xx)
|
||||
static void uri_unescape(char *uri) {
|
||||
char chr = 0;
|
||||
char *src = uri;
|
||||
char *dst = uri;
|
||||
|
||||
// Skip inital non encoded character
|
||||
while (*src && !isspace((int)(*src)) && (*src != '%'))
|
||||
src++;
|
||||
|
||||
// Replace encoded characters with corresponding code.
|
||||
dst = src;
|
||||
while (*src && !isspace((int)(*src))) {
|
||||
if (*src == '+')
|
||||
chr = ' ';
|
||||
else if ((*src == '%') && src[1] && src[2]) {
|
||||
src++;
|
||||
chr = ((*src & 0x0F) + 9 * (*src > '9')) * 16;
|
||||
src++;
|
||||
chr += ((*src & 0x0F) + 9 * (*src > '9'));
|
||||
} else
|
||||
chr = *src;
|
||||
*dst++ = chr;
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
// client connection
|
||||
void respond(int slot) {
|
||||
int rcvd;
|
||||
|
||||
buf = malloc(BUF_SIZE);
|
||||
rcvd = recv(clients[slot], buf, BUF_SIZE, 0);
|
||||
|
||||
if (rcvd < 0) // receive error
|
||||
fprintf(stderr, ("recv() error\n"));
|
||||
else if (rcvd == 0) // receive socket closed
|
||||
fprintf(stderr, "Client disconnected upexpectedly.\n");
|
||||
else // message received
|
||||
{
|
||||
buf[rcvd] = '\0';
|
||||
|
||||
method = strtok(buf, " \t\r\n");
|
||||
uri = strtok(NULL, " \t");
|
||||
prot = strtok(NULL, " \t\r\n");
|
||||
|
||||
uri_unescape(uri);
|
||||
|
||||
fprintf(stderr, "\x1b[32m + [%s] %s\x1b[0m\n", method, uri);
|
||||
|
||||
qs = strchr(uri, '?');
|
||||
|
||||
if (qs)
|
||||
*qs++ = '\0'; // split URI
|
||||
else
|
||||
qs = uri - 1; // use an empty string
|
||||
|
||||
header_t *h = reqhdr;
|
||||
char *t, *t2;
|
||||
while (h < reqhdr + 16) {
|
||||
char *key, *val;
|
||||
|
||||
key = strtok(NULL, "\r\n: \t");
|
||||
if (!key)
|
||||
break;
|
||||
|
||||
val = strtok(NULL, "\r\n");
|
||||
while (*val && *val == ' ')
|
||||
val++;
|
||||
|
||||
h->name = key;
|
||||
h->value = val;
|
||||
h++;
|
||||
fprintf(stderr, "[H] %s: %s\n", key, val);
|
||||
t = val + 1 + strlen(val);
|
||||
if (t[1] == '\r' && t[2] == '\n')
|
||||
break;
|
||||
}
|
||||
t = strtok(NULL, "\r\n");
|
||||
t2 = request_header("Content-Length"); // and the related header if there is
|
||||
payload = t;
|
||||
payload_size = t2 ? atol(t2) : (rcvd - (t - buf));
|
||||
|
||||
// bind clientfd to stdout, making it easier to write
|
||||
int clientfd = clients[slot];
|
||||
dup2(clientfd, STDOUT_FILENO);
|
||||
close(clientfd);
|
||||
|
||||
// call router
|
||||
route();
|
||||
|
||||
// tidy up
|
||||
fflush(stdout);
|
||||
shutdown(STDOUT_FILENO, SHUT_WR);
|
||||
close(STDOUT_FILENO);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
51
server/httpd.h
Normal file
51
server/httpd.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef _HTTPD_H___
|
||||
#define _HTTPD_H___
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// Client request
|
||||
extern char *method, // "GET" or "POST"
|
||||
*uri, // "/index.html" things before '?'
|
||||
*qs, // "a=1&b=2" things after '?'
|
||||
*prot, // "HTTP/1.1"
|
||||
*payload; // for POST
|
||||
|
||||
extern int payload_size;
|
||||
|
||||
// Server control functions
|
||||
void serve_forever(const char *PORT);
|
||||
|
||||
char *request_header(const char *name);
|
||||
|
||||
typedef struct {
|
||||
char *name, *value;
|
||||
} header_t;
|
||||
static header_t reqhdr[17] = {{"\0", "\0"}};
|
||||
header_t *request_headers(void);
|
||||
|
||||
// user shall implement this function
|
||||
|
||||
void route();
|
||||
|
||||
// Response
|
||||
#define RESPONSE_PROTOCOL "HTTP/1.1"
|
||||
|
||||
#define HTTP_200 printf("%s 200 OK\n\n", RESPONSE_PROTOCOL)
|
||||
#define HTTP_201 printf("%s 201 Created\n\n", RESPONSE_PROTOCOL)
|
||||
#define HTTP_404 printf("%s 404 Not found\n\n", RESPONSE_PROTOCOL)
|
||||
#define HTTP_500 printf("%s 500 Internal Server Error\n\n", RESPONSE_PROTOCOL)
|
||||
#define HTTP_301 printf("%s 301 Moved Permanently\n\n", RESPONSE_PROTOCOL)
|
||||
|
||||
// some interesting macro for `route()`
|
||||
#define ROUTE_START() if (0) {
|
||||
#define ROUTE(METHOD, URI) \
|
||||
} \
|
||||
else if (strcmp(URI, uri) == 0 && strcmp(METHOD, method) == 0) {
|
||||
#define GET(URI) ROUTE("GET", URI)
|
||||
#define POST(URI) ROUTE("POST", URI)
|
||||
#define ROUTE_END() \
|
||||
} \
|
||||
else HTTP_500;
|
||||
|
||||
#endif
|
176
server/main.c
Normal file
176
server/main.c
Normal file
@ -0,0 +1,176 @@
|
||||
#include "httpd.h"
|
||||
#include <sys/stat.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#define CHUNK_SIZE 1024 // read 1024 bytes at a time
|
||||
|
||||
// Public directory settings
|
||||
#define PUBLIC_DIR "./public"
|
||||
#define INDEX_HTML "/index.html"
|
||||
#define NOT_FOUND_HTML "/404.html"
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
char *value;
|
||||
} KeyValuePair;
|
||||
|
||||
// Function to create key-value pair
|
||||
KeyValuePair* createKeyValuePair(const char *key, const char *value) {
|
||||
KeyValuePair *pair = malloc(sizeof(KeyValuePair));
|
||||
if (pair != NULL) {
|
||||
pair->key = strdup(key);
|
||||
pair->value = strdup(value);
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
// Function to free memory occupied by a key-value pair
|
||||
void freeKeyValuePair(KeyValuePair *pair) {
|
||||
if (pair != NULL) {
|
||||
free(pair->key);
|
||||
free(pair->value);
|
||||
free(pair);
|
||||
}
|
||||
}
|
||||
|
||||
void sha512_hash_string(const char *input, char outputBuffer[129]) {
|
||||
EVP_MD_CTX *mdctx;
|
||||
const EVP_MD *md;
|
||||
unsigned char hash[EVP_MAX_MD_SIZE];
|
||||
unsigned int hashLen;
|
||||
|
||||
md = EVP_sha512();
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
|
||||
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||
EVP_DigestUpdate(mdctx, input, strlen(input));
|
||||
EVP_DigestFinal_ex(mdctx, hash, &hashLen);
|
||||
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
|
||||
for (int i = 0; i < hashLen; i++) {
|
||||
sprintf(&outputBuffer[i * 2], "%02x", hash[i]);
|
||||
}
|
||||
outputBuffer[hashLen * 2] = '\0';
|
||||
}
|
||||
|
||||
void parsePasswordPostData(const char *postData) {
|
||||
char *dataCopy = strdup(postData); // Make a copy to avoid modifying the original string
|
||||
char *token = strtok(dataCopy, "&");
|
||||
|
||||
while (token != NULL) {
|
||||
char *keyValuePair = strdup(token);
|
||||
char *key = strtok(keyValuePair, "=");
|
||||
char *value = strtok(NULL, "=");
|
||||
|
||||
if (key != NULL && value != NULL) {
|
||||
//printf("Key: %s, Value: %s\n", key, value);
|
||||
// Here, you can store or process the key and value as needed
|
||||
if(*key == 'p') {
|
||||
char localHashOutput[129];
|
||||
sha512_hash_string(value, localHashOutput);
|
||||
//printf("Hashed");
|
||||
printf("Input password is: %s\nHashed password is: %s\n", value, localHashOutput);
|
||||
}
|
||||
}
|
||||
|
||||
free(keyValuePair);
|
||||
token = strtok(NULL, "&");
|
||||
}
|
||||
|
||||
free(dataCopy);
|
||||
}
|
||||
|
||||
|
||||
int main(int c, char **v) {
|
||||
char *port = c == 1 ? "8000" : v[1];
|
||||
serve_forever(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int file_exists(const char *file_name) {
|
||||
struct stat buffer;
|
||||
int exists;
|
||||
|
||||
exists = (stat(file_name, &buffer) == 0);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
int read_file(const char *file_name) {
|
||||
char buf[CHUNK_SIZE];
|
||||
FILE *file;
|
||||
size_t nread;
|
||||
int err = 1;
|
||||
|
||||
file = fopen(file_name, "r");
|
||||
|
||||
if (file) {
|
||||
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
|
||||
fwrite(buf, 1, nread, stdout);
|
||||
|
||||
err = ferror(file);
|
||||
fclose(file);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void route() {
|
||||
ROUTE_START()
|
||||
|
||||
GET("/") {
|
||||
char index_html[20];
|
||||
sprintf(index_html, "%s%s", PUBLIC_DIR, INDEX_HTML);
|
||||
|
||||
HTTP_200;
|
||||
if (file_exists(index_html)) {
|
||||
read_file(index_html);
|
||||
} else {
|
||||
printf("Hello! You are using %s\n\n", request_header("User-Agent"));
|
||||
}
|
||||
}
|
||||
|
||||
POST("/hash") {
|
||||
HTTP_201;
|
||||
if(payload_size > 0){
|
||||
parsePasswordPostData(payload);
|
||||
}
|
||||
}
|
||||
|
||||
GET("/test") {
|
||||
HTTP_200;
|
||||
printf("List of request headers:\n\n");
|
||||
|
||||
header_t *h = request_headers();
|
||||
|
||||
while (h->name) {
|
||||
printf("%s: %s\n", h->name, h->value);
|
||||
h++;
|
||||
}
|
||||
}
|
||||
|
||||
POST("/") {
|
||||
HTTP_201;
|
||||
printf("Wow, seems that you POSTed %d bytes.\n", payload_size);
|
||||
printf("Fetch the data using `payload` variable.\n");
|
||||
if (payload_size > 0)
|
||||
printf("Request body: %s", payload);
|
||||
}
|
||||
|
||||
GET(uri) {
|
||||
char file_name[255];
|
||||
sprintf(file_name, "%s%s", PUBLIC_DIR, uri);
|
||||
|
||||
if (file_exists(file_name)) {
|
||||
HTTP_200;
|
||||
read_file(file_name);
|
||||
} else {
|
||||
HTTP_404;
|
||||
sprintf(file_name, "%s%s", PUBLIC_DIR, NOT_FOUND_HTML);
|
||||
if (file_exists(file_name))
|
||||
read_file(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
ROUTE_END()
|
||||
}
|
61
server/public/404.html
Normal file
61
server/public/404.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Page Not Found</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
* {
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
color: #888;
|
||||
display: table;
|
||||
font-family: sans-serif;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
margin: 2em auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #555;
|
||||
font-size: 2em;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 auto;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 280px) {
|
||||
|
||||
body,
|
||||
p {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
margin: 0 0 0.3em;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Page Not Found</h1>
|
||||
<p>Sorry, but the page you were trying to view does not exist.</p>
|
||||
</body>
|
||||
|
||||
</html>
|
16
server/public/index.html
Normal file
16
server/public/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Pico HTTP server</title>
|
||||
<meta name="description" content="This is a very simple HTTP server for Unix, using fork(). It's very easy to use.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hello world!</h1>
|
||||
</body>
|
||||
|
||||
</html>
|
5
server/public/robots.txt
Normal file
5
server/public/robots.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# www.robotstxt.org/
|
||||
|
||||
# Allow crawling of all content
|
||||
User-agent: *
|
||||
Disallow:
|
Reference in New Issue
Block a user