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 }