💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Upload › files › 7eac294ae1907c41c45754a8a6a… captured on 2023-03-20 at 18:34:12. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /* See LICENSE for license details. */
1 #ifdef __FreeBSD__
2 #define __BSD_VISIBLE 1
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <sys/uio.h>
6 #endif
7 #include "server.h"
8 #include "parser.h"
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <sys/types.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <poll.h>
19 #ifdef __sun
20 #include <signal.h>
21 #endif
22 #define _GNU_SOURCE
23 size_t strlcpy(char*, const char*, size_t);
24
25 char header[] =
26 "HTTP/1.0 200 OK\r\n"
27 "Connection: close\r\n"
28 "Content-Length: %d\r\n"
29 "Content-Type: %s\r\n"
30 "Server: uploadservice\r\n\r\n";
31
32 void
33 print_now()
34 {
35 time_t now = time(NULL);
36 struct tm tm = *localtime(&now);
37 printf("[%d/%02d/%02d %02d:%02d:%02d] ",
38 tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday,
39 tm.tm_hour, tm.tm_min, tm.tm_sec);
40 }
41
42 int listener = 0;
43
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47
48 char data_error[] =
49 "<html>\n"
50 "<head>\n"
51 " <title>Fatal error</title>\n"
52 "</head>\n"
53 "<body>\n"
54 " <h1>An error occured</h1>\n"
55 "</body>\n"
56 "</html>\n";
57
58 char data_upload[] =
59 "<html>\n"
60 "<head>\n"
61 " <title>File uploaded</title>\n"
62 "</head>\n"
63 "<body>\n"
64 " <a href=\"/\">Go back</a>\n"
65 " <h1>File succesfully uploaded</h1>\n"
66 " <p>Download link : <a href=\"%s\">%s</a></p>\n"
67 "</body>\n"
68 "</html>\n";
69
70 int
71 path_to_url(const char* path, char* url, int len)
72 {
73 int j = 0;
74 int i = 0;
75 for (; path[i] && j < len; i++) {
76 char c = path[i];
77 if ((c >= 'a' && c <= 'z') ||
78 (c >= 'A' && c <= 'Z') ||
79 (c >= '0' && c <= '9') ||
80 c == '.' || c == '/' || c == '_') {
81 url[j] = path[i];
82 j++;
83 continue;
84 }
85 snprintf(&url[j], len - j, "%%%02X", c);
86 j += 3;
87 }
88 url[j] = '\0';
89 return j;
90 }
91
92 int
93 server_upload(struct http_request* req)
94 {
95 char file_name[256], path[1024], url[2048];
96 char *start, *name_ptr, *slash_ptr;
97 int name_fail, fd, len;
98
99 /* path + name */
100 start = strstr(req->packet, "\r\n\r\n");
101 if (!start) start = req->packet;
102 name_ptr = strstr(start, "filename=\"");
103 name_fail = 1;
104 if (name_ptr) {
105 char* name_end;
106
107 name_ptr += sizeof("filename=\"") - 1;
108 name_end = strstr(name_ptr, "\"\r\n");
109 if (name_end && (size_t)(name_end - name_ptr) <
110 sizeof(file_name)) {
111 strlcpy(file_name, name_ptr, name_end - name_ptr + 1);
112 name_fail = 0;
113 }
114 }
115 if (name_fail)
116 strlcpy(file_name, "generic.dat", sizeof(file_name));
117 snprintf(path, sizeof(path), "/download/%08X%08X/%s",
118 (unsigned)(rand() * rand() + rand()),
119 (unsigned)(rand() * rand() - rand()), file_name);
120
121 start = strstr(start+4, "\r\n\r\n");
122 if (!start) start = req->content;
123 slash_ptr = strrchr(path, '/');
124 if (!slash_ptr) return -1;
125 *slash_ptr = '\0';
126 mkdir(&path[1], 0700);
127 *slash_ptr = '/';
128 fd = open((char*)&path[1], O_RDWR|O_CREAT, 0600);
129 if (fd < 0)
130 return -1;
131 req->data = fd;
132 path_to_url(path, url, sizeof(url));
133 len = snprintf(req->updata, sizeof(req->updata),
134 data_upload, url, file_name);
135 snprintf(req->header, sizeof(req->header), header, len, "text/html");
136 http_parse(req);
137 return 0;
138 }
139
140 int
141 server_init(int port)
142 {
143 #ifdef DEBUG
144 struct linger sl;
145 #endif
146 struct sockaddr_in addr;
147 listener = socket(AF_INET, SOCK_STREAM, 0);
148 if (listener == -1) {
149 printf("Failed to create socket\n");
150 return -1;
151 }
152 #ifdef DEBUG
153 /* instant reset, useful for testing */
154 sl.l_onoff = 1;
155 sl.l_linger = 0;
156 setsockopt(listener, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
157 #endif
158 #ifdef __sun
159 signal(SIGPIPE, SIG_IGN);
160 #endif
161
162 memset(&addr, 0, sizeof(addr));
163 addr.sin_family = AF_INET;
164 addr.sin_addr.s_addr = htonl(INADDR_ANY);
165 addr.sin_port = htons(port);
166 if (bind(listener, (struct sockaddr*)&addr, sizeof(addr))) {
167 printf("Failed to bind socket on port %d\n", port);
168 return -1;
169 }
170 if (listen(listener, 5)) {
171 printf("Failed to listen on port %d\n", port);
172 return -1;
173 }
174 print_now();
175 printf("Listening on port %d\n", port);
176 fflush(stdout); /* to print log in sfm on illumos */
177 return 0;
178 }
179
180 int
181 server_accept(struct http_request* req)
182 {
183 unsigned int len;
184 int socket;
185
186 memset(req, 0, sizeof(struct http_request));
187 req->data = -1;
188 len = sizeof(req->addr);
189 socket = accept(listener, (struct sockaddr*)&req->addr, &len);
190 if (socket == -1) {
191 printf("Failed to accept socket\n");
192 return -1;
193 }
194 req->socket = socket;
195 return 0;
196 }
197
198 int
199 server_recv(struct http_request* req)
200 {
201 char *data_ptr, *end;
202 int bytes, blen;
203
204 bytes = recv(req->socket,
205 (req->data > -1) ? req->packet : &req->packet[req->size],
206 (req->data > -1) ? sizeof(req->packet):
207 (sizeof(req->packet) - req->size), 0);
208 if (bytes <= 0) return -1;
209 if (!req->boundary_found) {
210 char* ptr = strstr(&req->packet[req->size], "boundary=");
211 if (ptr) {
212 char* start = ptr + sizeof("boundary=");
213 ptr = start;
214 while (ptr++ && *ptr != '\r');
215 strlcpy(req->boundary, start, ptr - start);
216 req->boundary_found = 1;
217 }
218 }
219 req->size += bytes;
220 data_ptr = req->packet;
221 end = NULL;
222 blen = 0;
223 if (req->boundary_found)
224 blen = strnlen(req->boundary, sizeof(req->boundary));
225 while (req->data < 0 && req->boundary_found) {
226 char* ptr = strstr(req->packet, req->boundary);
227 if (!ptr) break;
228 ptr = strstr(ptr + blen, req->boundary);
229 if (!ptr) break;
230 req->content = ptr + strnlen(req->boundary,
231 sizeof(req->boundary));
232 req->length = req->size - (req->content - req->packet);
233 server_upload(req);
234 end = strstr(req->packet + req->size - blen - 8,
235 req->boundary);
236 data_ptr = strstr(req->content + 4, "\r\n\r\n") + 4;
237 bytes = req->size - (data_ptr - req->packet);
238 break;
239 }
240 if (req->data > -1) {
241 char packet[4096];
242 size_t size;
243 if (!end && data_ptr == req->packet)
244 end = strstr(data_ptr + bytes - blen - 8,
245 req->boundary);
246 write(req->data, data_ptr,
247 end?(end - data_ptr - 4):bytes);
248 if (!end) return 1;
249 size = snprintf(packet, sizeof(packet), "%s%s",
250 req->header, req->updata);
251 bytes = 0;
252 while ((size_t)bytes < size) {
253 int ret = send(req->socket, &packet[bytes],
254 size - bytes, 0);
255 if (ret <= 0) break;
256 bytes += ret;
257 }
258 return 2;
259 }
260 if (!req->boundary_found &&
261 req->packet[req->size - 1] == '\n' &&
262 req->packet[req->size - 2] == '\r' &&
263 req->packet[req->size - 3] == '\n' &&
264 req->packet[req->size - 4] == '\r') {
265 return 0;
266 }
267 return 1;
268 }
269
270 #define MAX_REQUESTS 1024
271 #define TIMEOUT_SINCE_STARTED 1200000
272 #define TIMEOUT_SINCE_LAST 10000
273 struct http_request requests[MAX_REQUESTS];
274 struct pollfd fds[MAX_REQUESTS];
275 size_t requests_count = 0;
276
277 int
278 new_request()
279 {
280 int new = 1;
281 size_t i = 0;
282 time_t now = time(NULL);
283 for (; i < requests_count; i++) {
284 if (requests[i].done ||
285 now - requests[i].started >= TIMEOUT_SINCE_STARTED ||
286 now - requests[i].last >= TIMEOUT_SINCE_LAST) {
287 new = 0;
288 break;
289 }
290 }
291 if (new && i >= sizeof(requests)/sizeof(struct http_request) - 1)
292 return -1;
293 if (server_accept(&requests[i]))
294 return -1;
295 fds[i + 1].fd = requests[i].socket;
296 fds[i + 1].events = POLLIN;
297 requests[i].last = requests[i].started = time(NULL);
298 if (new)
299 requests_count++;
300 return 0;
301 }
302
303 void
304 print_req(struct http_request* req, int code)
305 {
306 uint8_t *ptr;
307 print_now();
308 ptr = (uint8_t*)&req->addr.sin_addr.s_addr;
309 printf("%d.%d.%d.%d, requested [%d]\n",
310 ptr[0], ptr[1], ptr[2], ptr[3], code);
311 fflush(stdout); /* to print log in sfm on illumos */
312 }
313
314 int
315 server_serve(struct http_request* req)
316 {
317 char packet[4096];
318 size_t l;
319
320 memset(packet, 0, sizeof(packet));
321 l = snprintf(packet, sizeof(packet),
322 header, sizeof(data_error) - 1, "text/html");
323 if (l >= sizeof(packet)) {
324 printf("packet buffer overflowing");
325 return -1;
326 }
327 l += strlcpy(&packet[l], data_error, sizeof(packet) - l);
328 send(req->socket, packet, l + 1, 0);
329 return 404;
330 }
331
332 int
333 server_thread()
334 {
335 size_t i;
336 memset(requests, 0, sizeof(requests));
337 for (i = 1; i < sizeof(fds)/sizeof(struct pollfd); i++) {
338 fds[i].fd = -1;
339 fds[i].events = POLLIN;
340 }
341 fds[0].fd = listener;
342 fds[0].events = POLLIN;
343 while (1) {
344 int nfds, ready;
345 size_t i;
346
347 nfds = requests_count + 1;
348 ready = poll(fds, nfds, -1);
349 if (ready == -1) break;
350 if (fds[0].revents == POLLIN && new_request()) {
351 print_now();
352 printf("Failed to accept client\n");
353 fflush(stdout);
354 }
355 for (i = 0; i < requests_count; i++) {
356 int ret = 0;
357 struct http_request* req = &requests[i];
358 switch (fds[i + 1].revents) {
359 case 0:
360 break;
361 case POLLOUT:
362 goto clean;
363 case POLLIN:
364 requests[i].last = time(NULL);
365 ret = server_recv(req);
366 if (ret == 1) continue;
367 if (ret == 2) print_req(req, 200);
368 if (ret == 0) {
369 if (req->data > -1) {
370 close(req->data);
371 req->data = -1;
372 }
373 http_parse(req);
374 print_req(req, server_serve(req));
375 if (req->data > -1) {
376 fds[i + 1].events = POLLOUT;
377 break;
378 }
379 }
380 clean:
381 if (req->data > -1) {
382 close(req->data);
383 req->data = -1;
384 }
385
386 close(req->socket);
387 req->socket = -1;
388 req->done = 1;
389 if (i + 1 == requests_count)
390 requests_count--;
391 memset(&fds[i + 1], 0, sizeof(struct pollfd));
392 fds[i + 1].fd = -1;
393 fds[i + 1].events = POLLIN;
394 break;
395 default:
396 fds[i + 1].fd = -1;
397 fds[i + 1].events = POLLIN;
398 }
399 }
400 }
401 return 0;
402 }
403
404 int
405 server_stop()
406 {
407 close(listener);
408 return 0;
409 }
410