Compare commits

..

1 commit
master ... pack

Author SHA1 Message Date
Dominika Liberda 1cb85c8e4a + basic packaging support, WiP 2021-12-06 13:18:57 +01:00
7 changed files with 161 additions and 187 deletions

View file

@ -21,9 +21,9 @@ cfg[ssl_cert]=''
cfg[ssl_key]=''
cfg[extension]='shs'
cfg[extra_headers]='server: HTTP.sh/0.95 (devel)'
cfg[extra_headers]='server: HTTP.sh/0.94 (devel)'
cfg[title]='HTTP.sh 0.95'
cfg[title]='HTTP.sh 0.94'
cfg[php_enabled]=false # enable PHP script evalutaion (requires PHP)
cfg[python_enabled]=false # enable Python script evalutaion (requires Python)

72
http.sh
View file

@ -3,7 +3,7 @@ trap ctrl_c INT
if [[ ! -f "config/master.sh" ]]; then
mkdir -p config
cat <<EOF > "config/master.sh"
cat <<MaeIsCute > "config/master.sh"
declare -A cfg
cfg[ip]=0.0.0.0 # IP address to bind to - use 0.0.0.0 to bind to all
@ -19,7 +19,7 @@ cfg[index]='index.shs'
cfg[autoindex]=true
cfg[auth_required]=false
cfg[auth_realm]="asdf"
cfg[auth_realm]="Luna is cute <3"
cfg[ssl]=false # enables/disables listening on HTTPS
cfg[ssl_port]=8443
@ -27,9 +27,9 @@ cfg[ssl_cert]=''
cfg[ssl_key]=''
cfg[extension]='shs'
cfg[extra_headers]='server: HTTP.sh/0.95 (devel)'
cfg[extra_headers]='server: HTTP.sh/0.94 (devel)'
cfg[title]='HTTP.sh 0.95'
cfg[title]='HTTP.sh 0.94'
cfg[php_enabled]=false # enable PHP script evalutaion (requires PHP)
cfg[python_enabled]=false # enable Python script evalutaion (requires Python)
@ -46,7 +46,7 @@ cfg[mail_server]=""
cfg[mail_password]=""
cfg[mail_ssl]=true
cfg[mail_ignore_bad_cert]=false
EOF
MaeIsCute
fi
source config/master.sh
@ -57,10 +57,10 @@ function ctrl_c() {
echo -e "Cleaned up, exitting.\nHave an awesome day!!"
}
if [[ ! -f "$(pwd)/http.sh" ]]; then
echo -e "Please run HTTP.sh inside it's designated directory\nRunning the script from arbitrary locations isn't supported."
exit 1
fi
if [[ ! -f "$(pwd)/http.sh" ]]; then # packer-exclude
echo -e "Please run HTTP.sh inside it's designated directory\nRunning the script from arbitrary locations isn't supported." # packer-exclude
exit 1 # packer-exclude
fi # packer-exclude
for i in $(cat src/dependencies.required); do
@ -89,24 +89,22 @@ if [[ $error == true ]]; then
fi
if [[ $1 == "init" ]]; then # will get replaced with proper parameter parsing in 1.0
#set -e
mkdir -p "${cfg[namespace]}/${cfg[root]}" "${cfg[namespace]}/workers/example" "${cfg[namespace]}/views" "${cfg[namespace]}/templates"
touch "${cfg[namespace]}/config.sh" "${cfg[namespace]}/workers/example/control"
cat <<EOF > "${cfg[namespace]}/config.sh"
cat <<LauraIsCute > "${cfg[namespace]}/config.sh"
## app config
## your application-specific config goes here!
# worker_add example 5
cfg[enable_multipart]=false # by default, uploading files is disabled
EOF
cat <<EOF > "${cfg[namespace]}/workers/example/worker.sh"
# worker_add example 5
LauraIsCute
cat <<LauraIsCute > "${cfg[namespace]}/workers/example/worker.sh"
#!/usr/bin/env bash
date
EOF
LauraIsCute
cat <<EOF > "${cfg[namespace]}/${cfg[root]}/index.shs"
cat <<LauraIsCute > "${cfg[namespace]}/${cfg[root]}/index.shs"
#!/usr/bin/env bash
source templates/head.sh
echo "<h1>Hello from HTTP.sh!</h1><br>To get started with your app, check out $(pwd)/${cfg[namespace]}/
@ -121,39 +119,40 @@ echo "<h1>Hello from HTTP.sh!</h1><br>To get started with your app, check out $(
<li>$(pwd)/config/<hostname> - config loaded if a request is made to a specific hostname</li>
<li>$(pwd)/storage/ - directory for storing all and any data your app may produce</li>
<li>$(pwd)/secret/ - user accounts and other secret tokens live here</li>
<li>$(pwd)/src/ - HTTP.sh src, feel free to poke around ;P</li></ul>"
EOF
cat <<EOF > "${cfg[namespace]}/routes.sh"
<li>$(pwd)/src/ - HTTP.sh src, feel free to poke around ;P</li></ul>
&copy; sdomi, ptrcnull, selfisekai - 2020, 2021"
LauraIsCute
cat <<MaeIsCute > "${cfg[namespace]}/routes.sh"
## routes - application-specific routes
##
## HTTP.sh supports both serving files using a directory structure (webroot),
## and using routes. The latter may come in handy if you want to create nicer
## paths, e.g.
##
## (webroot) https://example.com/profile.shs?name=asdf
## (webroot) https://example.com/profile.shs?name=ptrcnull
## ... may become ...
## (routes) https://example.com/profile/asdf
## (routes) https://example.com/profile/ptrcnull
##
## To set up routes, define rules in this file (see below for examples)
# router "/test" "app/views/test.shs"
# router "/profile/:user" "app/views/user.shs"
EOF
MaeIsCute
chmod +x "${cfg[namespace]}/workers/example/worker.sh"
echo -e "Success..?\nTry running \`./http.sh\` now"
echo -e "Success..?\nTry running ./http.sh now"
exit 0
fi
cat <<EOF >&2
cat <<MaeIsCute >&2
_ _ _______ _______ _____ ______ _ _
| | | |_______|_______| _ \/ ___/| | | |
| |__| | | | | | | |_| | |___ | |__| |
| |__| | | | | | | ___/\___ \ | |__| |
| | | | | | | | | | ___\ \| | | |
|_| |_| |_| |_| |_| □ /_____/|_| |_|
EOF
MaeIsCute
if [[ "$1" == "debug" ]]; then
cfg[dbg]=true
@ -182,16 +181,9 @@ else
# this is a workaround because ncat kept messing up large (<150KB) files over HTTP - but not over HTTPS!
socket=$(mktemp -u /tmp/socket.XXXXXX)
if [[ ${cfg[dbg]} == true ]]; then
# ncat with the "timeout" (-i) option has a bug which forces it
# to quit after the first time-outed connection, ignoring the
# "broker" (-k) mode. This is a workaround for this.
while true; do
ncat -i 600s -l -U "$socket" -c src/server.sh -k
done &
ncat -l -U "$socket" -c src/server.sh -k &
else
while true; do
ncat -i 600s -l -U "$socket" -c src/server.sh -k 2>> /dev/null &
done &
ncat -l -U "$socket" -c src/server.sh -k 2>> /dev/null &
fi
socat TCP-LISTEN:${cfg[port]},fork,bind=${cfg[ip]} UNIX-CLIENT:$socket &
echo "[HTTP] listening on ${cfg[ip]}:${cfg[port]} through '$socket'"
@ -200,13 +192,9 @@ else
if [[ ${cfg[ssl]} == true ]]; then
echo "[SSL] listening on port ${cfg[ip]}:${cfg[ssl_port]}"
if [[ ${cfg[dbg]} == true ]]; then
while true; do
ncat -i 600s -l ${cfg[ip]} ${cfg[ssl_port]} -c src/server.sh -k --ssl $([[ ${cfg[ssl_key]} != '' && ${cfg[ssl_cert]} != '' ]] && echo "--ssl-cert ${cfg[ssl_cert]} --ssl-key ${cfg[ssl_key]}")
done &
ncat -l ${cfg[ip]} ${cfg[ssl_port]} -c src/server.sh -k --ssl $([[ ${cfg[ssl_key]} != '' && ${cfg[ssl_cert]} != '' ]] && echo "--ssl-cert ${cfg[ssl_cert]} --ssl-key ${cfg[ssl_key]}") &
else
while true; do
ncat -i 600s -l ${cfg[ip]} ${cfg[ssl_port]} -c src/server.sh -k --ssl $([[ ${cfg[ssl_key]} != '' && ${cfg[ssl_cert]} != '' ]] && echo "--ssl-cert ${cfg[ssl_cert]} --ssl-key ${cfg[ssl_key]}") 2>> /dev/null
done &
ncat -l ${cfg[ip]} ${cfg[ssl_port]} -c src/server.sh -k --ssl $([[ ${cfg[ssl_key]} != '' && ${cfg[ssl_cert]} != '' ]] && echo "--ssl-cert ${cfg[ssl_cert]} --ssl-key ${cfg[ssl_key]}") 2>> /dev/null &
fi
fi
fi

