FileRecord *Dir_resolve_file(Dir *dir, bstring path) { FileRecord *file = NULL; bstring target = NULL; check(Dir_lazy_normalize_base(dir) == 0, "Failed to normalize base path when requesting %s", bdata(path)); check(bstrncmp(path, dir->prefix, blength(dir->prefix)) == 0, "Request for path %s does not start with %s prefix.", bdata(path), bdata(dir->prefix)); file = FileRecord_cache_check(dir, path); if(file) { // TODO: double check this gives the right users count file->users++; return file; } // We subtract one from the blengths below, because dir->prefix includes // a trailing '/'. If we skip over this in path->data, we drop the '/' // from the URI, breaking the target path if(bchar(path, blength(path) - 1) == '/') { target = bformat("%s%s%s", bdata(dir->normalized_base), path->data + blength(dir->prefix) - 1, bdata(dir->index_file)); } else { target = bformat("%s%s", bdata(dir->normalized_base), path->data + blength(dir->prefix) - 1); } check(target, "Couldn't construct target path for %s", bdata(path)); check_debug(normalize_path(target) == 0, "Failed to normalize target path."); check_debug(bstrncmp(target, dir->normalized_base, blength(dir->normalized_base)) == 0, "Request for path %s does not start with %s base after normalizing.", bdata(target), bdata(dir->base)); // the FileRecord now owns the target file = Dir_find_file(target, dir->default_ctype); check_debug(file, "Error opening file: %s", bdata(target)); // Increment the user count because we're adding it to the cache file->users++; file->request_path = bstrcpy(path); Cache_add(dir->fr_cache, file); return file; error: bdestroy(target); FileRecord_release(file); return NULL; }
int Dir_serve_file(Dir *dir, Request *req, Connection *conn) { FileRecord *file = NULL; bstring resp = NULL; bstring path = Request_path(req); bstring pattern = req->pattern; int rc = 0; int is_get = biseq(req->request_method, &HTTP_GET); int is_head = is_get ? 0 : biseq(req->request_method, &HTTP_HEAD); check(path, "Request had not path. That's weird."); req->response_size = 0; if(!(is_get || is_head)) { req->status_code = 405; rc = Response_send_status(conn, &HTTP_405); check_debug(rc == blength(&HTTP_405), "Failed to send 405 to client."); return -1; } else { file = Dir_resolve_file(dir, pattern, path); resp = Dir_calculate_response(req, file); if(resp) { rc = Response_send_status(conn, resp); check_debug(rc == blength(resp), "Failed to send error response on file serving."); } else if(is_get) { rc = Dir_stream_file(file, conn); req->response_size = rc; check_debug(rc == file->sb.st_size, "Didn't send all of the file, sent %d of %s.", rc, bdata(path)); } else if(is_head) { rc = Dir_send_header(file, conn); check_debug(rc, "Failed to write header to socket."); } else { sentinel("How the hell did you get to here. Tell Zed."); } FileRecord_release(file); return 0; } sentinel("Invalid code branch, Tell Zed you have magic."); error: FileRecord_release(file); return -1; }
static void filerecord_cache_evict(void *data) { FileRecord_release((FileRecord *) data); }
FileRecord *Dir_resolve_file(Dir *dir, bstring pattern, bstring path) { FileRecord *file = NULL; bstring target = NULL; bstring prefix = NULL; check(Dir_lazy_normalize_base(dir) == 0, "Failed to normalize base path when requesting %s", bdata(path)); file = FileRecord_cache_check(dir, path); if(file) { // TODO: double check this gives the right users count file->users++; return file; } int paren = bstrchr(pattern, '('); prefix = (paren > 0) ? bHead(pattern, paren) : bstrcpy(pattern); check(bchar(prefix, 0) == '/', "Route '%s' pointing to directory must have pattern with leading '/'", bdata(pattern)); check(blength(prefix) < MAX_DIR_PATH, "Prefix is too long, must be less than %d", MAX_DIR_PATH); debug("Building target from base: %s pattern: %s prefix: %s path: %s index_file: %s", bdata(dir->normalized_base), bdata(pattern), bdata(prefix), bdata(path), bdata(dir->index_file)); if(bchar(path, blength(path) - 1) == '/') { // a directory so figureo out the index file target = bformat("%s%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1, bdata(dir->index_file)); } else if(biseq(prefix, path)) { target = bformat("%s%s", bdata(dir->normalized_base), bdata(path)); } else { target = bformat("%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1); } check(target, "Couldn't construct target path for %s", bdata(path)); check_debug(normalize_path(target) == 0, "Failed to normalize target path: %s", bdata(target)); check_debug(bstrncmp(target, dir->normalized_base, blength(dir->normalized_base)) == 0, "Request for path %s does not start with %s base after normalizing.", bdata(target), bdata(dir->base)); // the FileRecord now owns the target file = Dir_find_file(target, dir->default_ctype); check_debug(file, "Error opening file: %s", bdata(target)); // Increment the user count because we're adding it to the cache file->users++; file->request_path = bstrcpy(path); Cache_add(dir->fr_cache, file); return file; error: bdestroy(target); FileRecord_release(file); return NULL; }