--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/safs/service.c Sat Jan 14 13:53:44 2012 +0100 @@ -0,0 +1,227 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 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 <errno.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 <sys/sendfile.h> +#include "../util/strbuf.h" + +// TODO: system sendfile Abstraktionen in neue Datei auslagern +/* +ssize_t sys_sendfile(int out_fd, int in_fd, off_t *off, size_t len) { + +} +*/ +#define sys_sendfile sendfile + + +/* + * prepares for servicing a file + * + * adds content-length header and starts the response + * + * return the file descriptor or an error code + */ +int prepare_service_file(Session *sn, Request *rq) { + char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); + + /* open the file */ + int fd = open(ppath, O_RDONLY); + if(fd < 0) { + perror("prepare_service_file: open"); + + int status = 500; + switch(errno) { + case EACCES: { + status = 403; + break; + } + case ENOENT: { + status = 404; + break; + } + } + protocol_status(sn, rq, status, NULL); + return -1; + } + + /* get stat */ + struct stat stat; + if (fstat(fd, &stat) != 0) { + perror("prepare_service_file: stat"); + + protocol_status(sn, rq, 500, NULL); + return -1; + } + + /* add content-length header*/ + char contentLength[32]; + int len = snprintf(contentLength, 32, "%d", stat.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) { + printf("test_service\n"); + + // request body test begin + char *ctval = pblock_findkeyval(pb_key_content_length, rq->headers); + if(ctval != NULL) { + printf("read request body\n"); + + printf("netbuf{%d}\n", sn->inbuf); + + int c; + while((c = netbuf_getc(sn->inbuf)) != IO_EOF) { + putchar(c); + } + printf("\n"); + } + + + // end test + + int fd = prepare_service_file(sn, rq); + if(fd < 0) { + /* TODO: service error */ + http_start_response(sn, rq); + return REQ_PROCEED; + } + + /* send file*/ + SystemIOStream *io = (SystemIOStream*) sn->csd; + + off_t fileoffset = 0; + int len = atoi(pblock_findkeyval(pb_key_content_length, rq->srvhdrs)); + printf("content-length: %d\n", len); + sendfile(io->fd, fd, &fileoffset, len); + + close(fd); + + return REQ_PROCEED; +} + +int service_hello(pblock *pb, Session *sn, Request *rq) { + 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 */ + int fd = open(ppath, O_RDONLY); + if(fd < 0) { + perror("service_index: open"); + + int status = 500; + switch(errno) { + case EACCES: { + status = 403; + break; + } + case ENOENT: { + status = 404; + break; + } + } + protocol_status(sn, rq, status, NULL); + printf("REQ_ABORTED\n"); + return REQ_ABORTED; + } + + DIR *dir = fdopendir(fd); + if(dir == NULL) { + protocol_status(sn, rq, 500, NULL); + printf("DIR is null\n"); + 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"); + + struct dirent *f; + while((f = readdir(dir)) != NULL) { + if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) { + continue; + } + + sstr_t filename = sstr(f->d_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 */ + closedir(dir); + + return REQ_PROCEED; +}