tresp.c - quark - quark web server
 (HTM) git clone git://git.suckless.org/quark
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       tresp.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 }