|
|
ind.c - geomyidae - A small C-based gopherd. |
|
|
 |
git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/geomyidae/ (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
ind.c (12847B) |
|
|
|
--- |
|
|
|
1 /* |
|
|
|
2 * Copy me if you can. |
|
|
|
3 * by 20h |
|
|
|
4 */ |
|
|
|
5 |
|
|
|
6 #ifdef __linux__ |
|
|
|
7 #define _GNU_SOURCE |
|
|
|
8 #endif |
|
|
|
9 |
|
|
|
10 #include <libgen.h> |
|
|
|
11 #include <unistd.h> |
|
|
|
12 #include <stdarg.h> |
|
|
|
13 #include <string.h> |
|
|
|
14 #include <memory.h> |
|
|
|
15 #include <fcntl.h> |
|
|
|
16 #include <stdio.h> |
|
|
|
17 #include <stdlib.h> |
|
|
|
18 #include <stdint.h> |
|
|
|
19 #include <time.h> |
|
|
|
20 #include <netdb.h> |
|
|
|
21 #include <sys/socket.h> |
|
|
|
22 #include <sys/stat.h> |
|
|
|
23 #include <netinet/in.h> |
|
|
|
24 #include <netinet/tcp.h> |
|
|
|
25 #include <arpa/inet.h> |
|
|
|
26 #include <sys/ioctl.h> |
|
|
|
27 #include <limits.h> |
|
|
|
28 #include <errno.h> |
|
|
|
29 |
|
|
|
30 #define PAGE_SHIFT 12 |
|
|
|
31 #define PAGE_SIZE (1UL << PAGE_SHIFT) |
|
|
|
32 #define BLOCK_SIZE ((PAGE_SIZE * 16) - 1) |
|
|
|
33 |
|
|
|
34 #include "arg.h" |
|
|
|
35 #include "ind.h" |
|
|
|
36 #include "handlr.h" |
|
|
|
37 |
|
|
|
38 /* |
|
|
|
39 * Be careful, to look at handlerequest(), in case you add any executing |
|
|
|
40 * handler, so nocgi will be valuable. |
|
|
|
41 * |
|
|
|
42 * All files are handled as binary, without a following ".\r\n". Proper |
|
|
|
43 * encoding lines with beginning "." would be a really slow function, not |
|
|
|
44 * adding any feature to gopher. Clients can check for the types |
|
|
|
45 * requested and assume ".\r\n" or leave it out. |
|
|
|
46 * |
|
|
|
47 * Geomyidae only adds ".\r\n" in all kind of menus, like dir listings |
|
|
|
48 * or dcgi files. There the case of some maybe future "." item type needs |
|
|
|
49 * to be handled, if really used. |
|
|
|
50 */ |
|
|
|
51 |
|
|
|
52 #include "filetypes.h" |
|
|
|
53 |
|
|
|
54 int |
|
|
|
55 pendingbytes(int sock) |
|
|
|
56 { |
|
|
|
57 int pending, rval; |
|
|
|
58 |
|
|
|
59 pending = 0; |
|
|
|
60 rval = 0; |
|
|
|
61 #if defined(TIOCOUTQ) && !defined(__OpenBSD__) |
|
|
|
62 rval = ioctl(sock, TIOCOUTQ, &pending); |
|
|
|
63 #else |
|
|
|
64 #ifdef SIOCOUTQ |
|
|
|
65 rval = ioctl(sock, SIOCOUTQ, &pending); |
|
|
|
66 #endif |
|
|
|
67 #endif |
|
|
|
68 |
|
|
|
69 if (rval != 0) |
|
|
|
70 return 0; |
|
|
|
71 |
|
|
|
72 return pending; |
|
|
|
73 } |
|
|
|
74 |
|
|
|
75 void |
|
|
|
76 waitforpendingbytes(int sock) |
|
|
|
77 { |
|
|
|
78 int npending = 0, opending = 0; |
|
|
|
79 useconds_t trytime = 10; |
|
|
|
80 |
|
|
|
81 /* |
|
|
|
82 * Wait until there is nothing pending or the connection stalled |
|
|
|
83 * (nothing was sent) for around 40 seconds. Beware, trytime is |
|
|
|
84 * an exponential wait. |
|
|
|
85 */ |
|
|
|
86 while ((npending = pendingbytes(sock)) > 0 && trytime < 20000000) { |
|
|
|
87 if (opending != 0) { |
|
|
|
88 if (opending != npending) { |
|
|
|
89 trytime = 10; |
|
|
|
90 } else { |
|
|
|
91 /* |
|
|
|
92 * Exponentially increase the usleep |
|
|
|
93 * waiting time to not waste CPU |
|
|
|
94 * resources. |
|
|
|
95 */ |
|
|
|
96 trytime += trytime; |
|
|
|
97 } |
|
|
|
98 } |
|
|
|
99 opending = npending; |
|
|
|
100 |
|
|
|
101 usleep(trytime); |
|
|
|
102 } |
|
|
|
103 } |
|
|
|
104 |
|
|
|
105 #ifdef __linux__ |
|
|
|
106 int |
|
|
|
107 xsplice(int fd, int sock) |
|
|
|
108 { |
|
|
|
109 int pipefd[2], ret = 0; |
|
|
|
110 ssize_t nread, nwritten; |
|
|
|
111 off_t in_offset = 0; |
|
|
|
112 |
|
|
|
113 if (pipe(pipefd) < 0) |
|
|
|
114 return -1; |
|
|
|
115 |
|
|
|
116 do { |
|
|
|
117 nread = splice(fd, &in_offset, pipefd[1], NULL, |
|
|
|
118 BLOCK_SIZE, SPLICE_F_MOVE | SPLICE_F_MORE); |
|
|
|
119 |
|
|
|
120 if (nread <= 0) { |
|
|
|
121 ret = nread < 0 ? -1 : 0; |
|
|
|
122 goto out; |
|
|
|
123 } |
|
|
|
124 |
|
|
|
125 nwritten = splice(pipefd[0], NULL, sock, NULL, BLOCK_SIZE, |
|
|
|
126 SPLICE_F_MOVE | SPLICE_F_MORE); |
|
|
|
127 if (nwritten < 0) { |
|
|
|
128 ret = -1; |
|
|
|
129 goto out; |
|
|
|
130 } |
|
|
|
131 } while (nwritten > 0); |
|
|
|
132 |
|
|
|
133 out: |
|
|
|
134 close(pipefd[0]); |
|
|
|
135 close(pipefd[1]); |
|
|
|
136 |
|
|
|
137 return ret; |
|
|
|
138 } |
|
|
|
139 #endif |
|
|
|
140 |
|
|
|
141 int |
|
|
|
142 xsendfile(int fd, int sock) |
|
|
|
143 { |
|
|
|
144 struct stat st; |
|
|
|
145 char *sendb, *sendi; |
|
|
|
146 size_t bufsiz = BUFSIZ; |
|
|
|
147 int len, sent, optval; |
|
|
|
148 |
|
|
|
149 #ifdef splice |
|
|
|
150 return xsplice(fd, sock); |
|
|
|
151 #endif |
|
|
|
152 |
|
|
|
153 USED(optval); |
|
|
|
154 |
|
|
|
155 /* |
|
|
|
156 * The story of xsendfile. |
|
|
|
157 * |
|
|
|
158 * Once upon a time, here you saw a big #ifdef switch source of |
|
|
|
159 * many ways how to send files with special functions on |
|
|
|
160 * different operating systems. All of this was removed, because |
|
|
|
161 * operating systems and kernels got better over time, |
|
|
|
162 * simplifying what you need and reducing corner cases. |
|
|
|
163 * |
|
|
|
164 * For example Linux sendfile(2) sounds nice and faster, but |
|
|
|
165 * the function is different on every OS and slower to the now |
|
|
|
166 * used approach of read(2) and write(2). |
|
|
|
167 * |
|
|
|
168 * If you ever consider changing this to some "faster" approach, |
|
|
|
169 * consider benchmarks on all platforms. |
|
|
|
170 */ |
|
|
|
171 |
|
|
|
172 if (fstat(fd, &st) >= 0) { |
|
|
|
173 if ((bufsiz = st.st_blksize) < BUFSIZ) |
|
|
|
174 bufsiz = BUFSIZ; |
|
|
|
175 } |
|
|
|
176 |
|
|
|
177 sendb = xmalloc(bufsiz); |
|
|
|
178 while ((len = read(fd, sendb, bufsiz)) > 0) { |
|
|
|
179 sendi = sendb; |
|
|
|
180 while (len > 0) { |
|
|
|
181 if ((sent = write(sock, sendi, len)) < 0) { |
|
|
|
182 free(sendb); |
|
|
|
183 return -1; |
|
|
|
184 } |
|
|
|
185 len -= sent; |
|
|
|
186 sendi += sent; |
|
|
|
187 } |
|
|
|
188 } |
|
|
|
189 free(sendb); |
|
|
|
190 |
|
|
|
191 return 0; |
|
|
|
192 } |
|
|
|
193 |
|
|
|
194 void * |
|
|
|
195 xcalloc(size_t nmemb, size_t size) |
|
|
|
196 { |
|
|
|
197 void *p; |
|
|
|
198 |
|
|
|
199 if (!(p = calloc(nmemb, size))) { |
|
|
|
200 perror("calloc"); |
|
|
|
201 exit(1); |
|
|
|
202 } |
|
|
|
203 |
|
|
|
204 return p; |
|
|
|
205 } |
|
|
|
206 |
|
|
|
207 void * |
|
|
|
208 xmalloc(size_t size) |
|
|
|
209 { |
|
|
|
210 void *p; |
|
|
|
211 |
|
|
|
212 if (!(p = malloc(size))) { |
|
|
|
213 perror("malloc"); |
|
|
|
214 exit(1); |
|
|
|
215 } |
|
|
|
216 |
|
|
|
217 return p; |
|
|
|
218 } |
|
|
|
219 |
|
|
|
220 void * |
|
|
|
221 xrealloc(void *ptr, size_t size) |
|
|
|
222 { |
|
|
|
223 if (!(ptr = realloc(ptr, size))) { |
|
|
|
224 perror("realloc"); |
|
|
|
225 exit(1); |
|
|
|
226 } |
|
|
|
227 |
|
|
|
228 return ptr; |
|
|
|
229 } |
|
|
|
230 |
|
|
|
231 char * |
|
|
|
232 xstrdup(const char *str) |
|
|
|
233 { |
|
|
|
234 char *ret; |
|
|
|
235 |
|
|
|
236 if (!(ret = strdup(str))) { |
|
|
|
237 perror("strdup"); |
|
|
|
238 exit(1); |
|
|
|
239 } |
|
|
|
240 |
|
|
|
241 return ret; |
|
|
|
242 } |
|
|
|
243 |
|
|
|
244 filetype * |
|
|
|
245 gettype(char *filename) |
|
|
|
246 { |
|
|
|
247 char *end; |
|
|
|
248 int i; |
|
|
|
249 |
|
|
|
250 end = strrchr(filename, '.'); |
|
|
|
251 if (end == NULL) |
|
|
|
252 return &type[0]; |
|
|
|
253 end++; |
|
|
|
254 |
|
|
|
255 for (i = 0; type[i].end != NULL; i++) |
|
|
|
256 if (!strcasecmp(end, type[i].end)) |
|
|
|
257 return &type[i]; |
|
|
|
258 |
|
|
|
259 return &type[0]; |
|
|
|
260 } |
|
|
|
261 |
|
|
|
262 void |
|
|
|
263 gph_freeelem(gphelem *e) |
|
|
|
264 { |
|
|
|
265 if (e != NULL) { |
|
|
|
266 if (e->e != NULL) { |
|
|
|
267 for (;e->num > 0; e->num--) |
|
|
|
268 if (e->e[e->num - 1] != NULL) |
|
|
|
269 free(e->e[e->num - 1]); |
|
|
|
270 free(e->e); |
|
|
|
271 } |
|
|
|
272 free(e); |
|
|
|
273 } |
|
|
|
274 return; |
|
|
|
275 } |
|
|
|
276 |
|
|
|
277 void |
|
|
|
278 gph_freeindex(gphindex *i) |
|
|
|
279 { |
|
|
|
280 if (i != NULL) { |
|
|
|
281 if (i->n != NULL) { |
|
|
|
282 for (;i->num > 0; i->num--) |
|
|
|
283 gph_freeelem(i->n[i->num - 1]); |
|
|
|
284 free(i->n); |
|
|
|
285 } |
|
|
|
286 free(i); |
|
|
|
287 } |
|
|
|
288 |
|
|
|
289 return; |
|
|
|
290 } |
|
|
|
291 |
|
|
|
292 void |
|
|
|
293 gph_addelem(gphelem *e, char *s) |
|
|
|
294 { |
|
|
|
295 e->num++; |
|
|
|
296 e->e = xrealloc(e->e, sizeof(char *) * e->num); |
|
|
|
297 e->e[e->num - 1] = xstrdup(s); |
|
|
|
298 |
|
|
|
299 return; |
|
|
|
300 } |
|
|
|
301 |
|
|
|
302 gphelem * |
|
|
|
303 gph_getadv(char *str) |
|
|
|
304 { |
|
|
|
305 char *b, *e, *o, *bo; |
|
|
|
306 gphelem *ret; |
|
|
|
307 |
|
|
|
308 ret = xcalloc(1, sizeof(gphelem)); |
|
|
|
309 |
|
|
|
310 if (strchr(str, '\t')) { |
|
|
|
311 gph_addelem(ret, "i"); |
|
|
|
312 gph_addelem(ret, "Happy helping ☃ here: You tried to " |
|
|
|
313 "output a spurious TAB character. This will " |
|
|
|
314 "break gopher. Please review your scripts. " |
|
|
|
315 "Have a nice day!"); |
|
|
|
316 gph_addelem(ret, "Err"); |
|
|
|
317 gph_addelem(ret, "server"); |
|
|
|
318 gph_addelem(ret, "port"); |
|
|
|
319 |
|
|
|
320 return ret; |
|
|
|
321 } |
|
|
|
322 |
|
|
|
323 /* Check for escape sequence. */ |
|
|
|
324 if (str[0] == '[' && str[1] != '|') { |
|
|
|
325 o = xstrdup(str); |
|
|
|
326 b = o + 1; |
|
|
|
327 bo = b; |
|
|
|
328 while ((e = strchr(bo, '|')) != NULL) { |
|
|
|
329 if (e != bo && e[-1] == '\\') { |
|
|
|
330 memmove(&e[-1], e, strlen(e)); |
|
|
|
331 bo = e; |
|
|
|
332 continue; |
|
|
|
333 } |
|
|
|
334 *e = '\0'; |
|
|
|
335 e++; |
|
|
|
336 gph_addelem(ret, b); |
|
|
|
337 b = e; |
|
|
|
338 bo = b; |
|
|
|
339 } |
|
|
|
340 |
|
|
|
341 e = strchr(b, ']'); |
|
|
|
342 if (e != NULL) { |
|
|
|
343 *e = '\0'; |
|
|
|
344 gph_addelem(ret, b); |
|
|
|
345 } |
|
|
|
346 free(o); |
|
|
|
347 |
|
|
|
348 if (ret->e != NULL && ret->e[0] != NULL && |
|
|
|
349 ret->e[0][0] != '\0' && ret->num == 5) { |
|
|
|
350 return ret; |
|
|
|
351 } |
|
|
|
352 |
|
|
|
353 /* Invalid entry: Give back the whole line. */ |
|
|
|
354 gph_freeelem(ret); |
|
|
|
355 ret = xcalloc(1, sizeof(gphelem)); |
|
|
|
356 } |
|
|
|
357 |
|
|
|
358 gph_addelem(ret, "i"); |
|
|
|
359 /* Jump over escape sequence. */ |
|
|
|
360 if (str[0] == '[' && str[1] == '|') |
|
|
|
361 str += 2; |
|
|
|
362 gph_addelem(ret, str); |
|
|
|
363 gph_addelem(ret, "Err"); |
|
|
|
364 gph_addelem(ret, "server"); |
|
|
|
365 gph_addelem(ret, "port"); |
|
|
|
366 |
|
|
|
367 return ret; |
|
|
|
368 } |
|
|
|
369 |
|
|
|
370 void |
|
|
|
371 gph_addindex(gphindex *idx, gphelem *el) |
|
|
|
372 { |
|
|
|
373 idx->num++; |
|
|
|
374 idx->n = xrealloc(idx->n, sizeof(gphelem *) * idx->num); |
|
|
|
375 idx->n[idx->num - 1] = el; |
|
|
|
376 |
|
|
|
377 return; |
|
|
|
378 } |
|
|
|
379 |
|
|
|
380 gphindex * |
|
|
|
381 gph_scanfile(char *fname) |
|
|
|
382 { |
|
|
|
383 char *ln = NULL; |
|
|
|
384 size_t linesiz = 0; |
|
|
|
385 ssize_t n; |
|
|
|
386 FILE *fp; |
|
|
|
387 gphindex *ret; |
|
|
|
388 gphelem *el; |
|
|
|
389 |
|
|
|
390 if (!(fp = fopen(fname, "r"))) |
|
|
|
391 return NULL; |
|
|
|
392 |
|
|
|
393 ret = xcalloc(1, sizeof(gphindex)); |
|
|
|
394 |
|
|
|
395 while ((n = getline(&ln, &linesiz, fp)) > 0) { |
|
|
|
396 if (ln[n - 1] == '\n') |
|
|
|
397 ln[--n] = '\0'; |
|
|
|
398 el = gph_getadv(ln); |
|
|
|
399 if (el == NULL) |
|
|
|
400 continue; |
|
|
|
401 |
|
|
|
402 gph_addindex(ret, el); |
|
|
|
403 } |
|
|
|
404 if (ferror(fp)) |
|
|
|
405 perror("getline"); |
|
|
|
406 free(ln); |
|
|
|
407 fclose(fp); |
|
|
|
408 |
|
|
|
409 if (ret->n == NULL) { |
|
|
|
410 free(ret); |
|
|
|
411 return NULL; |
|
|
|
412 } |
|
|
|
413 |
|
|
|
414 return ret; |
|
|
|
415 } |
|
|
|
416 |
|
|
|
417 int |
|
|
|
418 gph_printelem(int fd, gphelem *el, char *file, char *base, char *addr, char *port) |
|
|
|
419 { |
|
|
|
420 char *path, *p, *argbase, buf[PATH_MAX+1], *argp, *realbase, *rpath; |
|
|
|
421 int len, blen; |
|
|
|
422 |
|
|
|
423 if (!strcmp(el->e[3], "server")) { |
|
|
|
424 free(el->e[3]); |
|
|
|
425 el->e[3] = xstrdup(addr); |
|
|
|
426 } |
|
|
|
427 if (!strcmp(el->e[4], "port")) { |
|
|
|
428 free(el->e[4]); |
|
|
|
429 el->e[4] = xstrdup(port); |
|
|
|
430 } |
|
|
|
431 |
|
|
|
432 /* |
|
|
|
433 * Ignore if the path is from base, if it might be some h type with |
|
|
|
434 * some URL and ignore various types that have different semantics, |
|
|
|
435 * do not point to some file or directory. |
|
|
|
436 */ |
|
|
|
437 if ((el->e[2][0] != '\0' |
|
|
|
438 && el->e[2][0] != '/' /* Absolute Request. */ |
|
|
|
439 && el->e[0][0] != 'i' /* Informational item. */ |
|
|
|
440 && el->e[0][0] != '2' /* CSO server */ |
|
|
|
441 && el->e[0][0] != '3' /* Error */ |
|
|
|
442 && el->e[0][0] != '8' /* Telnet */ |
|
|
|
443 && el->e[0][0] != 'w' /* Selector is direct URI. */ |
|
|
|
444 && el->e[0][0] != 'T') && /* tn3270 */ |
|
|
|
445 !(el->e[0][0] == 'h' && !strncmp(el->e[2], "URL:", 4))) { |
|
|
|
446 path = file + strlen(base); |
|
|
|
447 |
|
|
|
448 /* Strip off original gph file name. */ |
|
|
|
449 if ((p = strrchr(path, '/'))) { |
|
|
|
450 len = strlen(path) - strlen(basename(path)); |
|
|
|
451 } else { |
|
|
|
452 len = strlen(path); |
|
|
|
453 } |
|
|
|
454 |
|
|
|
455 /* Strip off arguments for realpath. */ |
|
|
|
456 argbase = strchr(el->e[2], '?'); |
|
|
|
457 if (argbase != NULL) { |
|
|
|
458 blen = argbase - el->e[2]; |
|
|
|
459 } else { |
|
|
|
460 blen = strlen(el->e[2]); |
|
|
|
461 } |
|
|
|
462 |
|
|
|
463 /* |
|
|
|
464 * Print everything together. Realpath will resolve it. |
|
|
|
465 */ |
|
|
|
466 snprintf(buf, sizeof(buf), "%s%.*s%.*s", base, len, |
|
|
|
467 path, blen, el->e[2]); |
|
|
|
468 |
|
|
|
469 if ((rpath = realpath(buf, NULL)) && |
|
|
|
470 (realbase = realpath(*base? base : "/", NULL)) && |
|
|
|
471 !strncmp(realbase, rpath, strlen(realbase))) { |
|
|
|
472 p = rpath + (*base? strlen(realbase) : 0); |
|
|
|
473 |
|
|
|
474 /* |
|
|
|
475 * Do not forget to re-add arguments which were |
|
|
|
476 * stripped off. |
|
|
|
477 */ |
|
|
|
478 argp = smprintf("%s%s", *p? p : "/", argbase? argbase : ""); |
|
|
|
479 |
|
|
|
480 free(el->e[2]); |
|
|
|
481 el->e[2] = argp; |
|
|
|
482 free(realbase); |
|
|
|
483 } |
|
|
|
484 if (rpath != NULL) |
|
|
|
485 free(rpath); |
|
|
|
486 } |
|
|
|
487 |
|
|
|
488 if (dprintf(fd, "%.1s%s\t%s\t%s\t%s\r\n", el->e[0], el->e[1], el->e[2], |
|
|
|
489 el->e[3], el->e[4]) < 0) { |
|
|
|
490 perror("printgphelem: dprintf"); |
|
|
|
491 return -1; |
|
|
|
492 } |
|
|
|
493 return 0; |
|
|
|
494 } |
|
|
|
495 |
|
|
|
496 char * |
|
|
|
497 smprintf(char *fmt, ...) |
|
|
|
498 { |
|
|
|
499 va_list fmtargs; |
|
|
|
500 char *ret; |
|
|
|
501 int size; |
|
|
|
502 |
|
|
|
503 va_start(fmtargs, fmt); |
|
|
|
504 size = vsnprintf(NULL, 0, fmt, fmtargs); |
|
|
|
505 va_end(fmtargs); |
|
|
|
506 |
|
|
|
507 ret = xcalloc(1, ++size); |
|
|
|
508 va_start(fmtargs, fmt); |
|
|
|
509 vsnprintf(ret, size, fmt, fmtargs); |
|
|
|
510 va_end(fmtargs); |
|
|
|
511 |
|
|
|
512 return ret; |
|
|
|
513 } |
|
|
|
514 |
|
|
|
515 char * |
|
|
|
516 reverselookup(char *host) |
|
|
|
517 { |
|
|
|
518 struct in_addr hoststr; |
|
|
|
519 struct hostent *client; |
|
|
|
520 char *rethost; |
|
|
|
521 |
|
|
|
522 rethost = NULL; |
|
|
|
523 |
|
|
|
524 if (inet_pton(AF_INET, host, &hoststr)) { |
|
|
|
525 client = gethostbyaddr((const void *)&hoststr, |
|
|
|
526 sizeof(hoststr), AF_INET); |
|
|
|
527 if (client != NULL) |
|
|
|
528 rethost = xstrdup(client->h_name); |
|
|
|
529 } |
|
|
|
530 |
|
|
|
531 if (rethost == NULL) |
|
|
|
532 rethost = xstrdup(host); |
|
|
|
533 |
|
|
|
534 return rethost; |
|
|
|
535 } |
|
|
|
536 |
|
|
|
537 void |
|
|
|
538 setcgienviron(char *file, char *path, char *port, char *base, char *args, |
|
|
|
539 char *sear, char *ohost, char *chost, char *bhost, int istls, |
|
|
|
540 char *sel, char *traverse) |
|
|
|
541 { |
|
|
|
542 /* |
|
|
|
543 * TODO: Clean environment from possible unsafe environment variables. |
|
|
|
544 * But then it is the responsibility of the script writer. |
|
|
|
545 */ |
|
|
|
546 unsetenv("AUTH_TYPE"); |
|
|
|
547 unsetenv("CONTENT_LENGTH"); |
|
|
|
548 unsetenv("CONTENT_TYPE"); |
|
|
|
549 setenv("GATEWAY_INTERFACE", "CGI/1.1", 1); |
|
|
|
550 /* TODO: Separate, if run like rest.dcgi. */ |
|
|
|
551 setenv("PATH_INFO", path+strlen(base), 1); |
|
|
|
552 setenv("PATH_TRANSLATED", path, 1); |
|
|
|
553 |
|
|
|
554 setenv("QUERY_STRING", args, 1); |
|
|
|
555 setenv("SELECTOR", sel, 1); |
|
|
|
556 setenv("REQUEST", sel, 1); |
|
|
|
557 setenv("TRAVERSAL", traverse, 1); |
|
|
|
558 |
|
|
|
559 setenv("REMOTE_ADDR", chost, 1); |
|
|
|
560 /* |
|
|
|
561 * Don't do a reverse lookup on every call. Only do when needed, in |
|
|
|
562 * the script. The RFC allows us to set the IP to the value. |
|
|
|
563 */ |
|
|
|
564 setenv("REMOTE_HOST", chost, 1); |
|
|
|
565 /* Please do not implement identd here. */ |
|
|
|
566 unsetenv("REMOTE_IDENT"); |
|
|
|
567 unsetenv("REMOTE_USER"); |
|
|
|
568 /* Make PHP happy. */ |
|
|
|
569 setenv("REDIRECT_STATUS", "", 1); |
|
|
|
570 /* |
|
|
|
571 * Only GET is possible in gopher. POST emulation would be really |
|
|
|
572 * ugly. |
|
|
|
573 */ |
|
|
|
574 setenv("REQUEST_METHOD", "GET", 1); |
|
|
|
575 setenv("SCRIPT_NAME", file, 1); |
|
|
|
576 setenv("SERVER_NAME", ohost, 1); |
|
|
|
577 setenv("SERVER_PORT", port, 1); |
|
|
|
578 setenv("SERVER_LISTEN_NAME", bhost, 1); |
|
|
|
579 if (istls) { |
|
|
|
580 setenv("SERVER_PROTOCOL", "gophers/1.0", 1); |
|
|
|
581 } else { |
|
|
|
582 setenv("SERVER_PROTOCOL", "gopher/1.0", 1); |
|
|
|
583 } |
|
|
|
584 setenv("SERVER_SOFTWARE", "geomyidae", 1); |
|
|
|
585 |
|
|
|
586 setenv("X_GOPHER_SEARCH", sear, 1); |
|
|
|
587 /* legacy compatibility */ |
|
|
|
588 setenv("SEARCHREQUEST", sear, 1); |
|
|
|
589 |
|
|
|
590 if (istls) { |
|
|
|
591 setenv("GOPHERS", "on", 1); |
|
|
|
592 setenv("HTTPS", "on", 1); |
|
|
|
593 } else { |
|
|
|
594 unsetenv("GOPHERS"); |
|
|
|
595 unsetenv("HTTPS"); |
|
|
|
596 } |
|
|
|
597 |
|
|
|
598 } |
|
|
|
599 |
|
|
|
600 char * |
|
|
|
601 humansize(off_t n) |
|
|
|
602 { |
|
|
|
603 static char buf[16]; |
|
|
|
604 const char postfixes[] = "BKMGTPE"; |
|
|
|
605 double size; |
|
|
|
606 int i = 0; |
|
|
|
607 |
|
|
|
608 for (size = n; size >= 1024 && i < strlen(postfixes); i++) |
|
|
|
609 size /= 1024; |
|
|
|
610 |
|
|
|
611 if (!i) { |
|
|
|
612 snprintf(buf, sizeof(buf), "%ju%c", (uintmax_t)n, |
|
|
|
613 postfixes[i]); |
|
|
|
614 } else { |
|
|
|
615 snprintf(buf, sizeof(buf), "%.1f%c", size, postfixes[i]); |
|
|
|
616 } |
|
|
|
617 |
|
|
|
618 return buf; |
|
|
|
619 } |
|
|
|
620 |
|
|
|
621 char * |
|
|
|
622 humantime(const time_t *clock) |
|
|
|
623 { |
|
|
|
624 static char buf[32]; |
|
|
|
625 struct tm *tm; |
|
|
|
626 |
|
|
|
627 tm = localtime(clock); |
|
|
|
628 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M %Z", tm); |
|
|
|
629 |
|
|
|
630 return buf; |
|
|
|
631 } |
|
|
|
632 |
|
|
|
633 void |
|
|
|
634 lingersock(int sock) |
|
|
|
635 { |
|
|
|
636 struct linger lingerie; |
|
|
|
637 int j; |
|
|
|
638 |
|
|
|
639 /* |
|
|
|
640 * On close only wait for at maximum 60 seconds for all data to be |
|
|
|
641 * transmitted before forcefully closing the connection. |
|
|
|
642 */ |
|
|
|
643 lingerie.l_onoff = 1; |
|
|
|
644 lingerie.l_linger = 60; |
|
|
|
645 setsockopt(sock, SOL_SOCKET, SO_LINGER, |
|
|
|
646 &lingerie, sizeof(lingerie)); |
|
|
|
647 |
|
|
|
648 /* |
|
|
|
649 * Force explicit flush of buffers using TCP_NODELAY. |
|
|
|
650 */ |
|
|
|
651 j = 1; |
|
|
|
652 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &j, sizeof(int)); |
|
|
|
653 waitforpendingbytes(sock); |
|
|
|
654 j = 0; |
|
|
|
655 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &j, sizeof(int)); |
|
|
|
656 |
|
|
|
657 return; |
|
|
|
658 } |
|
|
|
659 |
|