big update: simplifying + pandoc

This commit is contained in:
Michael Thomson 2024-09-13 08:22:21 -07:00
parent f16cb153e1
commit 291d55642d
24 changed files with 228 additions and 297 deletions

View File

@ -1,6 +1,6 @@
# ----- Variables for customization -----
CC = gcc # Compiler (you can change to clang if desired)
CFLAGS = -g2 -Wall -Wextra #-fsanitize=address # Standard flags + debugging & warnings
CFLAGS = -g2 -Wall -Wextra #-fsanitize=address,undefined # Standard flags + debugging & warnings
LDFLAGS = # Linker flags, if any
# ----- Automatic dependency tracking -----
@ -19,4 +19,4 @@ server: $(OBJS)
# Phony target for cleaning
.PHONY: clean
clean:
rm -f $(OBJS)
rm -f $(OBJS) server

20
content/post.md Normal file
View File

@ -0,0 +1,20 @@
---
title: Hello, World!
author: Michael
date: 2024-09-13
abstract: This is my first post
---
this is a test
- oh yeah
this is a quote:
> sdfdsfsdfdsfdsfdsfds
> sfdsfdsfsfdsfds
```c
int main()
{
return 0;
}
```

View File

@ -30,7 +30,9 @@
vcpkg
vcpkg-tool
ccls
man-pages
bear
pandoc
] ++ (if system == "aarch64-darwin" then [ ] else [ gdb ]);
};
});

View File

@ -1,9 +0,0 @@
#include "header.h"
#include <string.h>
struct Header header_constructor(char *key, char *value) {
struct Header header;
header.key = strdup(key);
header.value = strdup(value);
return header;
}

View File

@ -1,11 +0,0 @@
#ifndef HEADER_H
#define HEADER_H
struct Header {
char *key;
char *value;
};
struct Header header_constructor(char *key, char *value);
#endif // !HEADER_H

12
main.c
View File

@ -2,18 +2,8 @@
#include "server.h"
#include <stdlib.h>
char *home(struct Request request) {
return read_file("public/index.html");
}
char *clicked(struct Request request) {
return read_file("public/clicked.html");
}
int main(void) {
struct Server server = server_constructor("3000");
add_route(&server, "GET", "/", home);
add_route(&server, "POST", "/clicked", clicked);
struct Server server = server_constructor("3000", "public");
launch(&server);
return EXIT_SUCCESS;
}

BIN
public/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1 +0,0 @@
<p>see?</p>

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

10
public/index.css Normal file
View File

@ -0,0 +1,10 @@
html {
background: #0D1017;
color: #BFBDB6;
font-family: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, "Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, "Helvetica Neue", sans-serif;
}
body {
max-width: 760px;
margin: auto;
}

View File

@ -5,19 +5,11 @@
<title>Michael Thomson</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<h1>Michael Thomson</h1>
<p>Welcome to my site! doesn't it have so much content? I know, right?</p>
<p>It even has reactivity!</p>
<div>
<!-- have a button POST a click via AJAX -->
<button hx-post="/clicked" hx-swap="outerHTML">
Click Me
</button>
</div>
</body>
</html>

31
public/post.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="author" content="Michael" />
<meta name="dcterms.date" content="2024-09-13" />
<title>Hello, World!</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<h1>Michael Thomson</h1>
<nav>
<a href="blog">Blog</a>
<a href="about">About</a>
<a href="contact">Contact</a>
</nav>
<h1 class="title">Hello, World!</h1>
<p class="author">Michael</p>
<p class="date">2024-09-13</p>
</header>
<p>this is a test - oh yeah</p>
<p>this is a quote:</p>
<blockquote>
<p>sdfdsfsdfdsfdsfdsfds sfdsfdsfsfdsfds</p>
</blockquote>
<div class="sourceCode" id="cb1"><pre
class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</body>
</html>

View File

