shttp

A small http server written in C

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


0#include "super.h"
1
2#include <arpa/inet.h>
3#include <sys/stat.h>
4#include <unistd.h>
5#include <string.h>
6#include <stdlib.h>
7#include <ctype.h>
8#include <errno.h>
9
10
11int check_host(int fd, struct HTTP_request *rq) {
12	const char *val = header_find(&rq->headers, "Host");
13	if (val != NULL) return 0;
14
15	reply(fd, 400, NULL);
16	return 1;
17}
18
19int check_path(int fd, struct HTTP_request *rq)
20{
21	const char *ptr = rq->path;
22	int depth = 0;
23	while (*ptr) {
24		if (!strncmp(ptr, "/./", 3) || !strcmp(ptr, "/.")) {}
25		else if (!strncmp(ptr, "/../", 4) || !strcmp(ptr, "/..")) depth--;
26		else depth++;
27
28		if (depth < 0) {
29			reply(fd, 400, NULL);
30			return 1;
31		}
32
33		ptr++;
34		while (*ptr && *ptr != '/') ptr++;
35	}
36
37	return 0;
38}
39
40int __find(char buff[], int len, struct HTTP_request *rq)
41{
42	char *ptr = buff;
43	memset(buff, 0, len);
44
45	push(len, "%s/%s", ROOT_DIR, rq->path);
46
47	struct stat st;
48	if (stat(buff, &st)) {
49		if (errno == ENOENT)
50			return 404;
51		if (errno == ENAMETOOLONG)
52			return 414;
53
54		return 403;
55	}
56
57	
58	if (st.st_mode & S_IFDIR)
59		push(len, "/index.html")
60	else if ((st.st_mode & S_IFREG) == 0)
61		return 403;
62
63	if (stat(buff, &st)) {
64		if (errno == ENOENT)
65			return 404;
66		if (errno == ENAMETOOLONG)
67			return 414;
68
69		return 403;
70	}
71
72	return access(buff, R_OK) ?
73		403 : 0;
74}
75
76int find_path(int fd, struct HTTP_request *rq)
77{
78	char buff[2048];
79
80	int o = __find(buff, sizeof(buff), rq);
81	if (o) {
82		reply(fd, o, NULL);
83		return 1;
84	}
85
86	FILE *fp = fopen(buff, "r");
87	if (fp == NULL) {
88		reply(fd, 403, NULL);
89		return 1;
90	}
91
92	if (!strcmp("GET", rq->method))
93		return GET(fd, rq, fp, buff);
94
95	if (!strcmp("HEAD", rq->method))
96		return HEAD(fd, rq, fp, buff);
97
98	reply(fd, 405, NULL);
99	return 1;
100}
101
102int handle(int fd)
103{
104	char buff[64 * 1024];
105	char *ptr = buff;
106	memset(buff, 0, sizeof(buff));
107
108	struct HTTP_request rq;
109	memset(&rq, 0, sizeof(rq));
110
111	int c = recv(fd, buff, sizeof(buff)-1, 0);
112	if (c == -1) return 0;
113	buff[c] = '\0';
114
115	c = request(&rq, &ptr);
116
117	if (c) {
118		reply(fd, c, NULL);
119		return 0;
120	}
121
122	if (check_host(fd, &rq)) goto good;
123	if (check_path(fd, &rq)) goto good;
124	if (find_path(fd, &rq)) goto good;
125
126	header_free(&rq.headers);
127	return 1;
128good:
129	header_free(&rq.headers);
130	return 0;
131}
132
133