commit 1474650

uint  ·  2026-01-27 17:25:45 +0000 UTC
parent d97f7f0
move shared util functions to util.h/c, unify header reply with reply_hdr
5 files changed,  +175, -237
+50, -217
  1@@ -1,4 +1,3 @@
  2-#include <ctype.h>
  3 #include <errno.h>
  4 #include <fcntl.h>
  5 #include <limits.h>
  6@@ -17,16 +16,15 @@
  7 #include "json.h"
  8 #include "log.h"
  9 #include "scan.h"
 10+#include "util.h"
 11 
 12-static const char* cistrstr(const char* hay, const char* nee);
 13 static int cors_build(char* out, size_t outsz, const char* hdr, int preflight);
 14-static int get_host(char out[512], const char* hdr);
 15 static const struct item* find_item(uint64_t id);
 16-static int join_path(char* out, size_t outsz, const char* a, const char* b);
 17 static const char* mime_from_path(const char* path);
 18 static int parse_hex64(const char* s, uint64_t* out);
 19 static int parse_range(const char* hdr, size_t total, size_t* start, size_t* end);
 20 static int read_request(int c, char* method, size_t msz, char* path, size_t psz, char* hdr, size_t hsz);
 21+static void reply_hdr(int c, const char* hdr, const char* status, const char* ctype, size_t len, int preflight);
 22 static void reply_json(int c, const char* hdr, const char* status, const char* body, size_t len, int send_body);
 23 static void reply_m3u(int c, const char* hdr, const char* status, size_t len);
 24 static void reply_preflight(int c, const char* hdr);
 25@@ -34,40 +32,9 @@ static void reply_text(int c, const char* hdr, const char* status, const char* b
 26 static int queue_write(int c, const char* hdr, int head_only);
 27 static int stat_item(const struct item* it, struct stat* st);
 28 static int stream_file(int c, const struct item* it, const char* hdr, int head_only);
 29-static int write_all(int fd, const void* buf, size_t n);
 30-
 31 
 32 extern struct library lib;
 33 
 34-static const char* cistrstr(const char* hay, const char* nee)
 35-{
 36-	size_t nl = strlen(nee);
 37-	if (nl == 0)
 38-		return hay;
 39-
 40-	for (; *hay; hay++) {
 41-		size_t i = 0;
 42-
 43-		for (;;) {
 44-			if (i == nl)
 45-				return hay;
 46-
 47-			unsigned char a = (unsigned char)hay[i];
 48-			unsigned char b = (unsigned char)nee[i];
 49-
 50-			if (a == '\0')
 51-				break;
 52-
 53-			if (tolower(a) != tolower(b))
 54-				break;
 55-
 56-			i++;
 57-		}
 58-	}
 59-
 60-	return NULL;
 61-}
 62-
 63 static int cors_origin_allowed(const char* origin)
 64 {
 65 	if (cors_origin[0] == '\0')
 66@@ -101,38 +68,6 @@ static int cors_origin_allowed(const char* origin)
 67 	return 0;
 68 }
 69 
 70-static int cors_get_origin(char out[512], const char* hdr)
 71-{
 72-	const char* p = cistrstr(hdr, "\norigin:");
 73-	if (!p)
 74-		p = cistrstr(hdr, "\rorigin:");
 75-	if (!p)
 76-		p = cistrstr(hdr, "origin:");
 77-	if (!p)
 78-		return -1;
 79-
 80-	p = strchr(p, ':');
 81-	if (!p)
 82-		return -1;
 83-	p++;
 84-
 85-	while (*p == ' ' || *p == '\t')
 86-		p++;
 87-
 88-	size_t n = 0;
 89-	while (*p && *p != '\r' && *p != '\n') {
 90-		if (n + 1 >= 512)
 91-			return -1;
 92-		out[n++] = *p++;
 93-	}
 94-	out[n] = '\0';
 95-
 96-	if (n == 0)
 97-		return -1;
 98-
 99-	return 0;
100-}
101-
102 static int cors_build(char* out, size_t outsz, const char* hdr, int preflight)
103 {
104 	char origin[512];
105@@ -145,7 +80,7 @@ static int cors_build(char* out, size_t outsz, const char* hdr, int preflight)
106 	if (cors_origin[0] == '\0')
107 		return 0;
108 
109-	if (cors_get_origin(origin, hdr) < 0)
110+	if (hdr_get_value(origin, hdr, "origin") < 0)
111 		return 0;
112 
113 	if (!cors_origin_allowed(origin))
114@@ -183,38 +118,6 @@ static int cors_build(char* out, size_t outsz, const char* hdr, int preflight)
115 	return 1;
116 }
117 
118-static int get_host(char out[512], const char* hdr)
119-{
120-	const char* p = cistrstr(hdr, "\nhost:");
121-	if (!p)
122-		p = cistrstr(hdr, "\rhost:");
123-	if (!p)
124-		p = cistrstr(hdr, "host:");
125-	if (!p)
126-		return -1;
127-
128-	p = strchr(p, ':');
129-	if (!p)
130-		return -1;
131-	p++;
132-
133-	while (*p == ' ' || *p == '\t')
134-		p++;
135-
136-	size_t n = 0;
137-	while (*p && *p != '\r' && *p != '\n') {
138-		if (n + 1 >= 512)
139-			return -1;
140-		out[n++] = *p++;
141-	}
142-	out[n] = '\0';
143-
144-	if (n == 0)
145-		return -1;
146-
147-	return 0;
148-}
149-
150 static const struct item* find_item(uint64_t id)
151 {
152 	for (size_t i = 0; i < lib.len; i++)
153@@ -224,18 +127,6 @@ static const struct item* find_item(uint64_t id)
154 	return NULL;
155 }
156 
157-static int join_path(char* out, size_t outsz, const char* a, const char* b)
158-{
159-	int n = snprintf(out, outsz, "%s/%s", a, b);
160-	if (n < 0)
161-		return -1;
162-
163-	if ((size_t)n >= outsz)
164-		return -1;
165-
166-	return 0;
167-}
168-
169 static const char* mime_from_path(const char* path)
170 {
171 	const char* dot = strrchr(path, '.');
172@@ -432,24 +323,47 @@ static int read_request(int c, char* method, size_t msz, char* path, size_t psz,
173 	return 0;
174 }
175 
176-static void reply_json(int c, const char* hdr, const char* status, const char* body, size_t len, int send_body)
177+static void reply_hdr(int c, const char* hdr, const char* status, const char* ctype, size_t len, int preflight)
178 {
179 	char resp[HTTP_RESP_MAX];
180 	char cors[512];
181 
182-	(void)cors_build(cors, sizeof(cors), hdr, 0);
183-	int n = snprintf(
184-		resp, sizeof(resp),
185+	(void)cors_build(cors, sizeof(cors), hdr, preflight);
186+
187+	int n;
188+
189+	if (ctype && ctype[0]) {
190+		n = snprintf(
191+			resp, sizeof(resp),
192+
193+			"%s"
194+			"%s"
195+			"%s"
196+			HTTP_LENGTH
197+			HTTP_CLOSE
198+			"\r\n",
199+
200+			status,
201+			cors,
202+			ctype,
203+			len
204+		);
205+	}
206+	else {
207+		n = snprintf(
208+			resp, sizeof(resp),
209 
210-		"%s"
211-		"%s"
212-		HTTP_JSON
213-		HTTP_LENGTH
214-		HTTP_CLOSE
215-		"\r\n",
216+			"%s"
217+			"%s"
218+			HTTP_LENGTH
219+			HTTP_CLOSE
220+			"\r\n",
221 
222-		status, cors, len
223-	);
224+			status,
225+			cors,
226+			len
227+		);
228+	}
229 
230 	if (n < 0)
231 		return;
232@@ -458,6 +372,12 @@ static void reply_json(int c, const char* hdr, const char* status, const char* b
233 		n = (int)(sizeof(resp) - 1);
234 
235 	(void)write_all(c, resp, (size_t)n);
236+}
237+
238+
239+static void reply_json(int c, const char* hdr, const char* status, const char* body, size_t len, int send_body)
240+{
241+	reply_hdr(c, hdr, status, HTTP_JSON, len, 0);
242 
243 	if (send_body)
244 		(void)write_all(c, body, len);
245@@ -466,88 +386,20 @@ static void reply_json(int c, const char* hdr, const char* status, const char* b
246 
247 static void reply_m3u(int c, const char* hdr, const char* status, size_t len)
248 {
249-	char resp[HTTP_RESP_MAX];
250-	char cors[512];
251-
252-	(void)cors_build(cors, sizeof(cors), hdr, 0);
253-	int n = snprintf(
254-		resp, sizeof(resp),
255-
256-		"%s"
257-		"%s"
258-		HTTP_M3U
259-		HTTP_LENGTH
260-		HTTP_CLOSE
261-		"\r\n",
262-
263-		status, cors, len
264-	);
265-
266-	if (n < 0)
267-		return;
268-
269-	if ((size_t)n >= sizeof(resp))
270-		n = (int)(sizeof(resp) - 1);
271-
272-	(void)write_all(c, resp, (size_t)n);
273+	reply_hdr(c, hdr, status, HTTP_M3U, len, 0);
274 }
275 
276 static void reply_preflight(int c, const char* hdr)
277 {
278-	char resp[HTTP_RESP_MAX];
279-	char cors[512];
280-
281-	(void)cors_build(cors, sizeof(cors), hdr, 1);
282-
283-	int n = snprintf(
284-		resp, sizeof(resp),
285-		"%s"
286-		"%s"
287-		HTTP_LENGTH
288-		HTTP_CLOSE
289-		"\r\n",
290-		HTTP_204,
291-		cors,
292-		(size_t)0
293-	);
294-
295-	if (n < 0)
296-		return;
297-	if ((size_t)n >= sizeof(resp))
298-		n = (int)(sizeof(resp) - 1);
299-
300-	(void)write_all(c, resp, (size_t)n);
301+	reply_hdr(c, hdr, HTTP_204, NULL, (size_t)0, 1);
302 }
303 
304 static void reply_text(int c, const char* hdr, const char* status, const char* body)
305 {
306-	char resp[HTTP_RESP_MAX];
307-	char cors[512];
308+	size_t len = strlen(body);
309 
310-	(void)cors_build(cors, sizeof(cors), hdr, 0);
311-	int n = snprintf(
312-		resp, sizeof(resp),
313-
314-		"%s"
315-		"%s"
316-		HTTP_TEXT
317-		HTTP_LENGTH
318-		HTTP_CLOSE
319-		"\r\n"
320-		"%s",
321-
322-		status,
323-		cors,
324-		strlen(body), body
325-	);
326-
327-	if (n < 0)
328-		return;
329-
330-	if ((size_t)n >= sizeof(resp))
331-		n = (int)(sizeof(resp) - 1);
332-
333-	(void)write_all(c, resp, (size_t)n);
334+	reply_hdr(c, hdr, status, HTTP_TEXT, len, 0);
335+	(void)write_all(c, body, len);
336 }
337 
338 static int queue_write(int c, const char* hdr, int head_only)
339@@ -555,7 +407,7 @@ static int queue_write(int c, const char* hdr, int head_only)
340 	char host[512];
341 	char base[768];
342 
343-	if (get_host(host, hdr) == 0) {
344+	if (hdr_get_value(host, hdr, "host") == 0) {
345 		if (snprintf(base, sizeof(base), "http://%s", host) >= (int)sizeof(base))
346 			return -1;
347 	}
348@@ -785,25 +637,6 @@ static int stream_file(int c, const struct item* it, const char* hdr, int head_o
349 	return 0;
350 }
351 
352-static int write_all(int fd, const void* buf, size_t n)
353-{
354-	const char* p = buf;
355-
356-	while (n > 0) {
357-		ssize_t w = write(fd, p, n);
358-		if (w < 0) {
359-			if (errno == EINTR)
360-				continue;
361-			return -1;
362-		}
363-
364-		p += (size_t)w;
365-		n -= (size_t)w;
366-	}
367-
368-	return 0;
369-}
370-
371 int http_handle(int c)
372 {
373 	char method[16];
+12, -0
 1@@ -0,0 +1,12 @@
 2+#ifndef UTIL_H
 3+#define UTIL_H
 4+
 5+#include <stddef.h>
 6+
 7+const char* cistrstr(const char* hay, const char* nee);
 8+int hdr_get_value(char out[512], const char* hdr, const char* key);
 9+int join_path(char* out, size_t outsz, const char* a, const char* b);
10+int write_all(int fd, const void* buf, size_t n);
11+
12+#endif /* UTIL_H */
13+
+0, -1
1@@ -28,7 +28,6 @@
2 void die(const char* s, int e);
3 void run(void);
4 void setup(void);
5-int write_all(int fd, const void* buf, size_t n);
6 
7 int sock;
8 struct library lib;
+1, -19
 1@@ -11,9 +11,9 @@
 2 #include "config.h"
 3 #include "scan.h"
 4 #include "log.h"
 5+#include "util.h"
 6 
 7 static uint64_t encode_fnv1a64(const char* s);
 8-static int join_path(char* out, size_t outsz, const char* a, const char* b);
 9 static int library_push(struct library* l, const char* rel);
10 static int scan_dir(struct library* l, const char* root, const char* rel);
11 
12@@ -30,24 +30,6 @@ static uint64_t encode_fnv1a64(const char* s)
13 	return h;
14 }
15 
16-static int join_path(char* out, size_t outsz, const char* a, const char* b)
17-{
18-	size_t al = strlen(a);
19-	size_t bl = strlen(b);
20-
21-	if (al + 1 + bl + 1 > outsz) {
22-		LOG(verbose_log, "SCAN", "path too long");
23-		return -1;
24-	}
25-
26-	memcpy(out, a, al);
27-	out[al] = '/';
28-	memcpy(out + al + 1, b, bl);
29-	out[al + 1 + bl] = '\0';
30-
31-	return 0;
32-}
33-
34 static int library_push(struct library* l, const char* rel)
35 {
36 	if (l->len == l->cap) {
+112, -0
  1@@ -0,0 +1,112 @@
  2+#include <ctype.h>
  3+#include <errno.h>
  4+#include <stdio.h>
  5+#include <string.h>
  6+#include <unistd.h>
  7+
  8+#include "util.h"
  9+
 10+const char* cistrstr(const char* hay, const char* nee)
 11+{
 12+	size_t nl = strlen(nee);
 13+	if (nl == 0)
 14+		return hay;
 15+
 16+	for (; *hay; hay++) {
 17+		size_t i = 0;
 18+
 19+		for (;;) {
 20+			if (i == nl)
 21+				return hay;
 22+
 23+			unsigned char a = (unsigned char)hay[i];
 24+			unsigned char b = (unsigned char)nee[i];
 25+
 26+			if (a == '\0')
 27+				break;
 28+
 29+			if (tolower(a) != tolower(b))
 30+				break;
 31+
 32+			i++;
 33+		}
 34+	}
 35+
 36+	return NULL;
 37+}
 38+
 39+int hdr_get_value(char out[512], const char* hdr, const char* key)
 40+{
 41+	char pat1[64];
 42+	char pat2[64];
 43+	char pat3[64];
 44+
 45+	/* build patterns like "\nXXXX:" "\rXXXX:" "XXXX:" */
 46+	if (snprintf(pat1, sizeof(pat1), "\n%s:", key) >= (int)sizeof(pat1))
 47+		return -1;
 48+	if (snprintf(pat2, sizeof(pat2), "\r%s:", key) >= (int)sizeof(pat2))
 49+		return -1;
 50+	if (snprintf(pat3, sizeof(pat3), "%s:", key) >= (int)sizeof(pat3))
 51+		return -1;
 52+
 53+	const char* p = cistrstr(hdr, pat1);
 54+	if (!p)
 55+		p = cistrstr(hdr, pat2);
 56+	if (!p)
 57+		p = cistrstr(hdr, pat3);
 58+	if (!p)
 59+		return -1;
 60+
 61+	p = strchr(p, ':');
 62+	if (!p)
 63+		return -1;
 64+	p++;
 65+
 66+	while (*p == ' ' || *p == '\t')
 67+		p++;
 68+
 69+	size_t n = 0;
 70+	while (*p && *p != '\r' && *p != '\n') {
 71+		if (n + 1 >= 512)
 72+			return -1;
 73+		out[n++] = *p++;
 74+	}
 75+	out[n] = '\0';
 76+
 77+	if (n == 0)
 78+		return -1;
 79+
 80+	return 0;
 81+}
 82+
 83+int join_path(char* out, size_t outsz, const char* a, const char* b)
 84+{
 85+	int n = snprintf(out, outsz, "%s/%s", a, b);
 86+	if (n < 0)
 87+		return -1;
 88+
 89+	if ((size_t)n >= outsz)
 90+		return -1;
 91+
 92+	return 0;
 93+}
 94+
 95+int write_all(int fd, const void* buf, size_t n)
 96+{
 97+	const char* p = buf;
 98+
 99+	while (n > 0) {
100+		ssize_t w = write(fd, p, n);
101+		if (w < 0) {
102+			if (errno == EINTR)
103+				continue;
104+			return -1;
105+		}
106+
107+		p += (size_t)w;
108+		n -= (size_t)w;
109+	}
110+
111+	return 0;
112+}
113+