@ -1,32 +1,13 @@
#include "request.h"
#include "header.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#define MAX_HEADER_NUM 128
#include <stdlib.h>
struct Request request_constructor(char *raw_request) {
struct Request request;
request.method = strstrtok(raw_request, " ");
request.target = strstrtok(NULL, " ");
request.version = strstrtok(NULL, "\r\n");
char *raw_headers = strstrtok(NULL, "\r\n\r\n");
request.body = strstrtok(NULL, "\0");
int num_headers = 0;
struct Header headers[MAX_HEADER_NUM];
char *header_name = strstrtok(raw_headers, ": ");
if (header_name) {
char *header_value;
do {
header_value = strstrtok(NULL, "\r\n");
headers[num_headers++] = header_constructor(header_name, header_value);
} while ((header_name = strstrtok(NULL, ": ")));
}
request.num_headers = num_headers;
request.headers = headers;
request.method = (char *)malloc(12 * sizeof(char));
request.target = (char *)malloc(128 * sizeof(char));
request.version = (char *)malloc(12 * sizeof(char));
sscanf(raw_request, "%s %s %s", request.method, request.target, request.version);
// TODO: parse headers
return request;
}

View File

@ -1,15 +1,10 @@
#ifndef REQUEST_H
#define REQUEST_H
#include "header.h"
struct Request {
char *method; // GET, POST, ...
char *target; // /, /blog, /blog/post1, ...
char *version; // HTTP/1.1
char *body;
int num_headers;
struct Header *headers;
};
struct Request request_constructor(char *raw_request);

View File

