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 """