Ben Ashton
2 years ago
commit
a18f52b6a1
3 changed files with 197 additions and 0 deletions
@ -0,0 +1,50 @@
|
||||
# Exprash |
||||
|
||||
An Express-like HTTP router for Bash compatible with CGI 1.1 |
||||
|
||||
I'm aware that the name of this project evokes a feeling of physical disgust. That is by design. |
||||
|
||||
## Usage/Examples |
||||
|
||||
Here is some leaked source code for my brand new Cat website. Do not steal! |
||||
|
||||
```shell |
||||
#!/bin/bash |
||||
printf '%s\n\n' 'Content-Type: text/html'; |
||||
|
||||
source ../src/exprash.sh; |
||||
|
||||
declare -A cats; |
||||
cats[calico]="Calico"; |
||||
cats[sphynx]="Sphynx"; |
||||
cats[ragdoll]="Ragdoll"; |
||||
cats[scottish_fold]="Scottish Fold"; |
||||
|
||||
get '/' && { |
||||
printf '<h1>Cats</h1>\n'; |
||||
printf '<ul>\n'; |
||||
for key in "${!cats[@]}"; do |
||||
printf '<li><a href="cats/%s">%s</a></li>\n' "$key" "${cats[$key]}"; |
||||
done |
||||
printf '</ul>\n'; |
||||
} |
||||
|
||||
get '/cats/:cat' && { |
||||
key=$(param 'cat'); |
||||
|
||||
if [[ -v "cats[$key]" ]]; then |
||||
printf '<h1>Your Cat: %s</h1>\n' "${cats[$key]}"; |
||||
else |
||||
next; |
||||
fi; |
||||
} |
||||
|
||||
all '/cats/:cat' && { |
||||
printf '<h1>Error: Cannot find that cat</h1>\n'; |
||||
} |
||||
``` |
||||
|
||||
|
||||
## License |
||||
|
||||
[WTFPL](http://www.wtfpl.net/txt/copying/) |
@ -0,0 +1,33 @@
|
||||
#!/bin/bash |
||||
printf '%s\n\n' 'Content-Type: text/html'; |
||||
|
||||
source ../src/exprash.sh; |
||||
|
||||
declare -A cats; |
||||
cats[calico]="Calico"; |
||||
cats[sphynx]="Sphynx"; |
||||
cats[ragdoll]="Ragdoll"; |
||||
cats[scottish_fold]="Scottish Fold"; |
||||
|
||||
get '/' && { |
||||
printf '<h1>Cats</h1>\n'; |
||||
printf '<ul>\n'; |
||||
for key in "${!cats[@]}"; do |
||||
printf '<li><a href="cats/%s">%s</a></li>\n' "$key" "${cats[$key]}"; |
||||
done |
||||
printf '</ul>\n'; |
||||
} |
||||
|
||||
get '/cats/:cat' && { |
||||
key=$(param 'cat'); |
||||
|
||||
if [[ -v "cats[$key]" ]]; then |
||||
printf '<h1>Your Cat: %s</h1>\n' "${cats[$key]}"; |
||||
else |
||||
next; |
||||
fi; |
||||
} |
||||
|
||||
all '/cats/:cat' && { |
||||
printf '<h1>Error: Cannot find that cat</h1>\n'; |
||||
} |
@ -0,0 +1,114 @@
|
||||
#!/bin/bash |
||||
# shellcheck disable=SC2034 # false flags nameref params |
||||
|
||||
# ============= |
||||
# Route Methods |
||||
# ============= |
||||
|
||||
# $1: path |
||||
function get() { |
||||
[ "$REQUEST_METHOD" != "GET" ] && return 1; |
||||
all "$1"; |
||||
} |
||||
|
||||
# $1: path |
||||
function post() { |
||||
[ "$REQUEST_METHOD" != "POST" ] && return 1; |
||||
all "$1"; |
||||
} |
||||
|
||||
# $1: path |
||||
function put() { |
||||
[ "$REQUEST_METHOD" != "PUT" ] && return 1; |
||||
all "$1"; |
||||
} |
||||
|
||||
# $1: path |
||||
function delete() { |
||||
[ "$REQUEST_METHOD" != "DELETE" ] && return 1; |
||||
all "$1"; |
||||
} |
||||
|
||||
# $1: path |
||||
function all() { |
||||
[ "$routeHandled" -eq 1 ] && return 1; |
||||
|
||||
# Reset params |
||||
params=(); |
||||
pathMatch "$1" params || return 1; |
||||
|
||||
# # if path ooesn't match PATH_INFO: return 1 |
||||
routeHandled=1; |
||||
return 0; |
||||
} |
||||
|
||||
function next() { |
||||
routeHandled=0; |
||||
} |
||||
|
||||
# ================= |
||||
# Request Functions |
||||
# ================= |
||||
|
||||
# $1: param name |
||||
function param() { |
||||
printf '%s\n' "${params[$1]}"; |
||||
} |
||||
|
||||
# $1: param name |
||||
function hasParam() { |
||||
[[ -v "params[$1]" ]]; |
||||
} |
||||
|
||||
# ========= |
||||
# Internals |
||||
# ========= |
||||
|
||||
# $1: path |
||||
# $2: (nameref) array |
||||
function pathToArray() { |
||||
readarray -t "$2" < <(printf '%s\n' "$1" | tr '/' '\n' | grep .); |
||||
} |
||||
|
||||
# $1: route |
||||
# $2: (nameref) associative array for params |
||||
function pathMatch() { |
||||
[ -z ${PATH_INFO+x} ] && return 1; |
||||
[ -z ${1+x} ] && return 1; |
||||
|
||||
local path="$PATH_INFO"; |
||||
local route="$1"; |
||||
|
||||
local pathArr; |
||||
pathToArray "$path" pathArr; |
||||
|
||||
local routeArr; |
||||
pathToArray "$route" routeArr; |
||||
|
||||
# Params associative array |
||||
local -n routeParams="$2"; |
||||
|
||||
# Not a match if pathArr and routeArr have different length |
||||
[ "${#pathArr[@]}" -ne "${#routeArr[@]}" ] && return 1; |
||||
|
||||
for ((i=0; i<${#routeArr[@]}; i++)); do |
||||
local routeComponent="${routeArr[$i]}"; |
||||
local pathComponent="${pathArr[$i]}"; |
||||
|
||||
# If route component starts with ":" |
||||
if [[ "$routeComponent" == :* ]]; then |
||||
routeParams["${routeComponent:1}"]="$pathComponent"; |
||||
else |
||||
# Confirm paths match |
||||
[ "$routeComponent" != "$pathComponent" ] && return 1; |
||||
fi; |
||||
done; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
# ======= |
||||
# Globals |
||||
# ======= |
||||
routeHandled=0; |
||||
declare -A params; |
Loading…
Reference in new issue