@ -1,40 +1,11 @@
#include "response.h"
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER_SIZE 2048
struct Response response_constructor(char *version, char *status, char *body) {
struct Response response_constructor(char *version, char *status) {
struct Response response;
response.version = strdup(version);
response.status = strdup(status);
response.body = strdup(body);
response.num_headers = 0;
response.headers = NULL;
response.version = version;
response.status = status;
return response;
}
void add_header(struct Response *response, char *key, char *value) {
struct Header header = header_constructor(key, value);
response->headers = realloc(
response->headers, sizeof(struct Header) * (response->num_headers + 1));
response->headers[response->num_headers++] = header;
}
void response_to_string(char *buf, struct Response *response) {
char headers[MAX_BUFFER_SIZE];
headers[0] = '\0';
for (int i = 0; i < response->num_headers; i++) {
strcat(headers, response->headers[i].key);
strcat(headers, ": ");
strcat(headers, response->headers[i].value);
strcat(headers, "\r\n");
}
snprintf(buf, MAX_BUFFER_SIZE, "%s %s\r\n%s\r\n%s", response->version,
response->status, headers, response->body);
}

View File

@ -1,22 +1,11 @@
#ifndef RESPONSE_H
#define RESPONSE_H
#define OK "200 OK"
#define NOT_FOUND "404 Not Found"
#define INTERNAL_SERVER_ERROR "500 Internal Server Error"
struct Response {
char *version;
char *status;
char *body;
int num_headers;
struct Header *headers;
};
struct Response response_constructor(char *version, char *status, char *body);
void response_to_string(char *buf, struct Response *response);
void add_header(struct Response *response, char *key, char *value);
struct Response response_constructor(char *version, char *status);
#endif // !RESPONSE_H

12
route.c
View File

@ -1,12 +0,0 @@
#include <string.h>
#include "route.h"
struct Route route_constructor(char *target, char *method,
Route_Callback route_callback) {
struct Route route;
route.target = strdup(target);
route.method = strdup(method);
route.route_callback = route_callback;
return route;
}

17
route.h
View File

@ -1,17 +0,0 @@
#ifndef ROUTE_H
#define ROUTE_H
#include "request.h"
typedef char *(*Route_Callback)(struct Request request);
struct Route {
char *target;
char *method;
Route_Callback route_callback;
};
struct Route route_constructor(char *target, char *method,
Route_Callback route_callback);
#endif // !ROUTE_H

BIN
server

Binary file not shown.

217
server.c
View File

@ -10,42 +10,20 @@
#include "request.h"
#include "response.h"
#include "route.h"
#include "server.h"
#define MAX_BUFFER_SIZE 2048
#define MAX_HEADER_NUM 48
int sockfd;
struct Server server_constructor(const char *PORT) {
struct Server server_constructor(const char *port, const char *static_path) {
struct Server server;
server.PORT = PORT;
server.num_routes = 0;
server.routes = NULL;
server.port = port;
server.static_path = static_path;
return server;
}
void add_route(struct Server *server, char *method, char *target,
Route_Callback route_callback) {
struct Route route = route_constructor(target, method, route_callback);
server->routes =
realloc(server->routes, sizeof(struct Route) * (server->num_routes + 1));
server->routes[server->num_routes++] = route;
}
struct Route *match_route(struct Server *server, char *method, char *target) {
for (int i = 0; i < server->num_routes; i++) {
if (strcmp(server->routes[i].target, target) == 0 &&
strcmp(server->routes[i].method, method) == 0) {
return &server->routes[i];
}
}
return NULL;
}
void sigchld_handler(int s) {
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while (waitpid(-1, NULL, WNOHANG) > 0)
@ -54,7 +32,110 @@ void sigchld_handler(int s) {
errno = saved_errno;
}
static void start(const char *PORT) {
void path_from_target(struct Server *server, char *target, char *path) {
strcpy(path, server->static_path);
strcat(path, target);
char *question = strchr(path, '?');
if (question)
*question = '\0';
if (path[strlen(path) - 1] == '/')
strcat(path, "index.html");
char *dot = strchr(path, '.');
if (!dot)
strcat(path, ".html");
}
void get_mime_type(char *path, char *mime) {
char *dot = strchr(path, '.');
if (!dot)
strcpy(mime, "text/html");
else if (strcmp(dot, ".html") == 0)
strcpy(mime, "text/html");
else if (strcmp(dot, ".css") == 0)
strcpy(mime, "text/css");
else if (strcmp(dot, ".js") == 0)
strcpy(mime, "application/js");
else if (strcmp(dot, ".jpg") == 0)
strcpy(mime, "image/jpeg");
else if (strcmp(dot, ".png") == 0)
strcpy(mime, "image/png");
else if (strcmp(dot, ".gif") == 0)
strcpy(mime, "image/gif");
else if (strcmp(dot, ".ico") == 0)
strcpy(mime, "image/x-icon");
else
strcpy(mime, "text/html");
}
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
void handle(struct Server *server, int client_fd) {
char *buf = (char *)malloc(MAX_BUFFER_SIZE * sizeof(char));
recv(client_fd, buf, MAX_BUFFER_SIZE, 0);
struct Request request = request_constructor(buf);
char *path = (char *)malloc(1024 * sizeof(char));
path_from_target(server, request.target, path);
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
const char response[] = "HTTP/1.1 404 Not Found\r\n\r\nNot Found";
send(client_fd, response, sizeof(response), 0);
printf("[%s] %s -> %s %s\n", request.method, request.target, path, "404");
} else {
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
rewind(fp);
char mime_type[32];
get_mime_type(path, mime_type);
char res_header[1024];
sprintf(res_header, "HTTP/1.1 200 OK\r\nContent-Type: %s\r\n\r\n", mime_type);
int header_size = strlen(res_header);
char *res_buffer = (char *)malloc((file_size + header_size) * sizeof(char));
strcpy(res_buffer, res_header);
fread(res_buffer + header_size, 1, file_size, fp);
int len = file_size + header_size;
if (sendall(client_fd, res_buffer, &len) == -1) {
perror("send content");
exit(1);
}
printf("[%s] %s -> %s %s\n", request.method, request.target, path, "200");
free(res_buffer);
};
fclose(fp);
}
void launch(struct Server *server) {
struct sockaddr_storage client_addr;
socklen_t client_addr_len = sizeof client_addr;
struct addrinfo hints, *res, *p;
memset(&hints, 0, sizeof hints);
@ -63,7 +144,7 @@ static void start(const char *PORT) {
hints.ai_flags = AI_PASSIVE;
int gairv;
if ((gairv = getaddrinfo(NULL, PORT, &hints, &res)) != 0) {
if ((gairv = getaddrinfo(NULL, server->port, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gairv));
exit(1);
}
@ -108,86 +189,6 @@ static void start(const char *PORT) {
perror("sigaction");
exit(1);
}
}
char *read_file(char *filename) {
// read in file
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "read_file: error opening file: %s\n", filename);
return NULL;
}
// Calculate the content length
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
rewind(fp);
// allocate memory for file contents
char *buffer = malloc(file_size + 1);
if (buffer == NULL) {
fprintf(stderr, "read_file: memory allocation failed.\n");
fclose(fp);
return NULL;
}
// Read the file contents into buffer
size_t bytes_read = fread(buffer, 1, file_size, fp);
if (bytes_read != file_size) {
fprintf(stderr, "read_file: error reading file.\n");
free(buffer);
fclose(fp);
return NULL;
}
fclose(fp);
buffer[file_size] = '\0';
return buffer;
}
void respond(struct Server *server, int *client_fd) {
// Recieve request
char buf[MAX_BUFFER_SIZE];
recv(*client_fd, buf, MAX_BUFFER_SIZE, 0);
// Parse request
struct Request request = request_constructor(buf);
// Match route and get body content
struct Route *matched_route =
match_route(server, request.method, request.target);
struct Response response;
if (matched_route == NULL) {
response = response_constructor("HTTP/1.1", NOT_FOUND, "Not found");
} else {
char *body = matched_route->route_callback(request);
response = response_constructor("HTTP/1.1", OK, body);
}
// calculate content length
char body_length[12];
snprintf(body_length, sizeof(body_length), "%lu", strlen(response.body));
add_header(&response, "Content-Length", body_length);
printf("%s %s -> %s\n", request.method, request.target, response.status);
// send response string
char response_string[MAX_BUFFER_SIZE];
response_to_string(response_string, &response);
if (send(*client_fd, response_string, strlen(response_string), 0) == -1) {
perror("send content");
exit(1);
}
}
void launch(struct Server *server) {
struct sockaddr_storage client_addr;
socklen_t client_addr_len = sizeof client_addr;
start(server->PORT);
int client_fd;
while (1) {
@ -199,7 +200,7 @@ void launch(struct Server *server) {
if (!fork()) {
close(sockfd);
respond(server, &client_fd);
handle(server, client_fd);
close(client_fd);
exit(0);
}

View File

@ -1,21 +1,14 @@
#ifndef SERVER_H
#define SERVER_H
#include "header.h"
#include "route.h"
#define BACKLOG 128
#define BACKLOG 20
struct Server {
const char *PORT;
struct Route *routes;
int num_routes;
const char *port;
const char *static_path;
};
struct Server server_constructor(const char *PORT);
void add_route(struct Server *server, char *method, char *target,
Route_Callback route_callback);
struct Server server_constructor(const char *port, const char *static_path);
void launch(struct Server *server);

38
templates/post.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
$for(author-meta)$
<meta name="author" content="$author-meta$" />
$endfor$
$if(date-meta)$
<meta name="dcterms.date" content="$date-meta$" />
$endif$
<title>$pagetitle$</title>
$for(css)$
<link rel="stylesheet" href="$css$" />
$endfor$
</head>
<body>
<header>
<h1>Michael Thomson</h1>
<nav>
<a href="blog">Blog</a>
<a href="about">About</a>
<a href="contact">Contact</a>
</nav>
</header>
$if(title)$
<h1 class="title">$title$</h1>
$endif$
$if(subtitle)$
<p class="subtitle">$subtitle$</p>
$endif$
$for(author)$
<p class="author">$author$</p>
$endfor$
$if(date)$
<p class="date">$date$</p>
$endif$
$body$
</body>
</html>

25
utils.c
View File

@ -1,25 +0,0 @@
#include <string.h>
char *strstrtok(char *input, char *delim) {
static char *p;
if (input != NULL) {
p = input;
}
if (p == NULL) {
return p;
}
char *end = strstr(p, delim);
if (end == NULL) {
char *temp = p;
p = NULL;
return temp;
}
char *temp = p;
*end = '\0';
p = end + strlen(delim);
return temp;
}

View File

@ -1,7 +0,0 @@
#ifndef UTILS_H
#define UTILS_H
char *strstrtok(char *input, char *delim);
#endif // !UTILS_H