shttp

A small http server written in C

git clone git://git.janzachar.dev/shttp.git


0#include "super.h"
1#include <sys/stat.h>
2#include <string.h>
3#include <time.h>
4
5
6const char *MIME[][2] = {
7	{".html", "text/html"},
8	{".htm",  "text/html"},
9	{".css",  "text/css"},
10	{".js",   "application/javascript"},
11	{".json", "application/json"},
12	{".xml",  "application/xml"},
13	{".txt",  "text/plain"},
14	{".csv",  "text/csv"},
15	{".svg",  "image/svg+xml"},
16	{".png",  "image/png"},
17	{".jpg",  "image/jpeg"},
18	{".jpeg", "image/jpeg"},
19	{".gif",  "image/gif"},
20	{".webp", "image/webp"},
21	{".ico",  "image/x-icon"},
22	{".avif", "image/avif"},
23	{".mp4",  "video/mp4"},
24	{".webm", "video/webm"},
25	{".ogg",  "audio/ogg"},
26	{".mp3",  "audio/mpeg"},
27	{".wav",  "audio/wav"},
28	{".pdf",  "application/pdf"},
29	{".zip",  "application/zip"},
30	{".gz",   "application/gzip"},
31	{".tar",  "application/x-tar"},
32	{".wasm", "application/wasm"},
33	{".otf",  "font/otf"},
34	{".7z",   "application/x-7z-compressed"},
35	{NULL, NULL}
36};
37
38int endswith(const char *str, const char *with) {
39	int s = strlen(str);
40	int w = strlen(with);
41	if (s < w) return 0;
42	return !strcmp(str + s - w, with);
43}
44
45const char *guess_mime(const char *path)
46{
47	for (int i = 0; MIME[i][0] != NULL; i++) {
48		if (endswith(path, MIME[i][0]))
49			return MIME[i][1];
50	}
51	return "application/octet-stream";
52}
53const char *last_modified(const char *path)
54{
55	static char date[32];
56
57	struct stat st;
58	if (stat(path, &st))
59		return NULL;
60
61	struct tm tm;
62	gmtime_r(&st.st_mtime, &tm);
63	strftime(date, sizeof(date), TIMESTAMP_FORMAT, &tm);
64	return date;
65}
66
67int GET(int fd, struct HTTP_request *rq, FILE *fp, const char *path)
68{
69	freply(fd, 200, (struct header[]){
70		{"Last-Modified", last_modified(path)},
71		{"Content-Type", guess_mime(path)},
72		{NULL, NULL}
73	}, fp);
74	fclose(fp);
75	return 1;
76}
77
78int HEAD(int fd, struct HTTP_request *rq, FILE *fp, const char *path)
79{
80	long s = getsize(fp);
81	fclose(fp);
82	if (s == -1) {
83		reply(fd, 403, NULL);
84		return 1;
85	}
86
87	char out[16];
88	out[sprintf(out, "%ld", s)] = '\0';
89
90	reply(fd, 200, (struct header[]){
91		{"Last-Modified", last_modified(path)},
92		{"Content-Type", guess_mime(path)},
93		{"Content-Length", out},
94		{NULL, NULL}
95	});
96	return 1;
97}
98
99