Fri, 28 Jun 2013 14:52:35 +0200
preparation for admin interface
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 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 <stdio.h> #include <sys/file.h> #include <sys/stat.h> #include "service.h" #include "../util/io.h" #include "../util/pblock.h" #include "../daemon/protocol.h" #include "../daemon/vfs.h" //include <sys/sendfile.h> #include "../util/strbuf.h" #include <errno.h> /* * prepares for servicing a file * * adds content-length header and starts the response * * return the opened file */ SYS_FILE prepare_service_file(Session *sn, Request *rq, struct stat *s) { char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); // open the file VFSContext *vfs = vfs_request_context(sn, rq); SYS_FILE fd = vfs_open(vfs, ppath, O_RDONLY); if(!fd) { // vfs_open sets http status code return NULL; } // get stat if(vfs_fstat(vfs, fd, s) != 0) { //perror("prepare_service_file: stat"); protocol_status(sn, rq, 500, NULL); return NULL; } // 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); vfs_close(fd); return fd; } // add content-length header char contentLength[32]; int len = snprintf(contentLength, 32, "%lld", s->st_size); pblock_kvinsert(pb_key_content_length, contentLength, len, rq->srvhdrs); // start response protocol_status(sn, rq, 200, NULL); http_start_response(sn, rq); return fd; } int send_file(pblock *pb, Session *sn, Request *rq) { struct stat s; SYS_FILE fd = prepare_service_file(sn, rq, &s); if(!fd) { // if an error occurs, prepare_service_file sets the http status code // we can just return REQ_ABORTED return REQ_ABORTED; } if(!S_ISDIR(s.st_mode)) { // send file sendfiledata sfd; sfd.fd = fd; sfd.len = s.st_size; sfd.offset = 0; sfd.header = NULL; sfd.trailer = NULL; net_sendfile(sn->csd, &sfd); } vfs_close(fd); return REQ_PROCEED; } int service_hello(pblock *pb, Session *sn, Request *rq) { pblock_removekey(pb_key_content_type, rq->srvhdrs); pblock_nvinsert("content-type", "text/plain", rq->srvhdrs); pblock_nninsert("content-length", 13, rq->srvhdrs); protocol_status(sn, rq, 200, NULL); http_start_response(sn, rq); net_write(sn->csd, "Hello World!\n", 13); return REQ_PROCEED; } int service_index(pblock *pb, Session *sn, Request *rq) { //printf("service_index\n"); char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); sstr_t r_uri = sstr(uri); // open the file VFSContext *vfs = vfs_request_context(sn, rq); VFS_DIR dir = vfs_opendir(vfs, ppath); if(!dir) { return REQ_ABORTED; } sbuf_t *out = sbuf_new(1024); // output buffer // write html header sbuf_puts(out, "<html>\n<head>\n<title>Index of "); sbuf_puts(out, uri); sbuf_puts(out, "</title>\n</head><body>\n<h1>Index of "); sbuf_puts(out, uri); sbuf_puts(out, "</h1><hr>\n\n"); // list directory VFS_ENTRY f; while(vfs_readdir(dir, &f)) { sstr_t filename = sstr(f.name); sbuf_puts(out, "<a href=\""); sbuf_append(out, r_uri); sbuf_append(out, filename); sbuf_puts(out, "\">"); sbuf_append(out, filename); sbuf_puts(out, "</a><br>\n"); } sbuf_puts(out, "\n</body>\n</html>\n"); // send stuff to client pblock_removekey(pb_key_content_type, rq->srvhdrs); pblock_kvinsert(pb_key_content_type, "text/html", 9, rq->srvhdrs); pblock_nninsert("content-length", out->length, rq->srvhdrs); protocol_status(sn, rq, 200, NULL); http_start_response(sn, rq); net_write(sn->csd, out->ptr, out->length); // close vfs_closedir(dir); sbuf_free(out); return REQ_PROCEED; } int send_options(pblock *pb, Session *sn, Request *rq) { char *allow = "HEAD, GET, PUT, DELETE, TRACE, OPTIONS, MOVE, COPY, " "PROPFIND, PROPPATCH, MKCOL, LOCK, UNLOCK, ACL, REPORT"; char *dav = "1,2,access-control"; pblock_removekey(pb_key_content_type, rq->srvhdrs); pblock_nvinsert("allow", allow, rq->srvhdrs); pblock_nvinsert("dav", dav, rq->srvhdrs); pblock_nninsert("content-length", 0, rq->srvhdrs); protocol_status(sn, rq, 200, NULL); http_start_response(sn, rq); return REQ_PROCEED; }