Sat, 12 Nov 2022 17:28:32 +0100
improve error handling in send_file if the file is a directory
--- a/src/server/safs/objecttype.c Sat Nov 12 17:00:16 2022 +0100 +++ b/src/server/safs/objecttype.c Sat Nov 12 17:28:32 2022 +0100 @@ -42,7 +42,7 @@ cxstring ct; if(path.ptr[path.length - 1] == '/') { // directory - ct = (cxstring)CX_STR("internal/directory"); + ct = (cxstring)CX_STR(OBJTYPE_INTERNAL_DIRECTORY); } else { cxstring ext; ext.length = 0;
--- a/src/server/safs/objecttype.h Sat Nov 12 17:00:16 2022 +0100 +++ b/src/server/safs/objecttype.h Sat Nov 12 17:28:32 2022 +0100 @@ -35,6 +35,8 @@ extern "C" { #endif +#define OBJTYPE_INTERNAL_DIRECTORY "internal/directory" + int object_type_by_extension(pblock *pb, Session *sn, Request *rq); #ifdef __cplusplus
--- a/src/server/safs/service.c Sat Nov 12 17:00:16 2022 +0100 +++ b/src/server/safs/service.c Sat Nov 12 17:28:32 2022 +0100 @@ -31,6 +31,7 @@ #include <sys/stat.h> #include "service.h" +#include "objecttype.h" #include "../util/io.h" #include "../util/pblock.h" #include "../util/util.h" @@ -51,7 +52,7 @@ * * return the opened file */ -SYS_FILE prepare_service_file(Session *sn, Request *rq, VFSContext *vfs, struct stat *s) { +SYS_FILE prepare_service_file(Session *sn, Request *rq, VFSContext *vfs, struct stat *s, int *ret) { char *path = pblock_findkeyval(pb_key_path, rq->vars); // open the file @@ -70,17 +71,29 @@ // check if the file is a directory if(S_ISDIR(s->st_mode)) { - pblock_nvinsert("content-length", "0", rq->srvhdrs); pblock_removekey(pb_key_content_type, rq->srvhdrs); char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); size_t urilen = strlen(uri); - char *location = pool_malloc(sn->pool, urilen + 2); - memcpy(location, uri, urilen); - location[urilen] = '/'; - location[urilen+1] = '\0'; - pblock_kvinsert(pb_key_location, location, urilen + 1, rq->srvhdrs); - protocol_status(sn, rq, 302, NULL); - http_start_response(sn, rq); + if(urilen > 0 && uri[urilen-1] != '/') { + pblock_nvinsert("content-length", "0", rq->srvhdrs); + char *location = pool_malloc(sn->pool, urilen + 2); + memcpy(location, uri, urilen); + location[urilen] = '/'; + location[urilen+1] = '\0'; + pblock_kvinsert(pb_key_location, location, urilen + 1, rq->srvhdrs); + protocol_status(sn, rq, 302, NULL); + http_start_response(sn, rq); + *ret = REQ_PROCEED; + } else { + // set content-type to "internal/directory" and ret to REQ_NOACTION + // maybe a SAF will respond to that + pblock_kvinsert( + pb_key_content_type, + OBJTYPE_INTERNAL_DIRECTORY, + sizeof(OBJTYPE_INTERNAL_DIRECTORY)-1, + rq->srvhdrs); + *ret = REQ_NOACTION; + } vfs_close(fd); return NULL; } @@ -89,6 +102,7 @@ const char *etag = vfs_getetag(fd); // optionally, get etag from file if(http_set_finfo_etag(sn, rq, s, etag) != REQ_PROCEED) { vfs_close(fd); + *ret = REQ_ABORTED; return NULL; } @@ -574,13 +588,15 @@ } int send_file(pblock *pb, Session *sn, Request *rq) { + int ret = REQ_NOACTION; struct stat s; VFSContext *vfs = vfs_request_context(sn, rq); - SYS_FILE fd = prepare_service_file(sn, rq, vfs, &s); + SYS_FILE fd = prepare_service_file(sn, rq, vfs, &s, &ret); if(!fd) { // if an error occurs, prepare_service_file sets the http status code - // we can just return REQ_ABORTED - return REQ_ABORTED; + // in case fd is a directory and the uri already ends with an trailing + // '/', ret is set to REQ_NOACTION + return ret; } // get and validate range header @@ -637,7 +653,6 @@ length = s.st_size; } - int ret = REQ_NOACTION; if(single_range) { // send response header http_start_response(sn, rq);