src/server/safs/nametrans.c

Wed, 10 Aug 2022 20:56:24 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 10 Aug 2022 20:56:24 +0200
branch
webdav
changeset 369
e28ee9875a90
parent 366
47bc686fafe4
child 415
d938228c382e
permissions
-rw-r--r--

add support for named dav repositories in nametrans safs

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2016 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "nametrans.h"

#include "../daemon/log.h"
#include "../daemon/request.h"
#include "../util/pblock.h"
#include "../util/util.h"
#include "../public/webdav.h"

#include "../daemon/session.h"
#include "../daemon/config.h"

#include "../public/vfs.h"

static int initialize_dav_repo(pblock *pb, Session *sn, Request *rq, WebdavRepository *repo) {
    if(repo->vfs) {
        VFS *vfs = repo->vfs->create(sn, rq, pb, repo->vfsInitData);
        if(!vfs) {
            return REQ_ABORTED;
        }
        rq->vfs = vfs;
    }
    
    WebdavBackend *backend_first = NULL;
    WebdavBackend *backend_last = NULL;
    UCX_FOREACH(elm, repo->davBackends) {
        WebdavBackendInitData *davInit = elm->data;
        WebdavBackend *backend = davInit->davType->create(sn, rq, pb, davInit->davInitData);
        if(!backend) {
            return REQ_ABORTED;
        }
        
        if(backend_last) {
            backend_last->next = backend;
            backend_last = backend;
        } else {
            backend_first = backend;
            backend_last = backend;
        }
    }
    rq->davCollection = backend_first;
    
    return 0;
}

static int nametrans_set_dav_repository(pblock *pb, Session *sn, Request *rq) {
    char *dav = pblock_findkeyval(pb_key_dav, pb);
    if(!dav) return 0;
    
    ServerConfiguration *config = session_get_config(sn);
    WebdavRepository *repo = ucx_map_cstr_get(config->dav, dav);
    
    if(!repo) {
        log_ereport(LOG_MISCONFIG, "nametrans: unknown dav repository '%s'", dav);
        return REQ_ABORTED;
    }
    
    return initialize_dav_repo(pb, sn, rq, repo);
}

static int nametrans_set_vfs(pblock *pb, Session *sn, Request *rq) {
    char *vfsclass = pblock_findkeyval(pb_key_vfsclass, pb);
    if(!vfsclass) return 0;
    
    VFS *vfs = vfs_create(sn, rq, vfsclass, pb, NULL);
    if(!vfs) {
        return 1;
    }
    rq->vfs = vfs;
    return 0;
}

static int nametrans_set_dav(pblock *pb, Session *sn, Request *rq) {
    char *davclass = pblock_findkeyval(pb_key_davclass, pb);
    if(!davclass) return 0;
    
    WebdavBackend *dav = webdav_create(sn, rq, davclass, pb, NULL);
    
    rq->davCollection = dav;
    return 0;
}

/*
 * assign_name
 *
 * Assigns the name specified by the name parameter if the uri has the
 * specified prefix.
 *
 * pblock parameter:
 * name     object name
 * from     optional uri prefix
 */
int assign_name(pblock *pb, Session *sn, Request *rq) {
    /* TODO: expression instead of simple prefix */

    char *name = pblock_findkeyval(pb_key_name, pb);
    char *from = pblock_findkeyval(pb_key_from, pb);

    if(!name) {
        log_ereport(LOG_MISCONFIG, "assign-name: missing name parameter");
        protocol_status(sn, rq, 500, NULL);
        return REQ_ABORTED;
    }
    
    if(from) {
        char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
        char c;
        int i = 0;
        while((c = from[i]) != 0) {
            if(c != uri[i]) {
                return REQ_NOACTION;
            }
            i++;
        }
    }
    
    if(nametrans_set_dav_repository(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "assign-name: cannot create dav repository: name=%s from=%s", name, from);
        return REQ_ABORTED;
    }
    if(nametrans_set_vfs(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "assign-name: cannot create VFS: name=%s from=%s", name, from);
        return REQ_ABORTED;
    }
    if(nametrans_set_dav(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "assign-name: cannot create Webdav Backend: name=%s from=%s", name, from);
        return REQ_ABORTED;
    }

    // add object to rq->vars
    pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars);

    return REQ_NOACTION;
}

/*
 * document_root
 * 
 * Specifies the document root directory.
 * 
 * pblock parameter:
 * root   path to document root
 */