93
pack.sh Executable file
View file

@ -0,0 +1,93 @@
#!/bin/bash
# todo:
# - dependencies.optional dependencies.required
# - set namespace to '.'
function pack() {
echo "function __main() {"
cat http.sh
echo "}"
echo "function __account() {"
cat src/account.sh
echo "}"
echo "function __mail() {"
cat src/mail.sh
echo "}"
echo "function __mime() {"
cat src/mime.sh
echo "}"
echo "function __misc() {"
cat src/misc.sh
echo "}"
echo "function __route() {"
cat src/route.sh
echo "}"
echo "function __server() {"
cat src/server.sh
echo "}"
echo "function __template() {"
cat src/template.sh
echo "}"
echo "function __worker() {"
cat src/worker.sh
echo "}"
#echo "function __res_101 {"
#cat src/response/101.sh
#echo "}"
echo "function __res_200() {"
cat src/response/200.sh
echo "}"
echo "function __res_401() {"
cat src/response/401.sh
echo "}"
echo "function __res_403() {"
cat src/response/403.sh
echo "}"
echo "function __res_404() {"
cat src/response/404.sh
echo "}"
echo "function __res_listing() {"
cat src/response/listing.sh
echo "}"
echo "function __res_proxy() {"
cat src/response/proxy.sh
echo "}"
echo "function __template_head() {"
cat templates/head.sh
echo "}"
#echo "function __ws() {"
#cat src/ws.sh
#echo "}"
echo '[[ "$1" == "server_int" ]] && __server
[[ "$1" == "debug" ]] && __main debug
[[ "$1" == "init" ]] && __main init
[[ "$1" == "" ]] && __main'
}
pack | grep -v "packer-exclude" \
| sed -E 's@source "*src/response/@__res_@g;
s@source "*src/@__@;
s@__.*@&MaeIsCuteUwU@;
s@\.sh"*MaeIsCuteUwU@@;
s@source "*templates/head.sh@__template_head@;
s@MaeIsCuteUwU@@g;
s@exit .*@return@;
s@-c src/server.sh@-c "$0 server_int"@g'

