quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

resp.c (2539B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <dirent.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/stat.h>
      7 #include <time.h>
      8 #include <unistd.h>
      9 
     10 #include "http.h"
     11 #include "resp.h"
     12 #include "util.h"
     13 
     14 static int
     15 compareent(const struct dirent **d1, const struct dirent **d2)
     16 {
     17 	int v;
     18 
     19 	v = ((*d2)->d_type == DT_DIR ? 1 : -1) -
     20 	    ((*d1)->d_type == DT_DIR ? 1 : -1);
     21 	if (v) {
     22 		return v;
     23 	}
     24 
     25 	return strcmp((*d1)->d_name, (*d2)->d_name);
     26 }
     27 
     28 static char *
     29 suffix(int t)
     30 {
     31 	switch (t) {
     32 	case DT_FIFO: return "|";
     33 	case DT_DIR:  return "/";
     34 	case DT_LNK:  return "@";
     35 	case DT_SOCK: return "=";
     36 	}
     37 
     38 	return "";
     39 }
     40 
     41 enum status
     42 resp_dir(int fd, const struct response *res)
     43 {
     44 	enum status ret;
     45 	struct dirent **e;
     46 	size_t i;
     47 	int dirlen;
     48 	char esc[PATH_MAX /* > NAME_MAX */ * 6]; /* strlen("&...;") <= 6 */
     49 
     50 	/* read directory */
     51 	if ((dirlen = scandir(res->path, &e, NULL, compareent)) < 0) {
     52 		return S_FORBIDDEN;
     53 	}
     54 
     55 	/* listing */
     56 	for (i = 0; i < (size_t)dirlen; i++) {
     57 		/* skip hidden files, "." and ".." */
     58 		if (e[i]->d_name[0] == '.') {
     59 			continue;
     60 		}
     61 
     62 		/* entry line */
     63 		html_escape(e[i]->d_name, esc, sizeof(esc));
     64 		if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>",
     65 		            esc,
     66 		            (e[i]->d_type == DT_DIR) ? "/" : "",
     67 		            esc,
     68 		            suffix(e[i]->d_type)) < 0) {
     69 			ret = S_REQUEST_TIMEOUT;
     70 			goto cleanup;
     71 		}
     72 	}
     73 
     74 	/* listing footer */
     75 	if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) {
     76 		ret = S_REQUEST_TIMEOUT;
     77 		goto cleanup;
     78 	}
     79 
     80 cleanup:
     81 	while (dirlen--) {
     82 		free(e[dirlen]);
     83 	}
     84 	free(e);
     85 
     86 	return ret;
     87 }
     88 
     89 enum status
     90 resp_file(int fd, const struct response *res)
     91 {
     92 	FILE *fp;
     93 	enum status ret = 0;
     94 	ssize_t bread, bwritten;
     95 	size_t remaining;
     96 	static char buf[BUFSIZ], *p;
     97 
     98 	/* open file */
     99 	if (!(fp = fopen(res->path, "r"))) {
    100 		ret = S_FORBIDDEN;
    101 		goto cleanup;
    102 	}
    103 
    104 	/* seek to lower bound */
    105 	if (fseek(fp, res->file.lower, SEEK_SET)) {
    106 		ret = S_INTERNAL_SERVER_ERROR;
    107 		goto cleanup;
    108 	}
    109 
    110 	/* write data until upper bound is hit */
    111 	remaining = res->file.upper - res->file.lower + 1;
    112 
    113 	while ((bread = fread(buf, 1, MIN(sizeof(buf),
    114 	                      remaining), fp))) {
    115 		if (bread < 0) {
    116 			ret = S_INTERNAL_SERVER_ERROR;
    117 			goto cleanup;
    118 		}
    119 		remaining -= bread;
    120 		p = buf;
    121 		while (bread > 0) {
    122 			bwritten = write(fd, p, bread);
    123 			if (bwritten <= 0) {
    124 				ret = S_REQUEST_TIMEOUT;
    125 				goto cleanup;
    126 			}
    127 			bread -= bwritten;
    128 			p += bwritten;
    129 		}
    130 	}
    131 cleanup:
    132 	if (fp) {
    133 		fclose(fp);
    134 	}
    135 
    136 	return ret;
    137 }