improve error handling in send_file if the file is a directory

Sat, 12 Nov 2022 17:28:32 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 12 Nov 2022 17:28:32 +0100
changeset 428
ab58e46b50a5
parent 427
a327cb6cc868
child 429
25c8e8021156

improve error handling in send_file if the file is a directory

src/server/safs/objecttype.c file | annotate | diff | comparison | revisions
src/server/safs/objecttype.h file | annotate | diff | comparison | revisions
src/server/safs/service.c file | annotate | diff | comparison | revisions
--- 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);

mercurial