Sun, 13 Nov 2022 10:57:38 +0100
add http_send_response function that is usable for non-blocking IO
/* * 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; }