src/server/safs/nametrans.c

Sat, 12 Nov 2022 11:52:47 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 12 Nov 2022 11:52:47 +0100
changeset 424
3df9258cd3cc
parent 415
d938228c382e
child 490
d218607f5a7e
permissions
-rw-r--r--

allow '-' in tokens, add support for negative integers

/*
 * 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;
    }
    
    void *backend_first = NULL;
    void *backend_last = NULL;
    CxIterator i = cxListIterator(repo->davBackends, 0);
    cx_foreach(WebdavBackendInitData *, davInit, i) {
        WebdavBackend *backend = davInit->davType->create(sn, rq, pb, davInit->davInitData);
        if(!backend) {
            return REQ_ABORTED;
        }
        cx_linked_list_add(&backend_first, &backend_last, -1, offsetof(WebdavBackend, next), 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 = cxMapGet(config->dav, cx_hash_key_str(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;
    }
    
    cxstring root_str = cx_str(root);
    cxstring uri_str = cx_str(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(cx_str(dir), cx_str(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);
    cxstring u = cx_str(uri);
    cxstring f = cx_str(from);
    if(cx_strprefix(u, f)) {
        cxstring suf = cx_strsubs(u, f.length);
        cxmutstr ppath = cx_strcat(2, cx_str(path), suf);
        
        request_set_path(cx_str(root), (cxstring){ppath.ptr, ppath.length}, 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