diff --git a/doc/MANUAL.md b/doc/MANUAL.md
index b67e4de..295fcc5 100644
--- a/doc/MANUAL.md
+++ b/doc/MANUAL.md
@@ -115,6 +115,10 @@ Structurally, they are made up of the following elements:
- **`title`**: Text to show at the top of each page. **Required**, **String**.
+- **`static_dir`**: Path to a directory from which static files should be
+ served. See also "[Serving static files](#output_static_files)".
+ **Optional**, **String**.
+
- **`forms`**: A list of dictionaries of form definitions. **Required**, **List
of dictionaries**.
@@ -370,6 +374,29 @@ and shown to the user in the browser.
If a script's exit code is not 0, it is assumed an error occured. Scriptform
will show the script's stderr output (in red) to the user instead of stdin.
+### Serving static files
+
+Scriptform can serve static files. It is disabled by default. To enable it,
+provide a `static_dir` option in the top section of the form configuration:
+
+ {
+ "title": "Static serve",
+ "static_dir": "static",
+ "forms": [
+ ...
+
+This tells Scriptform to serve static files from that location. To refer to a
+static file, use the `/static` URL:
+
+ https://example.com/static?fname=foobar.png
+
+Will refer to the `static/foobar.png` file. If `static_dir` is a relative path,
+it will be relative to the form configuration (.json) file you're running.
+
+Scriptform does not provide the browser with a content-type of the file, since
+it is impossible to guess. Generally, browsers do a decent job at figuring it
+out themselves.
+
## Script execution
When the user submits the form, scriptform will validate the provided values.
diff --git a/examples/static_serve/job_serve.sh b/examples/static_serve/job_serve.sh
new file mode 100755
index 0000000..61cbf72
--- /dev/null
+++ b/examples/static_serve/job_serve.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+cat <
+ENDOFTEXT
diff --git a/examples/static_serve/static/ssh_server.png b/examples/static_serve/static/ssh_server.png
new file mode 100644
index 0000000..f79c801
Binary files /dev/null and b/examples/static_serve/static/ssh_server.png differ
diff --git a/examples/static_serve/static_serve.json b/examples/static_serve/static_serve.json
new file mode 100644
index 0000000..6406920
--- /dev/null
+++ b/examples/static_serve/static_serve.json
@@ -0,0 +1,15 @@
+{
+ "title": "Static serve",
+ "static_dir": "static",
+ "forms": [
+ {
+ "name": "static_serve",
+ "title": "Serve static files",
+ "description": "This example has a script that serves a HTML page. The HTML page refers to some static files that are served by Scriptform",
+ "submit_title": "Serve",
+ "script": "job_serve.sh",
+ "output": "html",
+ "fields": []
+ }
+ ]
+}
diff --git a/src/scriptform.py b/src/scriptform.py
index 378a975..a5a46c1 100755
--- a/src/scriptform.py
+++ b/src/scriptform.py
@@ -230,11 +230,14 @@ class ScriptForm:
config = json.load(file(self.config_file, 'r'))
+ static_dir = None
forms = []
users = None
if 'users' in config:
users = config['users']
+ if 'static_dir' in config:
+ static_dir = config['static_dir']
for form in config['forms']:
form_name = form['name']
script = form['script']
@@ -253,7 +256,8 @@ class ScriptForm:
form_config = FormConfig(
config['title'],
forms,
- users
+ users,
+ static_dir
)
self.form_config_singleton = form_config
return form_config
@@ -290,10 +294,11 @@ class FormConfig:
file. It holds information (title, users, the form definitions) on the
form configuration being served by this instance of ScriptForm.
"""
- def __init__(self, title, forms, users={}):
+ def __init__(self, title, forms, users={}, static_dir=None):
self.title = title
self.users = users
self.forms = forms
+ self.static_dir = static_dir
self.log = logging.getLogger('FORMCONFIG')
# Validate scripts
@@ -1001,6 +1006,28 @@ class ScriptFormWebApp(WebAppHandler):
if os.path.exists(file_name):
os.unlink(file_name)
+ def h_static(self, fname):
+ """Serve static files"""
+ form_config = self.scriptform.get_form_config()
+
+ if not form_config.static_dir:
+ self.send_error(501, "Static file serving not enabled")
+ return
+
+ if '..' in fname:
+ self.send_error(403, "Invalid file name")
+ return
+
+ path = os.path.join(form_config.static_dir, fname)
+ print path
+ if not os.path.exists(path):
+ self.send_error(404, "Not found")
+ return
+
+ f = file(path, 'r')
+ self.send_response(200)
+ self.end_headers()
+ self.wfile.write(f.read())
class Daemon: # pragma: no cover
"""