View file

@ -55,9 +55,3 @@ function url_encode() {
function url_decode() {
echo -ne "$(sed -E 's/%[0-1][0-9a-f]//g;s/%/\\x/g' <<< "$1")"
}
# bogus function!
# this is here to prevent "command not found" errors in debug mode
function worker_add() {
:
}

View file

@ -1,22 +1,14 @@
function __headers() {
if [[ "${cfg[unbuffered]}" != true ]]; then
if [[ "${r[headers]}" == *'Location'* ]]; then
printf "HTTP/1.0 302 aaaaa\r\n"
else
printf "HTTP/1.0 200 OK\r\n"
fi
[[ "${r[headers]}" != '' ]] && printf "${r[headers]}"
printf "${cfg[extra_headers]}\r\n"
else
echo "uh oh - we're running unbuffered" > /dev/stderr
fi
if [[ ${r[status]} == 200 ]]; then
get_mime "${r[uri]}"
[[ "$mimetype" != '' ]] && printf "content-type: $mimetype\r\n"
fi
printf "\r\n"
}
if [[ "${cfg[unbuffered]}" != true ]]; then
printf "HTTP/1.0 200 OK
${cfg[extra_headers]}\r\n"
else
echo "uh oh - we're running unbuffered" > /dev/stderr
fi
if [[ ${r[status]} == 200 ]]; then
get_mime "${r[uri]}"
[[ "$mimetype" != '' ]] && printf "content-type: $mimetype\r\n"
fi
if [[ ${r[status]} == 212 ]]; then
if [[ "${cfg[unbuffered]}" == true ]]; then
@ -24,7 +16,7 @@ if [[ ${r[status]} == 212 ]]; then
else
temp=$(mktemp)
source "${r[view]}" > $temp
__headers
[[ "${r[headers]}" != '' ]] && printf "${r[headers]}\r\n" || printf "\r\n"
cat $temp
rm $temp
fi
@ -32,21 +24,21 @@ if [[ ${r[status]} == 212 ]]; then
elif [[ "${cfg[php_enabled]}" == true && "${r[uri]}" =~ ".php" ]]; then
temp=$(mktemp)
php "${r[uri]}" "$(get_dump)" "$(post_dump)" > $temp
__headers
[[ "${r[headers]}" != '' ]] && printf "${r[headers]}\r\n" || printf "\r\n"
cat $temp
rm $temp
elif [[ "${cfg[python_enabled]}" == true && "${r[uri]}" =~ ".py" ]]; then
temp=$(mktemp)
python "${r[uri]}" "$(get_dump)" "$(post_dump)" > $temp
__headers
[[ "${r[headers]}" != '' ]] && printf "${r[headers]}\r\n" || printf "\r\n"
cat $temp
rm $temp
elif [[ "${r[uri]}" =~ \.${cfg[extension]}$ ]]; then
temp=$(mktemp)
source "${r[uri]}" > $temp
__headers
[[ "${r[headers]}" != '' ]] && printf "${r[headers]}\r\n" || printf "\r\n"
if [[ "${cfg[encoding]}" != '' ]]; then
iconv $temp -f UTF-8 -t "${cfg[encoding]}"
else
@ -55,7 +47,7 @@ elif [[ "${r[uri]}" =~ \.${cfg[extension]}$ ]]; then
rm $temp
else
__headers
printf "\r\n"
if [[ "$mimetype" == "text/"* && "${cfg[encoding]}" != '' ]]; then
iconv "${r[uri]}" -f UTF-8 -t "${cfg[encoding]}"
else

View file

@ -84,8 +84,8 @@ while read -r param; do
data="$(sed -E 's/\?/<2F><>Lun4_iS_CuTe<54>/;s/^(.*)<29><>Lun4_iS_CuTe<54>//' <<< "${r[url]}")"
IFS='&'
for i in $data; do
name="${i/=*/}"
value="${i/*=/}"
name="$(sed -E 's/\=(.*)$//' <<< "$i")"
value="$(sed "s/$name\=//" <<< "$i")"
get_data[$name]="$value"
done
fi
@ -99,8 +99,8 @@ while read -r param; do
data="$(sed -E 's/\?/<2F><>Lun4_iS_CuTe<54>/;s/^(.*)<29><>Lun4_iS_CuTe<54>//' <<< "${r[url]}")"
IFS='&'
for i in $data; do
name="${i/=*/}"
value="${i/*=/}"
name="$(sed -E 's/\=(.*)$//' <<< "$i")"
value="$(sed "s/$name\=//" <<< "$i")"
get_data[$name]="$value"
done
fi
@ -130,10 +130,10 @@ if [[ ${r[status]} != 101 ]]; then
r[view]="${route[$((i+2))]}"
IFS='/'
url=(${route[$i]})
url_=($(cut -d '?' -f 1 <<< "${r[url]}"))
url_=(${r[url]})
unset IFS
for (( j=0; j<${#url[@]}; j++ )); do
if [[ ${url_[$j]} != '' && ${url[$j]} == ":"* ]]; then
if [[ ${url_[$j]} != '' ]]; then
params[$(sed 's/://' <<< "${url[$j]}")]="${url_[$j]}"
fi
done
@ -175,7 +175,7 @@ if [[ "${cfg[proxy]}" == true ]]; then
r[status]=211
fi
if [[ "${r[post]}" == true ]] && [[ "${r[status]}" == 200 || "${r[status]}" == 212 ]]; then
if [[ "${r[post]}" == true && "${r[status]}" == 200 ]] || [[ "${r[post]}" == true && "${r[status]}" == 212 ]]; then
# This whole ordeal is here to prevent passing binary data as a variable.
# I could have done it as an array, but this solution works, and it's
# speedy enough so I don't care.
@ -209,8 +209,8 @@ if [[ "${r[post]}" == true ]] && [[ "${r[status]}" == 200 || "${r[status]}" ==
IFS='&'
for i in $(tr -d '\n' <<< "$data"); do
name="${i/=*/}"
param="${i/*=/}"
name="$(sed -E 's/\=(.*)$//' <<< "$i")"
param="$(sed "s/$name\=//" <<< "$i")"
post_data[$name]="$param"
done
unset IFS

View file

@ -1,72 +1,22 @@
#!/usr/bin/env bash
# template.sh - basic templating engine
# nightmare fuel
# render(array, template_file, recurse)
# render(array, template_file)
function render() {
if [[ "$3" != true ]]; then
local template="$(tr -d $'\01'$'\02' < "$2" | sed 's/\&/<2F>UwU<77>/g')"
else
local template="$(cat "$2" | sed -E 's/\\/\\\\/g')"
fi
local template="$(cat "$2")"
local -n ref=$1
local tmp=$(mktemp)
local key
for key in ${!ref[@]}; do
if [[ "$key" == "_"* ]]; then # iter mode
local subtemplate=$(mktemp)
echo "$template" | grep "{{start $key}}" -A99999 | grep "{{end $key}}" -B99999 | tr '\n' $'\01' > "$subtemplate"
echo 's'$'\02''\{\{start '"$key"'\}\}.*\{\{end '"$key"'\}\}'$'\02''\{\{'"$key"'\}\}'$'\02'';' >> "$tmp"
local -n asdf=${ref[$key]}
local j
local value=''
for j in ${!asdf[@]}; do
local -n fdsa=_${asdf[$j]}
value+="$(render fdsa "$subtemplate" true)"
done
value="$(sed -E 's'$'\02''\{\{start '"$key"'\}\}'$'\02'$'\02'';s'$'\02''\{\{end '"$key"'\}\}'$'\02'$'\02' <<< "$value")"
echo 's'$'\02''\{\{'"$key"'\}\}'$'\02'''"$value"''$'\02'';' >> "$tmp"
rm "$subtemplate"
elif [[ "$key" == "@"* && "${ref[$key]}" != '' ]]; then
local value="$(sed -E 's/\&/<2F>UwU<77>/g' <<< "${ref[$key]}")"
echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp"
elif [[ "$key" == '?'* ]]; then
local _key="\\?${key/?/}"
local subtemplate=$(mktemp)
echo 's'$'\02''\{\{start '"$_key"'\}\}((.*)\{\{else '"$_key"'\}\}.*\{\{end '"$_key"'\}\}|(.*)\{\{end '"$_key"'\}\})'$'\02''\2\3'$'\02'';' >> "$subtemplate"
cat <<< $(cat "$subtemplate" "$tmp") > "$tmp" # call that cat abuse
rm "$subtemplate"
elif [[ "${ref[$key]}" != "" ]]; then
echo "VALUE: ${ref[$key]}" > /dev/stderr
if [[ "$3" != true ]]; then
local value="$(html_encode <<< "${ref[$key]}" | sed -E 's/\&/<2F>UwU<77>/g')"
else
local value="$(sed -E 's/\\\\/<2F>OwO<77>/g;s/\\//g;s/<2F>OwO<77>/\\/g' <<< "${ref[$key]}" | html_encode | sed -E 's/\&/<2F>UwU<77>/g')"
fi
echo 's'$'\02''\{\{\.'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp"
if [[ "${ref[$key]}" != "" ]]; then
local value="$(html_encode "${ref[$key]}" | sed -E 's/\&/<2F>UwU<77>/g')"
echo 's/\{\{\.'"$key"'\}\}/'"$value"'/g' >> "$tmp"
else
echo 's'$'\02''\{\{\.'"$key"'\}\}'$'\02'$'\02''g;' >> "$tmp"
echo 's/\{\{\.'"$key"'\}\}//g' >> "$tmp"
fi
done
if [[ "$3" != true ]]; then # are we recursing?
cat "$tmp" | tr '\n' $'\01' | sed -E 's/'$'\02'';'$'\01''/'$'\02'';/g;s/'$'\02''g;'$'\01''/'$'\02''g;/g' > "${tmp}_"
echo 's/\{\{start \?([a-zA-Z0-9_-]*[^}])\}\}(.*\{\{else \?\1\}\}(.*)\{\{end \?\1\}\}|.*\{\{end \?\1\}\})/\3/g' >> "${tmp}_"
template="$(tr '\n' $'\01' <<< "$template" | sed -E -f "${tmp}_" | tr $'\01' '\n')"
sed -E 's/<2F>UwU<77>/\&/g' <<< "$template"
rm "$tmp" "${tmp}_"
else
tr '\n' $'\01' <<< "$template" | sed -E -f "$tmp" | tr $'\01' '\n'
rm "$tmp"
fi
template="$(sed -E -f "$tmp" <<< "$template")"
sed -E 's/<2F>UwU<77>/\&/g' <<< "$template"
rm "$tmp"
}
# render_unsafe(array, template_file)
@ -75,53 +25,10 @@ function render_unsafe() {
local -n ref=$1
local tmp=$(mktemp)
for key in ${!ref[@]}; do
if [[ "$key" == "_"* ]]; then # iter mode
# grep "start _test" -A99999 | grep "end _test" -B99999
local -n item_array=${ref[$key]}
local value
for ((_i = 0; _i < ${#item_array[@]}; _i++)); do
value+="$(xxd -p <<< "${item_array[$_i]}" | tr -d '\n' | sed -E 's/../\\x&/g')"
done
echo 's/\{\{'"$key"'\}\}/'"$value"'/g' >> "$tmp"
else
local value="$(xxd -p <<< "${ref[$key]}" | tr -d '\n' | sed -E 's/../\\x&/g')"
echo 's/\{\{\.'"$key"'\}\}/'"$value"'/g' >> "$tmp"
fi
local value="$(xxd -ps <<< "${ref[$key]}" | tr -d '\n' | sed -E 's/.{2}/\\x&/g')"
echo 's/\{\{\.'"$key"'\}\}/'"$value"'/g' >> "$tmp"
done
sed -E -f "$tmp" <<< "$template"
rm "$tmp"
}
# mmmm this should be a library because i am so much copying those later
# _nested_random
function _nested_random() {
dd if=/dev/urandom bs=1 count=16 status=none | xxd -p
}
# nested_declare(ref)
function nested_declare() {
declare -g -a $1
}
# nested_add(ref, array)
function nested_add() {
local nested_id=$(_nested_random)
declare -n nested_ref=$2
declare -g -A _$nested_id
# poor man's array copy
for k in ${!nested_ref[@]}; do
declare -g -A _$nested_id[$k]="${nested_ref[$k]}"
done
local -n ref=$1
ref+=("$nested_id")
}
# nested_get(ref, i)
function nested_get() {
local -n ref=$1
declare -g -n res=_${ref[$2]}
}