r5592 - in trunk/varnish-cache: bin/varnishtest/tests lib/libvmod_std
phk at varnish-cache.org
phk at varnish-cache.org
Sun Nov 28 15:50:55 CET 2010
Author: phk
Date: 2010-11-28 15:50:54 +0100 (Sun, 28 Nov 2010)
New Revision: 5592
Added:
trunk/varnish-cache/bin/varnishtest/tests/m00004.vtc
trunk/varnish-cache/lib/libvmod_std/vmod_std_fileread.c
Modified:
trunk/varnish-cache/lib/libvmod_std/Makefile.am
trunk/varnish-cache/lib/libvmod_std/vmod.vcc
Log:
Add the
STRING vmod_std.fileread(STRING filename)
function, which will read the contents of a file, typically
for use in synthetic responses.
Submitted by: Sanjoy Das
Added: trunk/varnish-cache/bin/varnishtest/tests/m00004.vtc
===================================================================
--- trunk/varnish-cache/bin/varnishtest/tests/m00004.vtc (rev 0)
+++ trunk/varnish-cache/bin/varnishtest/tests/m00004.vtc 2010-11-28 14:50:54 UTC (rev 5592)
@@ -0,0 +1,117 @@
+# $Id$
+# XXX: filenames should really contain m00004 for disambiguation
+
+test "Test fileread for std VMOD"
+
+shell {
+ echo -n "File One" > "${tmpdir}/file_one"
+ echo -n "File Two" > "${tmpdir}/file_two"
+ echo -n "File Three" > "${tmpdir}/file_three"
+}
+
+server s1 {
+ loop 3 {
+ rxreq
+ txresp -hdr "foo: bar" -bodylen 4
+ }
+} -start
+
+varnish v1 -arg "-pvmod_dir=${topbuild}/lib/libvmod_std/.libs/" \
+ -vcl+backend {
+ import std;
+
+ sub vcl_deliver {
+ if (req.url == "/one") {
+ set resp.http.one = std.fileread("${tmpdir}/file_one");
+ } else if (req.url == "/two") {
+ set resp.http.two = std.fileread("${tmpdir}/file_two");
+ } else if (req.url == "/three") {
+ set resp.http.three = std.fileread("${tmpdir}/file_three");
+ }
+ }
+} -start
+
+client c1 {
+ loop 5 {
+ txreq -url "/one"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.one == "File One"
+ }
+
+ loop 5 {
+ txreq -url "/two"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.two == "File Two"
+
+ txreq -url "/three"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.three == "File Three"
+ }
+}
+
+client c2 {
+ loop 5 {
+ txreq -url "/two"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.two == "File Two"
+ }
+
+ loop 5 {
+ txreq -url "/one"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.one == "File One"
+
+ txreq -url "/three"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.three == "File Three"
+ }
+}
+
+client c3 {
+ loop 5 {
+ txreq -url "/three"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.three == "File Three"
+ }
+
+ loop 5 {
+ txreq -url "/two"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.two == "File Two"
+
+ txreq -url "/one"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.content-length == "4"
+ expect resp.http.foo == "bar"
+ expect resp.http.one == "File One"
+ }
+}
+
+client c1 -run
+client c2 -run
+client c3 -run
Modified: trunk/varnish-cache/lib/libvmod_std/Makefile.am
===================================================================
--- trunk/varnish-cache/lib/libvmod_std/Makefile.am 2010-11-26 11:43:30 UTC (rev 5591)
+++ trunk/varnish-cache/lib/libvmod_std/Makefile.am 2010-11-28 14:50:54 UTC (rev 5592)
@@ -9,7 +9,8 @@
libvmod_std_la_SOURCES = \
vcc_if.c \
vcc_if.h \
- vmod_std.c
+ vmod_std.c \
+ vmod_std_fileread.c
vcc_if.c vcc_if.h: $(top_srcdir)/lib/libvmod_std/vmod.py $(top_srcdir)/lib/libvmod_std/vmod.vcc
@PYTHON@ $(top_srcdir)/lib/libvmod_std/vmod.py $(top_srcdir)/lib/libvmod_std/vmod.vcc
Modified: trunk/varnish-cache/lib/libvmod_std/vmod.vcc
===================================================================
--- trunk/varnish-cache/lib/libvmod_std/vmod.vcc 2010-11-26 11:43:30 UTC (rev 5591)
+++ trunk/varnish-cache/lib/libvmod_std/vmod.vcc 2010-11-28 14:50:54 UTC (rev 5592)
@@ -33,3 +33,4 @@
Function REAL random(REAL, REAL)
Function VOID log(STRING_LIST)
Function VOID syslog(INT, STRING_LIST)
+Function STRING fileread(PRIV_CALL, STRING)
Added: trunk/varnish-cache/lib/libvmod_std/vmod_std_fileread.c
===================================================================
--- trunk/varnish-cache/lib/libvmod_std/vmod_std_fileread.c (rev 0)
+++ trunk/varnish-cache/lib/libvmod_std/vmod_std_fileread.c 2010-11-28 14:50:54 UTC (rev 5592)
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2010 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Sanjoy Das <sanjoy at playingwithpointers.com>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * XXX: It might make sense to use just a single global list of all files
+ * XXX: and use the call-private pointer to point to the file instance on
+ * XXX: that list.
+ * XXX: Duplicates in the global list can be avoided by examining the
+ * XXX: dev+inode fields of the stat structure.
+ * XXX: Individual files would need to be refcounted, so they can be
+ * XXX: deleted when no VCL's reference them.
+ *
+ * XXX: We should periodically stat(2) the filename and check if the
+ * XXX: underlying file has been updated.
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "vrt.h"
+#include "../../bin/varnishd/cache.h"
+
+#include "vcc_if.h"
+
+VSLIST_HEAD(cached_file_list, cached_file);
+
+struct cached_file {
+ unsigned magic;
+#define CACHED_FILE_MAGIC 0xa8e9d87a
+ char *file_name;
+ char *contents;
+ time_t last_modification;
+ off_t file_sz;
+ VSLIST_ENTRY(cached_file) next;
+};
+
+static void
+free_cached_files(void *file_list)
+{
+ struct cached_file *iter, *tmp;
+ struct cached_file_list *list = file_list;
+ VSLIST_FOREACH_SAFE(iter, list, next, tmp) {
+ CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+ free(iter->file_name);
+ free(iter->contents);
+ FREE_OBJ(iter);
+ }
+ free(file_list);
+}
+
+static pthread_rwlock_t filelist_lock = PTHREAD_RWLOCK_INITIALIZER;
+static int filelist_update = 0;
+
+const char *
+vmod_fileread(struct sess *sp, struct vmod_priv *priv, const char *file_name)
+{
+ struct cached_file *iter = NULL;
+ struct stat buf;
+ struct cached_file_list *list;
+ int fd, my_filelist_update;
+
+ (void)sp;
+
+ AZ(pthread_rwlock_rdlock(&filelist_lock));
+
+ if (priv->free == NULL) {
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+ /*
+ * Another thread may already have initialized priv
+ * here, making the repeat check necessary.
+ */
+ AZ(pthread_rwlock_wrlock(&filelist_lock));
+ if (priv->free == NULL) {
+ priv->free = free_cached_files;
+ priv->priv = malloc(sizeof(struct cached_file_list));
+ AN(priv->priv);
+ list = priv->priv;
+ VSLIST_INIT(list);
+ }
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+ AZ(pthread_rwlock_rdlock(&filelist_lock));
+ } else {
+ list = priv->priv;
+ VSLIST_FOREACH(iter, list, next) {
+ CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+ if (strcmp(iter->file_name, file_name) == 0) {
+ /* This thread was holding a read lock. */
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+ return iter->contents;
+ }
+ }
+ }
+
+ my_filelist_update = filelist_update;
+
+ /* This thread was holding a read lock. */
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+
+ if ((fd = open(file_name, O_RDONLY)) == -1)
+ return "";
+
+ fstat(fd, &buf);
+
+ AZ(pthread_rwlock_wrlock(&filelist_lock));
+
+ if (my_filelist_update != filelist_update) {
+
+ /*
+ * Small optimization: search through the linked list again
+ * only if something has been changed.
+ */
+ VSLIST_FOREACH(iter, list, next) {
+ CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+ if (strcmp(iter->file_name, file_name) == 0) {
+ /* This thread was holding a write lock. */
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+ return iter->contents;
+ }
+ }
+ }
+
+ ALLOC_OBJ(iter, CACHED_FILE_MAGIC);
+ AN(iter);
+
+ iter->file_name = strdup(file_name);
+ iter->last_modification = buf.st_mtime;
+
+ iter->contents = malloc(buf.st_size + 1);
+ AN(iter->contents);
+ iter->file_sz = read(fd, iter->contents, buf.st_size);
+ assert(iter->file_sz == buf.st_size);
+ AZ(close(fd));
+
+ iter->contents[iter->file_sz] = '\0';
+
+ VSLIST_INSERT_HEAD(list, iter, next);
+
+ filelist_update++;
+
+ /* This thread was holding a write lock. */
+ AZ(pthread_rwlock_unlock(&filelist_lock));
+ return iter->contents;
+}
More information about the varnish-commit
mailing list