added access log

Wed, 02 Jan 2013 16:03:50 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 02 Jan 2013 16:03:50 +0100
changeset 45
a24aa388f02f
parent 44
3da1f7b6847f
child 46
636e05eb48f6

added access log

Makefile file | annotate | diff | comparison | revisions
make/install.mk file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/server/Makefile file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.h file | annotate | diff | comparison | revisions
src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/log.h file | annotate | diff | comparison | revisions
src/server/daemon/protocol.c file | annotate | diff | comparison | revisions
src/server/daemon/vserver.c file | annotate | diff | comparison | revisions
src/server/daemon/vserver.h file | annotate | diff | comparison | revisions
src/server/daemon/ws-fn.c file | annotate | diff | comparison | revisions
src/server/safs/addlog.c file | annotate | diff | comparison | revisions
src/server/safs/addlog.h file | annotate | diff | comparison | revisions
src/server/safs/objs.mk file | annotate | diff | comparison | revisions
src/server/webdav/objs.mk file | annotate | diff | comparison | revisions
templates/config/obj.conf file | annotate | diff | comparison | revisions
templates/config/server.template file | annotate | diff | comparison | revisions
--- a/Makefile	Tue Jan 01 19:22:56 2013 +0100
+++ b/Makefile	Wed Jan 02 16:03:50 2013 +0100
@@ -39,6 +39,10 @@
 	rm -f -R build
 	rm -f -R work
 
-install:
+cleanbuild:
+	@echo "clean build"
+	rm -f -R build
+
+install: all
 	cd make; $(MAKE) -f install.mk install
 
--- a/make/install.mk	Tue Jan 01 19:22:56 2013 +0100
+++ b/make/install.mk	Wed Jan 02 16:03:50 2013 +0100
@@ -53,7 +53,7 @@
 	sed s:%%WS_INSTALL_DIR%%:$(INSTALL_DIR):g ../templates/bin/startserv.template > $(INSTALL_DIR)/bin/startserv
 	chmod +x $(INSTALL_DIR)/bin/startserv
 	sed s:%%WS_INSTALL_DIR%%:$(INSTALL_DIR):g ../templates/bin/stopserv.template > $(INSTALL_DIR)/bin/stopserv
-	chmod -x $(INSTALL_DIR)/bin/stopserv
+	chmod +x $(INSTALL_DIR)/bin/stopserv
 	sed s:%%WS_INSTALL_DIR%%:$(INSTALL_DIR):g ../templates/bin/reconfig.template > $(INSTALL_DIR)/bin/reconfig
 	chmod -x $(INSTALL_DIR)/bin/reconfig
 	@echo "copy docs"
--- a/src/Makefile	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/Makefile	Wed Jan 02 16:03:50 2013 +0100
@@ -30,4 +30,3 @@
 
 all:
 	cd server; $(MAKE) all
-
--- a/src/server/Makefile	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/Makefile	Wed Jan 02 16:03:50 2013 +0100
@@ -1,7 +1,7 @@
 #
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 #
-# Copyright 2011 Olaf Wintermann. All rights reserved.
+# 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:
--- a/src/server/daemon/config.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/config.c	Wed Jan 02 16:03:50 2013 +0100
@@ -180,6 +180,12 @@
         return NULL;
     }
     
+    list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9));
+    UCX_FOREACH(UcxList*, list, elm) {
+        ServerConfigObject *scfgobj = elm->data;
+        cfg_handle_accesslog(serverconfig, scfgobj);
+    }
+    
     list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6));
     UCX_FOREACH(UcxList*, list, elm) {
         ServerConfigObject *scfgobj = elm->data;
@@ -376,6 +382,25 @@
     return ret;
 }
 
+int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) {
+    // TODO: use a name to identify the log file
+    
+    sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File"));
+    if(file.ptr == NULL) {
+        return 0;
+    }
+    sstr_t format;
+    format.ptr = NULL; 
+    
+    AccessLog *log = get_access_log(file, format);
+    if(log) {
+        // access logs are only stored in the server config to free them
+        cfg->logfiles = ucx_list_append(cfg->logfiles, log);
+    }
+    
+    return 0;
+}
+
 int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) {
     sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name"));
     sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type"));
@@ -493,6 +518,10 @@
     }
     vs->objectfile = sstrdup(file); // TODO: pool
     vs->objects = (HTTPObjectConfig*)f->data; // TODO: ref
+    
+    // set the access log for the virtual server
+    // TODO: don't use always the default
+    vs->log = get_default_access_log();
 
     ucx_map_sstr_put(cfg->host_vs, vs->host, vs);
     
