UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2016 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "nametrans.h" 30 31 #include "../daemon/log.h" 32 #include "../daemon/request.h" 33 #include "../util/pblock.h" 34 #include "../util/util.h" 35 #include "../public/webdav.h" 36 37 #include "../daemon/session.h" 38 #include "../daemon/config.h" 39 40 #include "../public/vfs.h" 41 42 static int initialize_dav_repo(pblock *pb, Session *sn, Request *rq, WebdavRepository *repo) { 43 if(repo->vfs) { 44 VFS *vfs = repo->vfs->create(sn, rq, pb, repo->vfsInitData); 45 if(!vfs) { 46 return REQ_ABORTED; 47 } 48 rq->vfs = vfs; 49 } 50 51 void *backend_first = NULL; 52 void *backend_last = NULL; 53 CxIterator i = cxListIterator(repo->davBackends); 54 cx_foreach(WebdavBackendInitData *, davInit, i) { 55 WebdavBackend *backend = davInit->davType->create(sn, rq, pb, davInit->davInitData); 56 if(!backend) { 57 return REQ_ABORTED; 58 } 59 cx_linked_list_add(&backend_first, &backend_last, -1, offsetof(WebdavBackend, next), backend); 60 } 61 rq->davCollection = backend_first; 62 63 return 0; 64 } 65 66 static int nametrans_set_dav_repository(pblock *pb, Session *sn, Request *rq) { 67 char *dav = pblock_findkeyval(pb_key_dav, pb); 68 if(!dav) return 0; 69 70 ServerConfiguration *config = session_get_config(sn); 71 WebdavRepository *repo = cxMapGet(config->dav, cx_hash_key_str(dav)); 72 73 if(!repo) { 74 log_ereport(LOG_MISCONFIG, "nametrans: unknown dav repository ''%s''", dav); 75 return REQ_ABORTED; 76 } 77 78 return initialize_dav_repo(pb, sn, rq, repo); 79 } 80 81 static int nametrans_set_vfs(pblock *pb, Session *sn, Request *rq) { 82 char *vfsclass = pblock_findkeyval(pb_key_vfsclass, pb); 83 if(!vfsclass) return 0; 84 85 VFS *vfs = vfs_create(sn, rq, vfsclass, pb, NULL); 86 if(!vfs) { 87 return 1; 88 } 89 rq->vfs = vfs; 90 return 0; 91 } 92 93 static int nametrans_set_dav(pblock *pb, Session *sn, Request *rq) { 94 char *davclass = pblock_findkeyval(pb_key_davclass, pb); 95 if(!davclass) return 0; 96 97 WebdavBackend *dav = webdav_create(sn, rq, davclass, pb, NULL); 98 99 rq->davCollection = dav; 100 return 0; 101 } 102 103 /* 104 * assign_name 105 * 106 * Assigns the name specified by the name parameter if the uri has the 107 * specified prefix. 108 * 109 * pblock parameter: 110 * name object name 111 * from optional uri prefix 112 */ 113 int assign_name(pblock *pb, Session *sn, Request *rq) { 114 /* TODO: expression instead of simple prefix */ 115 116 char *name = pblock_findkeyval(pb_key_name, pb); 117 char *from = pblock_findkeyval(pb_key_from, pb); 118 119 if(!name) { 120 log_ereport(LOG_MISCONFIG, "assign-name: missing name parameter"); 121 protocol_status(sn, rq, 500, NULL); 122 return REQ_ABORTED; 123 } 124 125 if(from) { 126 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 127 char c; 128 int i = 0; 129 while((c = from[i]) != 0) { 130 if(c != uri[i]) { 131 return REQ_NOACTION; 132 } 133 i++; 134 } 135 } 136 137 if(nametrans_set_dav_repository(pb, sn, rq)) { 138 log_ereport(LOG_FAILURE, "assign-name: cannot create dav repository: name=%s from=%s", name, from); 139 return REQ_ABORTED; 140 } 141 if(nametrans_set_vfs(pb, sn, rq)) { 142 log_ereport(LOG_FAILURE, "assign-name: cannot create VFS: name=%s from=%s", name, from); 143 return REQ_ABORTED; 144 } 145 if(nametrans_set_dav(pb, sn, rq)) { 146 log_ereport(LOG_FAILURE, "assign-name: cannot create Webdav Backend: name=%s from=%s", name, from); 147 return REQ_ABORTED; 148 } 149 150 // add object to rq->vars 151 pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars); 152 153 return REQ_NOACTION; 154 } 155 156 /* 157 * document_root 158 * 159 * Specifies the document root directory. 160 * 161 * pblock parameter: 162 * root path to document root 163 */ 164 int document_root(pblock *pb, Session *sn, Request *rq) { 165 char *root = pblock_findkeyval(pb_key_root, pb); 166 if(!root) { 167 log_ereport(LOG_MISCONFIG, "document-root: missing root parameter"); 168 protocol_status(sn, rq, 500, NULL); 169 return REQ_ABORTED; 170 } 171 172 if(nametrans_set_vfs(pb, sn, rq)) { 173 log_ereport(LOG_FAILURE, "document-root: cannot create VFS"); 174 return REQ_ABORTED; 175 } 176 177 cxstring root_str = cx_str(root); 178 cxstring uri_str = cx_str(pblock_findkeyval(pb_key_uri, rq->reqpb)); 179 180 request_set_path(root_str, uri_str, rq->vars); 181 182 return REQ_PROCEED; 183 } 184 185 /* 186 * pfx2dir 187 * 188 * ... 189 * 190 * pblock parameter: 191 * from prefix 192 * dir file system directory 193 * name (optional) object name 194 * dav (optional) dav repository name 195 * vfsclass (optional) vfs name 196 * davclass (optional) dav backend 197 * 198 */ 199 int pfx2dir(pblock *pb, Session *sn, Request *rq) { 200 char *from = pblock_findkeyval(pb_key_from, pb); 201 char *dir = pblock_findkeyval(pb_key_dir, pb); 202 char *name = pblock_findkeyval(pb_key_name, pb); 203 204 if(!from || !dir) { 205 if(!from && dir) { 206 log_ereport(LOG_MISCONFIG, "pfx2dir: missing from parameter"); 207 } else if(!dir && from) { 208 log_ereport(LOG_MISCONFIG, "pfx2dir: missing dir parameter"); 209 } else { 210 log_ereport( 211 LOG_MISCONFIG, 212 "pfx2dir: missing from and dir parameter"); 213 } 214 protocol_status(sn, rq, 500, NULL); 215 return REQ_ABORTED; 216 } 217 218 // check prefix 219 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 220 char fc; 221 char uc; 222 int i = 0; 223 while((fc = from[i]) != 0) { 224 uc = uri[i]; 225 if(fc != uc) { 226 return REQ_NOACTION; 227 } 228 i++; 229 } 230 231 // url has the specified prefix 232 233 uri = uri + i; 234 if(uri[0] == '/') { 235 uri++; 236 } 237 238 if(nametrans_set_dav_repository(pb, sn, rq)) { 239 log_ereport(LOG_FAILURE, "pfx2dir: cannot create dav repository: from=%s dir=%s name=%s", from, dir, name); 240 return REQ_ABORTED; 241 } 242 if(nametrans_set_vfs(pb, sn, rq)) { 243 log_ereport(LOG_FAILURE, "pfx2dir: cannot create VFS: from=%s dir=%s name=%s", from, dir, name); 244 return REQ_ABORTED; 245 } 246 if(nametrans_set_dav(pb, sn, rq)) { 247 log_ereport(LOG_FAILURE, "pfx2dir: cannot create Webdav Backend: from=%s dir=%s name=%s", from, dir, name); 248 return REQ_ABORTED; 249 } 250 251 request_set_path(cx_str(dir), cx_str(uri), rq->vars); 252 253 if(name) { 254 // add object to rq->vars 255 pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars); 256 } 257 258 return REQ_PROCEED; 259 } 260 261 262 int redirect(pblock *pb, Session *sn, Request *rq) { 263 char *from = pblock_findval("from", pb); 264 char *url = pblock_findval("url", pb); 265 266 if(!from || !url) { 267 log_ereport(LOG_MISCONFIG, "redirect: missing parameter (from, url)"); 268 return REQ_ABORTED; 269 } 270 271 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 272 if(!strcmp(uri, from)) { 273 pblock_nvinsert("location", url, rq->srvhdrs); 274 275 protocol_status(sn, rq, 302, NULL); 276 return REQ_ABORTED; 277 } 278 279 return REQ_NOACTION; 280 } 281 282 /* 283 * provisional rewrite saf 284 */ 285 int simple_rewrite(pblock *pb, Session *sn, Request *rq) { 286 char *from = pblock_findval("from", pb); 287 char *root = pblock_findval("root", pb); 288 char *path = pblock_findval("path", pb); 289 char *name = pblock_findval("name", pb); 290 291 if(!from || !path || !root) { 292 log_ereport(LOG_MISCONFIG, "simple-rewrite: missing parameter (from, root, path)"); 293 return REQ_ABORTED; 294 } 295 296 if(nametrans_set_vfs(pb, sn, rq)) { 297 log_ereport(LOG_FAILURE, "simple-rewrite: cannot create VFS: from=%s root=%s path=%s name=%s", from, root, path, name); 298 return REQ_ABORTED; 299 } 300 301 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 302 cxstring u = cx_str(uri); 303 cxstring f = cx_str(from); 304 if(cx_strprefix(u, f)) { 305 cxstring suf = cx_strsubs(u, f.length); 306 cxmutstr ppath = cx_strcat(2, cx_str(path), suf); 307 308 request_set_path(cx_str(root), (cxstring){ppath.ptr, ppath.length}, rq->vars); 309 free(ppath.ptr); 310 311 if(name) { 312 // add object to rq->vars 313 pblock_kvinsert(pb_key_name, name, strlen(name), rq->vars); 314 } 315 } 316 317 return REQ_NOACTION; 318 } 319