diff --git a/serve.c b/serve.c index 3b12786..75ae549 100644 --- a/serve.c +++ b/serve.c @@ -576,7 +576,7 @@ void respond(Request request, ResponseBuilder *b) return; } - if (serve_file_or_dir(b, LIT("/"), LIT("docroot/"), request.path, NULLSTR, false)) + if (serve_file_or_dir(b, LIT(""), LIT("docroot"), request.path, NULLSTR, false)) return; status_line(b, 404); @@ -1885,10 +1885,50 @@ string mimetype_from_filename(string name) return NULLSTR; } +void serve_file(string path, size_t size, string mime, ResponseBuilder *b) +{ + int fd; + do + fd = open(path.data, O_RDONLY); + while (fd < 0 && errno == EINTR); + + if (fd < 0) { + status_line(b, 500); + close(fd); + return; + } + + status_line(b, 200); + + if (mime.size == 0) mime = mimetype_from_filename(path); + if (mime.size > 0) add_header_f(b, "Content-Type: %.*s", (int) mime.size, mime.data); + + string dst = append_content_start(b, size); + if (dst.size == 0) { + status_line(b, 500); + close(fd); + return; + } + assert(dst.size >= size); + + size_t copied = 0; + while (copied < size) { + int num = read(fd, dst.data + copied, size - copied); + if (num <= 0) { + if (num < 0) + log_format("Failed reading from '%.*s'\n", (int) path.size, path.data); + break; + } + copied += num; + } + + append_content_end(b, copied); + close(fd); +} + bool serve_file_or_dir(ResponseBuilder *b, string prefix, string docroot, string reqpath, string mime, bool enable_dir_listing) { - // Sanitize the request path char pathmem[1<<10]; string path; @@ -1927,77 +1967,66 @@ bool serve_file_or_dir(ResponseBuilder *b, string prefix, string docroot, return true; } - if (S_ISREG(buf.st_mode)) { + if (S_ISDIR(buf.st_mode)) { - int fd; - do - fd = open(path.data, O_RDONLY); - while (fd < 0 && errno == EINTR); + if (enable_dir_listing) { - if (fd < 0) { - status_line(b, 500); - close(fd); - return true; - } + DIR *d = opendir(path.data); + if (d == NULL) { + status_line(b, 500); + return true; + } - status_line(b, 200); + status_line(b, 200); + append_content_s(b, LIT( + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n")); + closedir(d); + } else { - string dst = append_content_start(b, (size_t) buf.st_size); - if (dst.size == 0) { - status_line(b, 500); - close(fd); - return true; - } - assert(dst.size >= (size_t) buf.st_size); + // Append /index.html to the path + if (path.size + SIZEOF("/index.html")-1 >= sizeof(pathmem)) { + status_line(b, 500); + return true; + } + memcpy(path.data + path.size, "/index.html", SIZEOF("/index.html")-1); + path.size += SIZEOF("/index.html")-1; + path.data[path.size] = '\0'; - size_t copied = 0; - while (copied < (size_t) buf.st_size) { - int num = read(fd, dst.data + copied, (size_t) buf.st_size - copied); - if (num <= 0) { - if (num < 0) - log_format("Failed reading from '%.*s'\n", (int) path.size, path.data); - break; + if (stat(path.data, &buf)) { + if (errno == ENOENT) + return false; + status_line(b, 500); + return true; + } + if (!S_ISREG(buf.st_mode)) { + status_line(b, 500); + return true; } - copied += num; - } - append_content_end(b, copied); - close(fd); + serve_file(path, (size_t) buf.st_size, mime, b); + } return true; } - if (enable_dir_listing && S_ISDIR(buf.st_mode)) { - - DIR *d = opendir(path.data); - if (d == NULL) { - status_line(b, 500); - return true; - } - - status_line(b, 200); - append_content_s(b, LIT( - "\n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n")); - closedir(d); + if (S_ISREG(buf.st_mode)) { + serve_file(path, (size_t) buf.st_size, mime, b); return true; }