--- a/src/server/daemon/config.h	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/config.h	Wed Jan 02 16:03:50 2013 +0100
@@ -86,6 +86,8 @@
 
 int cfg_handle_eventhandler(ServerConfiguration *cfg, ServerConfigObject *obj);
 
+int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj);
+
 int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj);
 
 int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj);
--- a/src/server/daemon/httprequest.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/httprequest.c	Wed Jan 02 16:03:50 2013 +0100
@@ -110,6 +110,12 @@
 
     /* Pass request line as "clf-request" */
     /* TODO: with or without \r\n ? */
+    // hack to remove \r\n 
+    sstr_t clfreq = request->request_line;
+    while(clfreq.ptr[clfreq.length - 1] < 33) {
+        clfreq.length--;
+    }
+    request->request_line = clfreq;
     pblock_kvinsert(
             pb_key_clf_request,
             request->request_line.ptr,
@@ -348,6 +354,10 @@
             }
             case NSAPIAddLog: {
                 //printf(">>> AddLog\n");
+                r = nsapi_addlog(sn, rq);
+                if(r != REQ_PROCESSING && r != REQ_ABORTED) {
+                    break;
+                }
                 rq->phase++;
                 nsapi_context_next_stage(&rq->context);
             }
@@ -669,6 +679,43 @@
     return ret;
 }
 
+int nsapi_addlog(NSAPISession *sn, NSAPIRequest *rq) {
+    //printf("nsapi_addlog\n");
+    httpd_objset *objset = rq->rq.os;
+
+    if(NCX_OI(rq) == -1) {
+        NCX_OI(rq) = objset->pos - 1;
+    }
+
+    int ret = rq->context.last_req_code;
+    for(int i=NCX_OI(rq);i>=0;i--) {
+        httpd_object *obj = objset->obj[i];
+        dtable *dt = object_get_dtable(obj, NSAPIAddLog);
+
+        // execute directives
+        for(int j=NCX_DI(rq);j<dt->ndir;j++) {
+            if(ret == REQ_NOACTION) {
+                directive *d = dt->dirs[j];
+                ret = nsapi_exec(d, sn, rq);
+            }
+            
+            if(ret != REQ_NOACTION) {
+                if(ret == REQ_PROCESSING) {
+                    /* save nsapi context */
+                    rq->context.objset_index = i;
+
+                    /* add +1 to start next round with next function */
+                    rq->context.dtable_index = j + 1;
+                }
+
+                return ret;
+            }
+        }
+    }
+
+    return REQ_PROCEED;
+}
+
 struct _tpd_data {
     NSAPISession *sn;
     NSAPIRequest *rq;
--- a/src/server/daemon/httprequest.h	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/httprequest.h	Wed Jan 02 16:03:50 2013 +0100
@@ -91,6 +91,7 @@
 int nsapi_pathcheck(NSAPISession *sn, NSAPIRequest *rq);
 int nsapi_objecttype(NSAPISession *sn, NSAPIRequest *rq);
 int nsapi_service(NSAPISession *sn, NSAPIRequest *rq);
+int nsapi_addlog(NSAPISession *sn, NSAPIRequest *rq);
 
 int nsapi_exec(directive *d, NSAPISession *sn, NSAPIRequest *rq);
 
--- a/src/server/daemon/log.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/log.c	Wed Jan 02 16:03:50 2013 +0100
@@ -40,16 +40,24 @@
 #include "log.h"
 #include "../util/strbuf.h"
 #include "../util/io.h"
-
-int is_initialized = 0;
+#include "../ucx/map.h"
 
-int log_file_fd;
-int log_level = 0;
+static int is_initialized = 0;
+
+static int log_file_fd;
+static int log_level = 0;
 
 /*
  * if the log file is uninitialized, output is written to the ui_buffer
  */
-sbuf_t *ui_buffer = NULL;
+static sbuf_t *ui_buffer = NULL;
+
+/*
+ * access logfile map
+ */
+static UcxMap    *access_log_files; // map of AccessLog*
+static AccessLog *default_access_log;
+
 
 char *log_date_month[] = {
     "Jan",
@@ -215,3 +223,57 @@
     
     return 0;
 }
+
+
+/*
+ * access log
+ * This source file only manages access log files. IO is performed directly
+ * by AddLog safs. 
+ */
+AccessLog* get_access_log(sstr_t file, sstr_t format) {
+    if(!access_log_files) {
+        access_log_files = ucx_map_new(4);
+    }
+    
+    if(file.ptr == NULL || file.length == 0) {
+        return NULL;
+    }
+    
+    AccessLog *log = ucx_map_sstr_get(access_log_files, file);
+    if(log != NULL) {
+        // TODO: ref
+        return log;
+    }
+    
+    // the log file is not opened
+    // check first if we can open it
+    sstr_t path = sstrdup(file);
+    FILE *out = fopen(path.ptr, "a");
+    if(out == NULL) {
+        free(path.ptr);
+        return NULL;
+    }
+    
+    // create access log object
+    log = calloc(1, sizeof(AccessLog));
+    log->file = path;
+    if(format.ptr != NULL) {
+        log->format = sstrdup(format);
+    }
+    log->log = out;
+    // TODO: log->ref = 1;
+    
+    // add access log to the map
+    ucx_map_sstr_put(access_log_files, file, log);
+    
+    if(!default_access_log) {
+        default_access_log = log;
+    }
+    
+    return log;
+}
+
+AccessLog* get_default_access_log() {
+    // TODO: ref
+    return default_access_log;
+}
--- a/src/server/daemon/log.h	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/log.h	Wed Jan 02 16:03:50 2013 +0100
@@ -32,6 +32,8 @@
 #include "../public/nsapi.h"
 #include "../ucx/string.h"
 
+#include <inttypes.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -46,7 +48,15 @@
     int    log_stdout;
     int    log_stderr;
 } LogConfig;
