From 0ab8c73e07f470563d8514d26dc7f47da58f51bd Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Thu, 29 Jun 2017 15:37:51 +0200 Subject: [PATCH] nuweb: Added base libraries. Signed-off-by: Tony Tkacik --- bin/nuweb-run | 1 + inc/nuweb.inc.sh | 89 +++++++++++++++++++++++++++++++ inc/nuweb/router.inc.sh | 115 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 inc/nuweb.inc.sh create mode 100644 inc/nuweb/router.inc.sh diff --git a/bin/nuweb-run b/bin/nuweb-run index f7f7756..5d374d3 100755 --- a/bin/nuweb-run +++ b/bin/nuweb-run @@ -3,4 +3,5 @@ readonly NUWEB_BIN_DIR=$(dirname $(realpath ${BASH_SOURCE[0]})) source $NUWEB_BIN_DIR/../inc/nux-base.inc.sh +nux.use nuweb source "$1" diff --git a/inc/nuweb.inc.sh b/inc/nuweb.inc.sh new file mode 100644 index 0000000..0c94692 --- /dev/null +++ b/inc/nuweb.inc.sh @@ -0,0 +1,89 @@ +## #nuweb - Server-side HTTP scripting library for BASH +## +## *nuweb* is set of BASH function to ease implementation of CGI scripts using +## BASH. Idea behind it, is to allow for reuse of existing shell scripts +## and command-line utilities, without need to duplicate functionality. +## +## *nuweb* is based on *nux-env*, which allows large code-share with *nux-env* +## command line tools and use of *nux-env* libraries. +## +## *nuweb* is separated into several components: +## +## nuweb:: +## this library, base functionality +## nuweb/router:: router support functionality - dispatch of code +## based on path and query parameters +## nuweb/html:: +## basic support for generating HTML content +## + +## #Public functions: + +## nuweb.status:: +## Sets HTTP response status code. +## NOTE: If any content was already returned this function does not work. +## +nuweb.status() { + local code=$1; + local message=$2; + echo "HTTP/1.1 $code $message" +} + +## nuweb.content_type:: +## Sets HTTP response content type +## NOTE: If any content was already returned this function does not work. +nuweb.content_type() { + echo "Content-Type: $@" +} + +## nuweb.redirect:: [--relative] +## +nuweb.redirect() { + local prefix=""; + if [ "$1" == "--relative" ]; then + shift; + prefix="$(dirname "$SCRIPT_NAME")/" + fi + + echo Location: "$prefix$@" + echo + echo +} + +## nuweb.redirect.exec:: +## +nuweb.redirect.exec() { + if [ "$1" == "--relative" ]; then + args="--relative"; + shift; + fi + fn=$1; shift; + nuweb.redirect $args $($fn $@) +} + +## nuweb.http.query.var:: [defaultValue] +## Reads HTTP query string from variable *QUERY_STRING*, parses it and returns +## value of parameter *param* or *defaultValue*. +## +## NOTE: Currently does not perform urldecode +nuweb.http.query.var() { + local to_read=$1; + local line_separrated=$(sed "s/&/\n/g" <<< $QUERY_STRING) + + while IFS="=" read -r var value; do + if [ "$var" = "$to_read" ]; then + echo "$value" + return; + fi + done <<< "$line_separrated" + echo $2 +} + +## nuweb.http.query.to_var:: +## +nuweb.http.query.to_var() { + local line_separrated=$(sed "s/&/\n/g" <<< $QUERY_STRING) + while IFS="=" read -r var value; do + declare -x "nuweb_QUERY_$var"="$value" + done <<< "$line_separrated" +} diff --git a/inc/nuweb/router.inc.sh b/inc/nuweb/router.inc.sh new file mode 100644 index 0000000..fd63d26 --- /dev/null +++ b/inc/nuweb/router.inc.sh @@ -0,0 +1,115 @@ + + +## +## #Path specification format +## +## Path specification is written as standard path: +## *path_spec*[?*query_spec*] +## Where: +## *path_spec* is standard HTTP path separated with */* and following special +## characters: +## **@** - Required path component, it is captured as positional argument +## **@+** - Required path component, capture current and all subsequent +## components as path. Path is positional argument. +## *query_spec* is optional and allows for matching values of query arguments +## or transforming query arguments into positional arguments. It is written +## in form "?arg1=valueDef&arg2=valueDef" +## Following special characters are supported: +## **@** - Required argument, capture value as positional argument. +## **?@** - Optional argument, capture value as positional argument. +## +## +nuweb.router.tryexec.concrete() { + full_spec=$1; + path_spec=${full_spec%%\?*} + query_spec=${full_spec#$path_spec} + query_spec=${query_spec#\?} + + func=$2; + shift; shift; + echo "Checking Path Spec: '$path_spec', Query Spec: '$query_spec' Function:$func Additional Args:$@" >&2 + + IFS='/' read -ra spec_components <<< "$path_spec" + i=0 + path_args="" + path_c=""; + for path in "${PATH_COMPONENTS[@]}" ; do + spec=${spec_components[$i]} + if [ "$spec" == "@+" ]; then + consume="consume" + fi + if [ -n "$consume" ]; then + path_c="$path_c/$path" + elif [ "$spec" == "@" ]; then + path_args="$path_args $path"; + elif [ "$spec" != "$path" ] ; then + return -1 + fi + let i=$i+1 + done + if [ $i -lt "${#spec_components[@]}" ] ; then + return -1; + fi + if [ -n "$query_spec" ]; then + IFS='&' read -ra query_components <<< "$query_spec" + for varDef in "${query_components[@]}" ; do + IFS='=' read -r var valueDef <<< "$varDef" + value=$(nuweb.http.query.var $var) + #echo $var $valueDef $value >&2; + if [ "$valueDef" == "?@" ]; then + query_args="$query_args $value" + else + if [ -z "$value" ]; then + #echo "$def $value is empty." >&2; + return -1; + elif [ "$valueDef" == "@" ]; then + query_args="$query_args $value" + elif [ "$value" != "$valueDef" ]; then + #echo "$def $value != $valueDef" >&2; + return -1; + fi + fi + done + fi + $func $@ $path_args $path_c $query_args + exit 0 + +} + + +nuweb.get() { + nuweb.router.tryexec.concrete $@; +} + + +## +## nuweb.router.exec:: [path] +## Parses *path* and executes functions as defined in *definition*. +## *definition* is name of *function* which contains specific route patterns. +## *path* is HTTP path, for which router should parse arguments. If path is +## not specified, *PATH_INFO* will be used instead. +## +nuweb.router.exec() { + local definition="$1"; + local path="$2"; + + if [ -z "$path" ] ; then + path="$PATH_INFO" + fi + if [ -z "$path" ] ; then + path="/" + fi + + IFS='/' read -ra PATH_COMPONENTS <<< "$path" + + $definition + + nuweb.status 404 NOT FOUND + nuweb.content_type text/plain + echo """ + + Status:404 + Path $PATH_INFO Not found. + + """ +}