diff --git a/README.md b/README.md
index 3ba4854..bb72bf0 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Here is some leaked source code for my brand new Cat website. Do not steal!
#!/bin/bash
source exprash.sh;
-redirectStdout 'log';
+redirect_stdout 'log';
declare -A cats;
cats[calico]="Calico";
@@ -50,11 +50,11 @@ get '/cats/*' && {
printf '
Error: Cannot find that cat
\n' | send;
}
-getError '/cats/*' && {
- printf '%s
' "$(errorMessage)" | send;
+get_error '/cats/*' && {
+ printf '%s
' "$(get_error_message)" | send;
}
-(use || useError) && {
+(use || use_error) && {
printf '404
' | send;
}
```
diff --git a/examples/cats.sh b/examples/cats.sh
index ad8f36d..f4dbc46 100644
--- a/examples/cats.sh
+++ b/examples/cats.sh
@@ -1,7 +1,7 @@
#!/bin/bash
source exprash.sh;
-redirectStdout 'log';
+redirect_stdout 'log';
declare -A cats;
cats[calico]="Calico";
@@ -39,10 +39,10 @@ get '/cats/*' && {
printf 'Error: Cannot find that cat
\n' | send;
}
-getError '/cats/*' && {
- printf '%s
' "$(errorMessage)" | send;
+get_error '/cats/*' && {
+ printf '%s
' "$(get_error_message)" | send;
}
-(use || useError) && {
+(use || use_error) && {
printf '404
' | send;
}
diff --git a/examples/login.sh b/examples/login.sh
new file mode 100644
index 0000000..8ef62ee
--- /dev/null
+++ b/examples/login.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+source exprash.sh;
+
+redirect_stdout 'log';
+use_session
+use_body
+
+username='admin'
+password='password'
+
+# Authorization middleware
+function is_authorized() {
+ if [ "$(session 'authorized')" != "1" ]; then
+ next 'unauthorized'
+ return 1
+ fi
+}
+
+get '/' && {
+ if [ "$(session 'authorized')" == "1" ]; then
+ html="Welcome $username
"
+ html+="Click Here For Secrets
"
+ html+="Logout"
+ else
+ html="Welcome
"
+ html+="You must login to learn secrets
"
+ html+="Login"
+ fi
+ printf '%s\n' "$html" | send
+}
+
+get '/admin' && is_authorized && {
+ html='Here are all of my secrets:
'
+ html+=""
+ html+="Go Home"
+ printf '%s' "$html" | send
+}
+
+get '/login' && {
+ html="Login:
"
+ html+=''
+ printf '%s\n' "$html" | send
+}
+
+get '/incorrect-password' && {
+ if [ "$(session 'authorized')" == "1" ]; then
+ redirect '.'
+ else
+ html="Incorrect Password
"
+ html+="Try again:
"
+ html+="Login"
+ printf '%s\n' "$html" | send
+ fi
+}
+
+post '/login' && {
+ post_user=$(body 'username')
+ post_pass=$(body 'password')
+ if [ "$post_user" == "$username" ] && [ "$post_pass" == "$password" ]; then
+ session 'authorized' 1
+ redirect '.'
+ else
+ redirect 'incorrect-password'
+ fi
+}
+
+get '/logout' && {
+ session 'authorized' 0
+ redirect '.'
+}
+
+(use || use_error) && {
+ if [ "$(get_error_message)" == "unauthorized" ]; then
+ html='Error: Access Denied
'
+ html+='Click here to login'
+ printf '%s' "$html" | send
+ else
+ status '404'
+ printf '404
' | send
+ fi
+}
+
diff --git a/src/exprash.sh b/src/exprash.sh
index c104952..6f1efbd 100644
--- a/src/exprash.sh
+++ b/src/exprash.sh
@@ -14,13 +14,13 @@ shopt -s lastpipe
# ===============
# $1: Log file for redirecting stdout to
-function redirectStdout() {
+function redirect_stdout() {
local output="$1";
[ -z "$output" ] && output="/dev/null";
exec 5<&1;
- _exprashRedirectStdout="$output";
- exec 1>>"$_exprashRedirectStdout";
+ _exprash_redirect_stdout="$output";
+ exec 1>>"$_exprash_redirect_stdout";
printf '%s: %s\n' "${REQUEST_METHOD:-UNKNOWN}" "${PATH_INFO:-/}"
}
@@ -54,23 +54,23 @@ function delete() {
# $1: path
function all() {
- [ "$_exprashRouteHandled" -eq 1 ] && return 1;
- [ -n "$_exprashErrorMessage" ] && return 1;
+ [ "$_exprash_route_handled" -eq 1 ] && return 1;
+ [ -n "$_exprash_error_message" ] && return 1;
# Reset params
- _exprashParams=();
+ _exprash_params=();
- _pathMatch "$1" _exprashParams || return 1;
- _exprashRouteHandled=1;
+ _path_match "$1" _exprash_params || return 1;
+ _exprash_route_handled=1;
return 0;
}
function use() {
- [ "$_exprashRouteHandled" -eq 1 ] && return 1;
- [ -n "$_exprashErrorMessage" ] && return 1;
+ [ "$_exprash_route_handled" -eq 1 ] && return 1;
+ [ -n "$_exprash_error_message" ] && return 1;
- _exprashRouteHandled=1;
+ _exprash_route_handled=1;
return 0;
}
@@ -79,48 +79,48 @@ function use() {
# =====================
# $1: path
-function getError() {
+function get_error() {
[ "$REQUEST_METHOD" != "GET" ] && return 1;
- allError "$1";
+ all_error "$1";
}
# $1: path
-function postError() {
+function post_error() {
[ "$REQUEST_METHOD" != "POST" ] && return 1;
- allError "$1";
+ all_error "$1";
}
# $1: path
-function putError() {
+function put_error() {
[ "$REQUEST_METHOD" != "PUT" ] && return 1;
- allError "$1";
+ all_error "$1";
}
# $1: path
-function deleteError() {
+function delete_error() {
[ "$REQUEST_METHOD" != "DELETE" ] && return 1;
- allError "$1";
+ all_error "$1";
}
# $1: path
-function allError() {
- [ "$_exprashRouteHandled" -eq 1 ] && return 1;
- [ -z "$_exprashErrorMessage" ] && return 1;
+function all_error() {
+ [ "$_exprash_route_handled" -eq 1 ] && return 1;
+ [ -z "$_exprash_error_message" ] && return 1;
# Reset params
- _exprashParams=();
+ _exprash_params=();
- _pathMatch "$1" _exprashParams || return 1;
- _exprashRouteHandled=1;
+ _path_match "$1" _exprash_params || return 1;
+ _exprash_route_handled=1;
return 0;
}
-function useError() {
- [ "$_exprashRouteHandled" -eq 1 ] && return 1;
- [ -z "$_exprashErrorMessage" ] && return 1;
+function use_error() {
+ [ "$_exprash_route_handled" -eq 1 ] && return 1;
+ [ -z "$_exprash_error_message" ] && return 1;
- _exprashRouteHandled=1;
+ _exprash_route_handled=1;
return 0;
}
@@ -130,20 +130,20 @@ function useError() {
# $1 (optional): error message
function next() {
- _exprashRouteHandled=0;
- [ -n "$1" ] && _exprashErrorMessage="$1";
+ _exprash_route_handled=0;
+ [ -n "$1" ] && _exprash_error_message="$1";
}
# =============
# App Functions
# =============
-function errorMessage() {
- printf '%s' "$_exprashErrorMessage";
+function get_error_message() {
+ printf '%s' "$_exprash_error_message";
}
-function hasErrorMessage() {
- [ -n "$_exprashErrorMessage" ];
+function has_error_message() {
+ [ -n "$_exprash_error_message" ];
}
# =================
@@ -152,59 +152,60 @@ function hasErrorMessage() {
# $1: param name
function param() {
- printf '%s\n' "${_exprashParams[$1]}";
+ printf '%s\n' "${_exprash_params[$1]}";
}
-function hasParam() {
- [[ -v "_exprashParams[$1]" ]];
+function has_param() {
+ [[ -v "_exprash_params[$1]" ]];
}
# $1: key
# $2: (optional) index for accessing array parameters
function query() {
- _multiGet _exprashQuery "$1" "$2"
+ _multi_get _exprash_query "$1" "$2"
}
# $1: key
-function hasQuery() {
- _multiHas _exprashQuery "$1"
+function has_query() {
+ _multi_has _exprash_query "$1"
}
# $1: key
-function lenQuery() {
- _multiLen _exprashQuery "$1"
+function len_query() {
+ _multi_len _exprash_query "$1"
}
# Call this function to parse URLencoded request bodies
-function useBody() {
- if [[ "${HTTP_CONTENT_TYPE,,}" == "application/x-www-form-urlencoded" ]]; then
- _parseUrlEncoded _exprashBody
+function use_body() {
+ if [[ "${HTTP_CONTENT_TYPE,,}" == "application/x-www-form-urlencoded" ]];
+ then
+ _parse_url_encoded _exprash_body
fi
}
# $1: key
# $2: (optional) index for accessing array parameters
function body() {
- _multiGet _exprashBody "$1" "$2"
+ _multi_get _exprash_body "$1" "$2"
}
# $1: key
-function hasBody() {
- _multiHas _exprashBody "$1"
+function has_body() {
+ _multi_has _exprash_body "$1"
}
# $1: key
-function lenBody() {
- _multiLen _exprashBody "$1"
+function len_body() {
+ _multi_len _exprash_body "$1"
}
# $1: key
function cookie() {
- printf '%s' "${_exprashCookies[$1]}"
+ printf '%s' "${_exprash_cookies[$1]}"
}
# $1: key
-function hasCookie() {
- [[ -v "_exprashCookies[$1]" ]]
+function has_cookie() {
+ [[ -v "_exprash_cookies[$1]" ]]
}
# $1: key
# $2: value
-function setCookie() {
- _exprashSetCookies["$1"]="$2"
+function set_cookie() {
+ _exprash_set_cookies["$1"]="$2"
}
# ==================
@@ -212,16 +213,16 @@ function setCookie() {
# ==================
function send() {
- if [ "$_exprashHeadersSent" -eq 0 ]; then
- sendHeaders
- _exprashHeadersSent=1
+ if [ "$_exprash_headers_sent" -eq 0 ]; then
+ send_headers
+ _exprash_headers_sent=1
fi
- _sendRaw
+ _send_raw
}
-function sendJson() {
- setHeader 'Content-Type' 'application/json'
+function send_json() {
+ set_header 'Content-Type' 'application/json'
send
}
@@ -233,31 +234,34 @@ function redirect() {
fi
status '302'
- setHeader 'Location' "$path"
+ set_header 'Location' "$path"
printf 'Redirecting to: %s' "$path" | send
}
# $1: satus code
function status() {
- setHeader "Status" "$1"
+ set_header "Status" "$1"
}
# $1: Header Name
# $2: Header Value
-function setHeader() {
- _exprashHeaders["$1"]="$2"
+function set_header() {
+ _exprash_headers["$1"]="$2"
}
-function sendHeaders() {
- printf '%s\n' "Content-Type: ${_exprashHeaders['Content-Type']}" | _sendRaw
- for key in "${!_exprashHeaders[@]}"; do
+function send_headers() {
+ printf '%s\n' "Content-Type: ${_exprash_headers['Content-Type']}" | \
+ _send_raw
+ for key in "${!_exprash_headers[@]}"; do
[ "$key" == 'Content-Type' ] && continue
- printf '%s\n' "${key}: ${_exprashHeaders[$key]}" | _sendRaw
+ printf '%s\n' "${key}: ${_exprash_headers[$key]}" | \
+ _send_raw
done;
- for key in "${!_exprashSetCookies[@]}"; do
- printf '%s\n' "Set-Cookie: ${key}=${_exprashSetCookies[$key]}" | _sendRaw
+ for key in "${!_exprash_set_cookies[@]}"; do
+ printf '%s\n' "Set-Cookie: ${key}=${_exprash_set_cookies[$key]}" | \
+ _send_raw
done;
- printf '\n' | _sendRaw
+ printf '\n' | _send_raw
}
@@ -267,7 +271,7 @@ function sendHeaders() {
# Call this function to automatically manage sessions
# $1: (optional) session dir, defaults to "session" in the current directory
-function useSession() {
+function use_session() {
local session_dir=$1
# Create default session directory
@@ -277,10 +281,10 @@ function useSession() {
fi
# Setup session globals
- _exprashUseSession=1
- _exprashSessionDir=$session_dir
+ _exprash_use_session=1
+ _exprash_session_dir=$session_dir
- _loadSession || _createSession || return 1
+ _load_session || _create_session || return 1
}
# Set a session variable
@@ -290,9 +294,9 @@ function session() {
local name="$1"
if [[ -v 2 ]]; then
local value="$2"
- _exprashSession["$name"]="$value"
+ _exprash_session["$name"]="$value"
else
- printf '%s' "${_exprashSession["$name"]}"
+ printf '%s' "${_exprash_session["$name"]}"
fi
}
@@ -300,21 +304,21 @@ function session() {
# Internals
# =========
-function _sendRaw() {
- [ -n "$_exprashRedirectStdout" ] && exec >&5;
+function _send_raw() {
+ [ -n "$_exprash_redirect_stdout" ] && exec >&5;
cat;
- [ -n "$_exprashRedirectStdout" ] && exec 1>>"$_exprashRedirectStdout";
+ [ -n "$_exprash_redirect_stdout" ] && exec 1>>"$_exprash_redirect_stdout";
}
# $1: path
# $2: (nameref) array
-function _pathToArray() {
+function _path_to_array() {
readarray -t "$2" < <(printf '%s\n' "$1" | tr '/' '\n' | grep .);
}
# $1: route
# $2: (nameref) associative array for params
-function _pathMatch() {
+function _path_match() {
[ -z ${PATH_INFO+x} ] && return 1;
[ -z ${1+x} ] && return 1;
@@ -322,33 +326,33 @@ function _pathMatch() {
local route="$1";
# Params associative array
- local -n routeParams="$2";
+ local -n route_params="$2";
- local pathArr;
- _pathToArray "$path" pathArr;
+ local path_arr;
+ _path_to_array "$path" path_arr;
- local routeArr;
- _pathToArray "$route" routeArr;
+ local route_arr;
+ _path_to_array "$route" route_arr;
# Get max path length
- local routeLen=${#routeArr[@]};
- local pathLen=${#pathArr[@]};
- local maxLen=$(( routeLen >= pathLen ? routeLen : pathLen ));
+ local route_len=${#route_arr[@]};
+ local path_len=${#path_arr[@]};
+ local maxLen=$(( route_len >= path_len ? route_len : path_len ));
for ((i=0; i "$session_file"
+ declare -p _exprash_session | sed '1 s/\([^-]*-\)/\1g/' > "$session_file"
}
# =================
@@ -523,44 +527,44 @@ function _trim() {
# Shutdown
# ========
-function _exprashShutdown() {
- _saveSession
+function _exprash_shutdown() {
+ _save_session
}
# ==============
# Initialization
# ==============
-function _exprashInit() {
- _exprashRedirectStdout=''
-
- declare -gA _exprashParams=()
- declare -gA _exprashBody=()
- declare -gA _exprashQuery=()
- declare -gA _exprashHeaders=()
- declare -gA _exprashCookies=()
- declare -gA _exprashSetCookies=()
-
- _exprashUseSession=0
- _exprashSessionDir=''
- _exprashSessionId=''
- declare -gA _exprashSession=()
- _exprashSessionCookieName='exprash_session'
-
- _exprashRouteHandled=0
- _exprashErrorMessage=''
- _exprashHeadersSent=0
- _exprashHeaders['Content-Type']='text/html'
+function _exprash_init() {
+ _exprash_redirect_stdout=''
+
+ declare -gA _exprash_params=()
+ declare -gA _exprash_body=()
+ declare -gA _exprash_query=()
+ declare -gA _exprash_headers=()
+ declare -gA _exprash_cookies=()
+ declare -gA _exprash_set_cookies=()
+
+ _exprash_use_session=0
+ _exprash_session_dir=''
+ _exprash_sessionId=''
+ declare -gA _exprash_session=()
+ _exprash_session_cookie_name='exprash_session'
+
+ _exprash_route_handled=0
+ _exprash_error_message=''
+ _exprash_headers_sent=0
+ _exprash_headers['Content-Type']='text/html'
# Parse query string
- _parseUrlEncoded _exprashQuery "$QUERY_STRING"
+ _parse_url_encoded _exprash_query "$QUERY_STRING"
# Parse cookies
- _parseCookies _exprashCookies "$HTTP_COOKIE"
+ _parse_cookies _exprash_cookies "$HTTP_COOKIE"
}
# Shutdown trap
-trap _exprashShutdown EXIT
+trap _exprash_shutdown EXIT
# Initialize exprash
-_exprashInit
+_exprash_init
diff --git a/tests/cookies.sh b/tests/cookies.sh
index 597e4cb..2aa49e0 100755
--- a/tests/cookies.sh
+++ b/tests/cookies.sh
@@ -1,20 +1,22 @@
+# shellcheck disable=SC2154,SC2034
+
it "Should parse cookies" "$({
HTTP_COOKIE='bob=gob; job=tob'
- _exprashInit
- output=$(declare -p _exprashCookies)
- expected_output='declare -A _exprashCookies=([bob]="gob" [job]="tob" )'
+ _exprash_init
+ output=$(declare -p _exprash_cookies)
+ expected_output='declare -A _exprash_cookies=([bob]="gob" [job]="tob" )'
[ "$output" == "$expected_output" ]
})"
it "Should get cookie value by name" "$({
HTTP_COOKIE='bob=gob; job=tob'
- _exprashInit
+ _exprash_init
[ "$(cookie 'bob')" == 'gob' ]
})"
it "Should determine if a cookie exists by name" "$({
HTTP_COOKIE='bob=gob; job=tob'
- _exprashInit
- hasCookie 'bob' && ! hasCookie 'kob'
+ _exprash_init
+ has_cookie 'bob' && ! has_cookie 'kob'
})"
diff --git a/tests/query.sh b/tests/query.sh
index e3ffac6..24d492f 100644
--- a/tests/query.sh
+++ b/tests/query.sh
@@ -1,6 +1,8 @@
+# shellcheck disable=SC2154,SC2034
+
it "Should parse query string" "$({
QUERY_STRING='ohmy=zsh&exit=vim'
- _exprashInit
- hasQuery 'ohmy' && ! hasQuery 'ohno' && [ "$(query 'exit')" == 'vim' ]
+ _exprash_init
+ has_query 'ohmy' && ! has_query 'ohno' && [ "$(query 'exit')" == 'vim' ]
})"
diff --git a/tests/routes.sh b/tests/routes.sh
index 55d4a3e..dbad6ab 100755
--- a/tests/routes.sh
+++ b/tests/routes.sh
@@ -1,62 +1,64 @@
-it "Should match plain route" $({
+# shellcheck disable=SC2154,SC2034
+
+it "Should match plain route" "$({
PATH_INFO='/plain/route'
- _exprashInit
+ _exprash_init
all '/plain/route'
-})
+})"
-it "Should not match incorrect plain route" $({
+it "Should not match incorrect plain route" "$({
PATH_INFO='/plain/WRONG'
- _exprashInit
+ _exprash_init
! all '/plain/route'
-})
+})"
-it "Should extract parameter" $({
+it "Should extract parameter" "$({
PATH_INFO='/cats/calico/pet'
- _exprashInit
- all '/cats/:cat/pet' && hasParam 'cat' && [ "$(param 'cat')" == 'calico' ]
-})
+ _exprash_init
+ all '/cats/:cat/pet' && has_param 'cat' && [ "$(param 'cat')" == 'calico' ]
+})"
-it "Should match wildcard route" $({
+it "Should match wildcard route" "$({
PATH_INFO='/cats/calico/pet'
- _exprashInit
+ _exprash_init
all '/cats/*/pet'
-})
+})"
-it "Should not match incorrect wildcard route" $({
+it "Should not match incorrect wildcard route" "$({
PATH_INFO='/cats/calico/'
- _exprashInit
+ _exprash_init
! all '/cats/*/pet'
-})
+})"
-it "Should match multi-wildcard route" $({
+it "Should match multi-wildcard route" "$({
PATH_INFO='/cats/calico/pet/donkey'
- _exprashInit
+ _exprash_init
all '/cats/**'
-})
+})"
-it "Should not match incorrect multi-wildcard route" $({
+it "Should not match incorrect multi-wildcard route" "$({
PATH_INFO='/INCORRECT/calico/pet/donkey'
- _exprashInit
+ _exprash_init
! all '/cats/**'
-})
+})"
-it "Should not match path shorter than route" $({
+it "Should not match path shorter than route" "$({
PATH_INFO='/year'
- _exprashInit
+ _exprash_init
! all '/year/:year'
-})
+})"
-it "Should match get route" $({
+it "Should match get route" "$({
REQUEST_METHOD='GET'
PATH_INFO='/simple/route'
- _exprashInit
+ _exprash_init
get '/simple/route'
-})
+})"
-it "Should not match get route with incorrect method" $({
+it "Should not match get route with incorrect method" "$({
REQUEST_METHOD='POST'
PATH_INFO='/simple/route'
- _exprashInit
+ _exprash_init
! get '/simple/route'
-})
+})"
diff --git a/tests/session.sh b/tests/session.sh
index e258354..cb02c1f 100644
--- a/tests/session.sh
+++ b/tests/session.sh
@@ -1,30 +1,30 @@
# shellcheck disable=SC2154,SC2034
-testSessionDir='/tmp/exprash_test_sessions'
-mkdir -p "$testSessionDir"
+test_session_dir='/tmp/exprash_test_sessions'
+mkdir -p "$test_session_dir"
it "Should set session directory" "$({
- _exprashInit
- useSession "$testSessionDir"
- [ "$_exprashSessionDir" == "$testSessionDir" ]
+ _exprash_init
+ use_session "$test_session_dir"
+ [ "$_exprash_session_dir" == "$test_session_dir" ]
})"
it "Should save and load session" "$({
- _exprashInit
- useSession "$testSessionDir"
+ _exprash_init
+ use_session "$test_session_dir"
session 'data' 'value'
- session_id=$_exprashSessionId
- cookie_value=${_exprashSetCookies[$_exprashSessionCookieName]}
- _exprashShutdown
+ session_id=$_exprash_session_id
+ cookie_value=${_exprash_set_cookies[$_exprash_session_cookie_name]}
+ _exprash_shutdown
# Forcibly clear session data just in case (but it should also get cleared by
- # _exprashInit)
- _exprashSession=()
- _exprashSessionId=''
+ # _exprash_init)
+ _exprash_session=()
+ _exprash_session_id=''
- HTTP_COOKIE="${_exprashSessionCookieName}=$cookie_value"
- _exprashInit
- useSession "$testSessionDir"
+ HTTP_COOKIE="${_exprash_session_cookie_name}=$cookie_value"
+ _exprash_init
+ use_session "$test_session_dir"
[ "$(session 'data')" == "value" ]
})"