-    
+
+typedef struct {
+    sstr_t   file;
+    sstr_t   format; // unused
+    FILE     *log;
+    uint32_t ref;
+} AccessLog;
+
+// server logging
 int init_log_file(LogConfig *cfg);
 
 void log_uninitialized_writeln(char *str, size_t len);
@@ -57,6 +67,11 @@
 
 int log_ereport(int degree, const char *format, ...);
 
+// access logging
+AccessLog* get_access_log(sstr_t file, sstr_t format);
+AccessLog* get_default_access_log();
+
+// TODO: ref/unref
 
 #ifdef	__cplusplus
 }
--- a/src/server/daemon/protocol.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/protocol.c	Wed Jan 02 16:03:50 2013 +0100
@@ -248,7 +248,7 @@
 
     for(int i=0;i<h->hsize;i++) {
         p = h->ht[i];
-        while(p != NULL) {
+        while(p != NULL) {           
             /* from http.cpp */
             const pb_key *key = PARAM_KEY(p->param);
             if (key == pb_key_status || key == pb_key_server || key == pb_key_date) {
@@ -262,6 +262,7 @@
             char *value = p->param->value;
 
             /* make first char of name uppercase */
+            // TODO: don't modify the headers
             if(name[0] > 90) {
                 name[0] -= 32;
             }
@@ -288,7 +289,7 @@
     flags = fcntl(fd, F_GETFL, 0);
     fcntl(fd, F_SETFL, flags ^ O_NONBLOCK);
 
-    /* iovec output buffer */
+    /* output buffer */
     sbuf_t *out = sbuf_new(512);
 
     /* add the http status line to the output buffer */
--- a/src/server/daemon/vserver.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/vserver.c	Wed Jan 02 16:03:50 2013 +0100
@@ -32,6 +32,7 @@
     VirtualServer *vs = malloc(sizeof(VirtualServer));
     vs->objects = NULL;
     vs->document_root = sstr("docs");
+    vs->log = NULL;
     vs->ref = 1;
     return vs;
 }
@@ -43,6 +44,7 @@
     newvs->host = sstrdup_pool(pool, vs->host);
     newvs->name = sstrdup_pool(pool, vs->name);
     newvs->objectfile = sstrdup_pool(pool, vs->objectfile);
+    newvs->log = vs->log; // TODO: ref
     
     newvs->objects = vs->objects;
     
--- a/src/server/daemon/vserver.h	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/vserver.h	Wed Jan 02 16:03:50 2013 +0100
@@ -34,6 +34,8 @@
 
 #include "../ucx/string.h"
 
+#include "log.h"
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -48,6 +50,8 @@
 
     sstr_t            document_root;
     
+    AccessLog         *log;
+    
     uint32_t          ref; // reference counter
 };
 
--- a/src/server/daemon/ws-fn.c	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/daemon/ws-fn.c	Wed Jan 02 16:03:50 2013 +0100
@@ -35,6 +35,7 @@
 #include "../safs/service.h"
 #include "../safs/init.h"
 #include "../safs/common.h"
+#include "../safs/addlog.h"
 #include "../webdav/webdav.h"
 
 #include "../admin/adminui.h"
@@ -55,5 +56,6 @@
     { "auth-db", auth_db, NULL, 0 },
     { "require-auth", require_auth, NULL, 0},
     { "print-message", print_message, NULL, 0},
+    { "common-log", common_log, NULL, 0},
     {NULL, NULL, NULL, 0}
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/safs/addlog.c	Wed Jan 02 16:03:50 2013 +0100
@@ -0,0 +1,88 @@
+/*
+ * 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 <stdlib.h>
+
+#include "addlog.h"
+
+#include "../daemon/request.h"
+#include "../daemon/vserver.h"
+#include "../daemon/log.h"
+
+int common_log(pblock *pb, Session *sn, Request *rq) {
+    NSAPIRequest *request = (NSAPIRequest*)rq;
+    VirtualServer *vs = request->vs;
+    AccessLog *log = vs->log;
+    
+    if(log == NULL) {
+        return REQ_NOACTION;
+    }
+    
+    char *ip = pblock_findval("ip", sn->client);
+    char *user = pblock_findval("auth-user", rq->vars);
+    time_t t = time(NULL);
+    char *time = ctime(&t);
+    char *req = pblock_findval("clf-request", rq->reqpb);
+    
+    // hack to get the content length
+    // http_start_response should not modify the header names
+    char *len = pblock_findval("Content-length", rq->srvhdrs);
+    
+    if(!ip) {
+        ip = "-";
+    }
+    if(!user) {
+        user = "-";
+    }
+    if(!len) {
+        len = "0";
+    }
+    
+    // remove trailing line feed
+    sstr_t tmstr = sstr(time);
+    if(tmstr.ptr[tmstr.length-1] == '\n') {
+        tmstr.length--;
+    }
+    tmstr = sstrdup_pool(sn->pool, tmstr);
+    
+    fprintf(
+            log->log,
+            "%s - %s [%s] \"%s\" %d %s\n",
+            ip,
+            user,
+            tmstr.ptr,
+            req,
+            rq->status_num,
+            len);
+    fflush(log->log);
+    
+    
+    return REQ_PROCEED;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/safs/addlog.h	Wed Jan 02 16:03:50 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef ADDLOG_H
+#define	ADDLOG_H
+
+#include "../public/nsapi.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int common_log(pblock *pb, Session *sn, Request *rq);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ADDLOG_H */
+
--- a/src/server/safs/objs.mk	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/safs/objs.mk	Wed Jan 02 16:03:50 2013 +0100
@@ -37,6 +37,7 @@
 SAFOBJ += auth.o
 SAFOBJ += pathcheck.o
 SAFOBJ += common.o
+SAFOBJ += addlog.o
 
 SAFOBJS = $(SAFOBJ:%=$(SAFS_OBJPRE)%)
 SAFSOURCE = $(SAFOBJ:%.o=safs/%.c)
--- a/src/server/webdav/objs.mk	Tue Jan 01 19:22:56 2013 +0100
+++ b/src/server/webdav/objs.mk	Wed Jan 02 16:03:50 2013 +0100
@@ -26,7 +26,7 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-DAV_SRC_DIR = server/safs/
+DAV_SRC_DIR = server/webdav/
 
 DAV_OBJPRE = $(OBJ_DIR)$(DAV_SRC_DIR)
 
--- a/templates/config/obj.conf	Tue Jan 01 19:22:56 2013 +0100
+++ b/templates/config/obj.conf	Wed Jan 02 16:03:50 2013 +0100
@@ -10,6 +10,7 @@
 Service fn="send-options" method="OPTIONS"
 Service fn="common-index" type="internal/directory"
 Service fn="send-file"
+AddLog fn="common-log"
 </Object>
 
 <Object name="hello">
--- a/templates/config/server.template	Tue Jan 01 19:22:56 2013 +0100
+++ b/templates/config/server.template	Wed Jan 02 16:03:50 2013 +0100
@@ -13,6 +13,10 @@
 	Level       INFO
 </LogFile>
 
+<AccessLog>
+	File        logs/access
+</AccessLog>
+
 <EventHandler>
     Name        default
     Threads     1
@@ -25,11 +29,6 @@
     MaxThreads  32
 </Threadpool>
 
-<AuthDB>
-    Name        keyfile
-    Type        keyfile
-</AuthDB>
-
 <Listener>
     Name        http-listener-1
     Port        9090

mercurial