vmod_file
allows for Varnish to act as a file server as well as a means to
interact with the file system from VCL.
The backend allows the serving of static files through Varnish. The backend request URL is appended to the vmod’s root directory to form a file path. If the file path resolves to a regular file and is readable to the Varnish child process, it is used as the source for this backend fetch operation. Files served this way are treated in the same manner as if they were fetched from a real backend, and so will be cached in memory according to the current configuration. TTL, grace and keep works just like it would normally as well.
The following headers are added based on the resolved files
attributes: Last-Modified
, Content-type
and Content-Length
.
If the file could not be read for any reason (e.g. not found, access restrictions or resolved outside of the root directory of the vmod), an appropriate error response is synthesized.
This VMOD includes a standard set of file operations and an ACL.
All file objects must allow at least one path in the ACL. To use executable
files, a mode of x
, varnishd
must be started with -p allow_exec=true
.
import file;
sub vcl_init {
new root = file.init("/var/www/html/");
}
sub vcl_backend_fetch {
# Set the file system as the backend
set bereq.backend = root.backend();
}
import file;
sub vcl_init {
new fs = file.init();
fs.allow("/usr/bin/uptime", "x");
}
sub vcl_recv {
if (req.method == "UPTIME") {
return (synth(200, "UPTIME"));
}
}
sub vcl_synth {
if (resp.reason == "UPTIME") {
synthetic(fs.exec("/usr/bin/uptime"));
if (fs.exec_get_errorcode() != 0) {
set resp.status = 404;
}
return (deliver);
}
}
OBJECT file.init(STRING rootdir = NULL, STRING mimedb = "/etc/mime.types", BOOL disable_symlinks = false)
Description
Creates a file system root. The rootdir
is the base of the file system hierarchy.
Return
An object to reference the file system through.
roodir
(Optional) The path of the root directory. When set, each path used in the functions bellow (except for .exec()
) will
be prepended with this root directory. Otherwise each path will be considered absolute or relative,
depending on a leading slash. Defaults to NULL
.
mimedb
The path to the mimedb. Defaults to /etc/mime.types
.
disable_symlinks
Should symlinks be allowed in any of the function calls below? Defaults to false
.
BACKEND .backend()
Description
Return a backend reference to this root for use during fetch.
Return
A backend object for varnish to get the file from.
VOID .allow(STRING path, STRING mode = "r")
Description
Allow path
to be accessed from functions that access files through mode
.
At least one path must be added to allow for the object to work correctly.
path
The path to add to allow access to. This path can be a glob.
mode
(Optional) What type of access should this file have? This can be any combination of read (r
),
write (w
), or execute (x
). Defaults to r
.
VOID .deny(STRING path, STRING mode = "rwx")
Description
Deny path
access from functions that access files through mode
.
path
The path to add to deny access to. This path can be a glob.
mode
What type of access should this file have? This can be any combination of read (r
), write (w
),
or execute (x
). Defaults to rwx
.
STRING .read(STRING file, STRING def = NULL)
Description
Read file
and return it as a string. If file
does not exist or does not pass the ACL, def
is returned.
Return
A string with the contents of file
.
file
The file to read.
def
(Optional) The string to return if there was an error reading the file. Defaults to NULL
.
BLOB .read(STRING file, STRING def = NULL)
Description
Read file
and return it in a blob. If file
does not exist or does not pass the ACL, def
is returned.
Return
A blob with the contents of file
.
file
The file to read.
def
(Optional) The contents of the blob to return if there was an error reading the file. Defaults to NULL
.
VOID .read_into_synth(STRING file, STRING def = NULL)
Description
Return a file as a synthetic response body. Only accessible through vcl_synth
and vcl_backend_error
. If file
does not exist or does not pass the ACL, def
is returned.
file
The file to read.
def
The string to return if there was an error reading the file. Defaults to NULL
.
BOOL .append(STRING file, STRING str, BOOL create_path = false, INT dir_perm = 755, BOOL lock = true)
Description
Append a string, str, to a file,
file. If
create_path = trueand a directory above the
file does not exist it will be created with permission
dir_perm. Must Pass ACL. If
lock` is true
the file will be appended under a lock.
Return
The number of bytes written. On failure, return -1
.
file
The path to the file to append. If the file doesn’t exist, it will be created.
str
The contents to append to the file.
create_path
If true
, create the path to the file if any of the sub directories do not exist. Defaults to false
.
dir_perm
The permission of the directory that will be created if create_dir = true
. Defaults to 755
.
lock
If true
, the append operation will be done under a lock. Defaults to true
.
INT .write(STRING file, STRING str, BOOL create_path = false, INT dir_perm = 755)
Description
Write to a file, file
, consisting of str
. If create_path = true
and a directory above the
file does not exist it will be created with permission dir_perm
. Must Pass ACL. The file is
first written to a temporary file by appending a random string to the end of the file path
(/rootdir/file[.random_string]
). Next, the file is renamed back to the original path.
If there are multiple concurrent writers, the last write wins.
Return
The number of bytes written. On failure, return -1
.
file
The path to the file to write. If the file doesn’t exist, it will be created.
str
The contents to write to the file.
create_path
If true
, create the path to the file if any of the sub directories do not exist. Defaults to false
.
dir_perm
The permission of the directory that will be created if create_dir = true
. Defaults to 755
.
INT .write(STRING file, BLOB blb, BOOL create_path = false, INT dir_perm = 755)
Description
Write to a file, file
, with the contents of blb
. If create_path = true
and a directory above the
file does not exist it will be created with permission dir_perm
. Must Pass ACL. The file is
first written to a temporary file by appending a random string to the end of the file path
(/rootdir/file[.random_string]
). Next, the file is renamed back to the original path.
If there are multiple concurrent writers, the last write wins.
Return
The number of bytes written. On failure, return -1
.
file
The path to the file to write. If the file doesn’t exist, it will be created.
blb
The object holding the contents to write to the file.
create_path
If true
, create the path to the file if any of the sub directories do not exist. Defaults to false
.
dir_perm
The permission of the directory that will be created if create_path = true
. Defaults to 755
.
INT .write_req_body(STRING file_path, BOOL create_path = false, INT dir_perm = 755)
Description
Write to a file, file_path
, the request body. If create_path = true
and a directory above the
file does not exist it will be created with permission dir_perm
. This can only can be called in vcl_recv
.
std.cache_req_body()
must be called before using this. The file is first written to a temporary file by
appending a random string to the end of the file path (/rootdir/file[.random_string]
).
Next, the file is renamed back to the original path. If there are multiple concurrent writers, the last write wins.
Return
The number of bytes written. On failure, return -1
.
file_path
The path to the file to write. If it doesn’t exist, it will be created.
create_path
If true
, create the path to the file if any of the sub directories do not exist. Defaults to false
.
dir_perm
The permission of the directory that will be created if create_path = true
. Defaults to 755
.
BOOL .delete(STRING path, BOOL recursive = false)
Description
Delete a path
. If a directory is to be deleted, recursive
must be set to true
. path
must pass the ACL.
Return
true
on success. On failure or if the path is a directory and recursive = false
, return false
.
file
The file to delete.
STRING .exec(STRING path, STRANDS arguments = NULL, STRING checksum = NULL, DURATION timeout = 60s, BOOL output_stdout = true,
BOOL output_stderr = true, STRING def = NULL)
Description
Run a binary or script and return the output in string. Must pass the ACL. Scripts must have execute permission and contain a first line of:
#! interpreter [optional-arg]
Return
A string of the contents of the output of the binary or script.
path
The path to the binary or script. This path is always considered to be absolute.
arguments
(Optional) Arguments for the script or binary. Defaults to NULL
.
checksum
(Optional) Compare the script or binary against the given checksum. If the checksum fails.
the binary or script is not run. The checksum format is sha256 Defaults to NULL
.
timeout
(Optional) How long should the binary or script run before being timedout. If it is less than 0
the request will fail.
If it is equal to 0
never timeout. Defaults to 60s
.
output_stdout
(Optional) Should the output of stdout be returned? Defaults to true
.
output_stderr
(Optional) Should the output of stderr be returned? Defaults to true
.
deff
(Optional) String to return if there is an error. Defaults to NULL
.
INT .exec_get_errorcode()
Get the response code from the previous .exec()
call.
This value is -1
until the binary or script is called in .exec()
and produces a response code.
If .exec()
has not been called, the request will fail.
Otherwise return the response code from the .exec()
call.
BOOL .exists(STRING path, STRING mode, ENUM {FILE, DIR, BOTH} type = FILE)
Description
Check if the path
exists.
Return
Return true
if the path exists and passes the ACL, otherwise return false
.
path
The path to check if it exists.
mode
What access type should this path have? This can be any combination of read (r
), write (w
),
or execute (x
). Defaults to r
.
type
Choose to limit the scope of this function to only files, only directories or both files and directories.
Defaults to FILE
.
TIME .lastaccess(STRING path, ENUM {FILE, DIR, BOTH} type = FILE)
Description
Return the time (Unix time) that the path
was last accessed. This time is updated when the
following system functions are called: execve(2)
, mknod(2)
, pipe(2)
, utime(2)
, and read(2)
(of more than zero bytes).
Return
The time since the path had last been accessed. If path
does not exist or does not pass the ACL,
return 0
.
path
The path to get the last access time from.
type
Choose to limit the scope of this function to only files, only directories or both files and directories.
Defaults to FILE
.
TIME .lastmodified(STRING path, ENUM {FILE, DIR, BOTH} type = FILE)
Description
Return the time (Unix time) that the path
was last modified. This time is updated when the
following system functions are called: mknod(2)
, truncate(2)
, utime(2)
, and write(2)
(of more
than zero bytes).
Return
The time since the path had last been modified. If path
does not exist or does not pass the ACL
, return 0
.
path
The path to get the last modified time from.
type
Choose to limit the scope of this function to only files, only directories or both files and directories.
Defaults to FILE
.
TIME .laststatus(STRING path, ENUM {FILE, DIR, BOTH} type = FILE)
Description
Return the time (Unix time) that path
last had a status change. This time is updated by
writing or setting inode information (i.e., owner, group, link count, mode, etc.).
Return
The time since the path last had a status change. If path
does not exist or does not pass the ACL,
return 0
.
path
The path to get the last status change time from.
type
Choose to limit the scope of this function to only files, only directories or both files and directories.
Defaults to FILE
.
BYTES .size(STRING path, ENUM {FILE, DIR, BOTH} type = FILE)
Description
Return the size of the path
in bytes.
Return
The number of bytes that the file contains. If path
does not exist or does not pass the ACL, return -1
.
path
The path to get the size of.
type
Choose to limit the scope of this function to only files, only directories or both files and directories.
Defaults to FILE
.
STRING file.arg(STRING str)
Allow a string literal to be used with STRANDS so it can be read in .exec()
arguments.
The string literal in a format that can be read by strands.
arg
String literal (i.e "argument"
).
STRANDS file.split_args(STRING str)
Turn a string into a STRANDS object to be read in .exec()
arguments. The string is broken
up in two ways, by whitespace or matching quotes. Quotes will be de deliminated by a
matching quote followed by any whitespace character or the end of the string.
Both single and double quotes are supported. This can be used to pass in multiple
arguments to .exec()
.
The string broken into individual strings.
arg
String to break up. (i.e -q 'ReqURL ~ "/abcd"'
)