int document_root(pblock *pb, Session *sn, Request *rq) {
    char *root = pblock_findkeyval(pb_key_root, pb);
    if(!root) {
        log_ereport(LOG_MISCONFIG, "document-root: missing root parameter");
        protocol_status(sn, rq, 500, NULL);
        return REQ_ABORTED;
    }
    
    if(nametrans_set_vfs(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "document-root: cannot create VFS");
        return REQ_ABORTED;
    }
    
    sstr_t root_str = sstr(root);
    sstr_t uri_str = sstr(pblock_findkeyval(pb_key_uri, rq->reqpb));  
    
    request_set_path(root_str, uri_str, rq->vars);
    
    return REQ_PROCEED;
}

/*
 * pfx2dir
 * 
 * ...
 * 
 * pblock parameter:
 * from     prefix
 * dir      file system directory
 * name     (optional) object name
 * dav      (optional) dav repository name
 * vfsclass (optional) vfs name
 * davclass (optional) dav backend
 * 
 */
int pfx2dir(pblock *pb, Session *sn, Request *rq) {
    char *from = pblock_findkeyval(pb_key_from, pb);
    char *dir = pblock_findkeyval(pb_key_dir, pb);
    char *name = pblock_findkeyval(pb_key_name, pb);
    
    if(!from || !dir) {
        if(!from && dir) {
            log_ereport(LOG_MISCONFIG, "pfx2dir: missing from parameter");
        } else if(!dir && from) {
            log_ereport(LOG_MISCONFIG, "pfx2dir: missing dir parameter");
        } else {
            log_ereport(
                    LOG_MISCONFIG,
                    "pfx2dir: missing from and dir parameter");
        }
        protocol_status(sn, rq, 500, NULL);
        return REQ_ABORTED;
    }
    
    // check prefix
    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
    char fc;
    char uc;
    int i = 0;
    while((fc = from[i]) != 0) {
        uc = uri[i];
        if(fc != uc) {
            return REQ_NOACTION;
        }
        i++;
    }
    
    // url has the specified prefix
    
    uri = uri + i;
    if(uri[0] == '/') {
        uri++;
    }
    
    if(nametrans_set_dav_repository(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "pfx2dir: cannot create dav repository: from=%s dir=%s name=%s", from, dir, name);
        return REQ_ABORTED;
    }
    if(nametrans_set_vfs(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "pfx2dir: cannot create VFS: from=%s dir=%s name=%s", from, dir, name);
        return REQ_ABORTED;
    }
    if(nametrans_set_dav(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "pfx2dir: cannot create Webdav Backend: from=%s dir=%s name=%s", from, dir, name);
        return REQ_ABORTED;
    }
    
    request_set_path(sstr(dir), sstr(uri), rq->vars);
    
    if(name) {
        // add object to rq->vars
        pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars);
    }
    
    return REQ_PROCEED;
}


int redirect(pblock *pb, Session *sn, Request *rq) {
    char *from = pblock_findval("from", pb);
    char *url = pblock_findval("url", pb);
    
    if(!from || !url) {
        log_ereport(LOG_MISCONFIG, "redirect: missing parameter (from, url)");
        return REQ_ABORTED;
    }
    
    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
    if(!strcmp(uri, from)) {
        pblock_nvinsert("location", url, rq->srvhdrs);
        
        protocol_status(sn, rq, 302, NULL); 
        return REQ_ABORTED;
    }
    
    return REQ_NOACTION;
}

/*
 * provisional rewrite saf
 */
int simple_rewrite(pblock *pb, Session *sn, Request *rq) {
    char *from = pblock_findval("from", pb);
    char *root = pblock_findval("root", pb);
    char *path = pblock_findval("path", pb);
    char *name = pblock_findval("name", pb);
    
    if(!from || !path || !root) {
        log_ereport(LOG_MISCONFIG, "simple-rewrite: missing parameter (from, root, path)");
        return REQ_ABORTED;
    }
    
    if(nametrans_set_vfs(pb, sn, rq)) {
        log_ereport(LOG_FAILURE, "simple-rewrite: cannot create VFS: from=%s root=%s path=%s name=%s", from, root, path, name);
        return REQ_ABORTED;
    }
    
    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
    sstr_t u = sstr(uri);
    sstr_t f = sstr(from);
    if(sstrprefix(u, f)) {
        sstr_t suf = sstrsubs(u, f.length);
        sstr_t ppath = sstrcat(2, sstr(path), suf);
        
        request_set_path(sstr(root), ppath, rq->vars);
        free(ppath.ptr);
        
        if(name) {
            // add object to rq->vars
            pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars);
        }
    }
    
    return REQ_NOACTION;
}

mercurial