CGI scripts with busybox httpd

For discussions about programming, programming questions/advice, and projects that don't really have anything to do with Puppy.
Message
Author
User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

CGI scripts with busybox httpd

#1 Post by sc0ttman »

I've been playing with shell based CGI scripts..

These essentially allow you to use shell script and all your normal system
commands inside a web page to create dynamic web pages, or in other
words, web based GUIs for system/terminal programs.

I wanted a lightweight way of creating dynamic web applications without installing any extra programs.

This method uses only the 'httpd' busybox applet, and BASH.

To use these examples, you'll need to create the folder ~/bin/ and add it to your $PATH:

Code: Select all

mkdir /root/bin
export PATH=/root/bin:$PATH
SETUP:

1. Create the folders /root/www/cgi-bin

2. Save the scripts below as /root/www/cgi-bin/test.sh and ~/www/cgi-bin/upload.sh

3. Run `chmod 755 /root/www/cgi-bin/test.sh` to make it executable and give it the right permissions

4. Run `DOCUMENT_ROOT=/root/www httpd -h /root/www -p 127.0.0.1:8080 -u nobody:nobody`

(Or you could start your web server with this wrapper I made, to get extra security
and automatic folder creation, file ownership/permission handling, etc)

5. Visit http://localhost:8080/ in your browser.

FEATURES OF TEST SCRIPT:

You can add ?foo=bar&stuff=whatever to the URL and these values will be displayed on the page as $GET['foo'], etc ..

You can submit the form on the page and then the form field values will be displayed on the page as $POST['foo'], etc ..

You can upload files - BUT BINARY FILES GET BROKEN IN THE UPLOAD ... Any fixes for that?!

File: test.sh

Code: Select all

#!/bin/bash

#===============================================================================
# Description:
#
#   a test script, demonstrating how to parse GET and POST
#   variables into associative arrays with BASH, httpd and CGI.
#
# Installation:
#
#   chmod 755 this script, and put it in your CGI bin (somewhere
#   like '$HOME/www/cgi-bin/test.sh')
#
# Usage:
#
#   Run the command `httpd -p 127.0.0.1:8080 -h ~/www` and visit
#   the URL 'http://localhost/cgi-bin/test.sh' in a web browser.
#
#   Adding a query string to the URL, or submitting the form on
#   the page will create $POST and $GET arrays containing the
#   key/value pairs of the POST/GET data.
#
#
# More info:
#
#   https://stackoverflow.com/questions/3919755/how-to-parse-query-string-from-a-bash-cgi-script
#
#===============================================================================

# Set some vars for later

title="CGI demo"

#===============================================================================

# Parsing GET and POST variables is horrible, let's make it easier.
# Let's put the query string and POST variables in into nice arrays.

# get POST vars (if any), with support for multi-line vars
POST_STRING="$(cat)"

# handling file uploads


if [ "$REQUEST_METHOD" = "POST" ]; then

  if [ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" != "" ];then

    if [ "$CONTENT_LENGTH" -gt 0 ]; then
      boundary=$(echo -n "$POST_STRING" | head -1 | tr -d '\r\n');
      filename=$(echo -n "$POST_STRING" | grep --text --max-count=1 -oP "(?<=filename=\")[^\"]*");
      file_content="$(echo -n "$POST_STRING" \
        | sed '1,/Content-Type:/d' \
        | tail -c +3 \
        | head --lines=-1 \
        | head --bytes=-4 \
        | head -n -4)"
    fi

  else

    # parse $QUERY_STRING
    saveIFS=$IFS                             # save IFS (internal field separator)
    IFS='=&'                                    # use '=' and '&' as internal field separators
    get_array=($QUERY_STRING)      # create an array from $QUERY_STRING
    post_array=($POST_STRING)       # create an array from $POST_STRING
    IFS=$saveIFS                             # restore IFS to its original state

    # Let's create associative array, so we can access the
    # query string and POST values like so: $GET['foo'] and $POST['foo']

    # The keys will be accessed using an exclamation point ${!array[@]},
    # the values are accessed using ${array[@]}, the total number of items
    # in the array can be accessed using a hash - ${#array[@]}.

    # Declare, is used to set variables, array  and attributes.The -a option
    # creates indexed arrays, -A creates associative arrays.

    # declare the $GET and $POST associative arrays (still empty at this point)
    declare -A GET
    declare -A POST

    # add the key/value pairs to $GET
    for ((i=0; i<${#get_array[@]}; i+=2))
    do
        key=${get_array[i]}
        value=${get_array[i+1]}
        GET[$key]=$value
    done

    # add the key/value pairs to $POST
    for ((i=0; i<${#post_array[@]}; i+=2))
    do
        key=${post_array[i]}
        value=${post_array[i+1]}
        POST[$key]=$value
    done

  fi

fi
#===============================================================================

# BEGIN OUTPUT

# IMPORTANT - set the content type first, then an empty newline!

echo 'Content-type: text/html; charset=UTF-8'
echo 'Status: 200 OK'
echo ''
echo ''

#===============================================================================

# BEGIN PAGE HTML
echo '<!DOCTYPE html>'
echo '<html>'
echo "<head><title>$title</title></head>"
echo "<body>"
echo "<h1>$title</h1>"

echo "<br>========================================================<br>"

echo "<p>ENV VARS</p>"
echo '<pre>'
uname -a
echo -n 'user = '; whoami
env | sort -u
echo "</pre>"

echo "<br>========================================================<br>"

# if we have a query string, print the relevant vars
if [ "$QUERY_STRING" != '' ];then
  echo '<p>$QUERY_STRING:</p>'
  echo "<pre>"
  echo $QUERY_STRING
  echo "</pre>"

  echo '<p>$GET[@] array:</p>'
  echo "<pre>"
  # print the key/value pairs:
  for x in "${!GET[@]}"
  do
    echo '$GET'"[$x] = ${GET[$x]}"
  done
  echo "</pre>"
else
  echo "<p>Add a query string to the URL to see it parsed here.</p>"
fi

echo '<br>========================================================<br>'

# if we have a POST vars, print the relevant vars
if [ "$POST_STRING" != "" ];then
  # file uploads
  if [ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" != "" ];then
    echo "<br>"
    echo "<p>File upload(s):</p>"
    echo "<pre>"
    echo "boundary: $boundary"
    echo "filename: $filename"
    echo "file contents:"
    echo "</pre>"
    echo "<div style=\"background-color:#dfdfdf;\"><pre>${file_content}</pre></div><p>more text..</p>"
  else
    echo '<p>$POST_STRING:</p>'
    echo "<pre>"
    echo $POST_STRING
    echo "</pre>"

    echo '<p>$POST[@] array:</p>'
    echo "<pre>"
    # print the key/value pairs:
    for x in "${!POST[@]}"
    do
      echo '$POST'"[$x] = ${POST[$x]}"
    done
    echo "</pre>"
  fi

else
  echo '<form id="file-form" action="upload.sh" method="post" enctype="multipart/form-data">
    Select file to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload File" name="submit">
    </form>'

  echo '<br>========================================================<br>'

  echo '<p>Enter a month and year then click "Submit" to see the POST variables here.</p>'
  echo '<form id="text-form" method="post" action="">'
  echo '  <p>Month: <input type="text" name="month" value="" style="width: 90px" /></p>'
  echo '  <p>Year: <input type="text" name="year" value="" style="width: 90px" /></p>'
  echo '  <input type="submit" value="Submit" />'
  echo '</form>'
fi

echo "</body>"
echo "</html>"
echo ""

And upload.sh

Code: Select all

#!/bin/bash

#======================================
# Description:
#
#   A dumb script for handling file uploads.. CANNOT handle binary files!
#
# Installation:
#
#   chmod 755 this script, and put it in your CGI bin
#
# Usage: POST the file to this script using something like this:
#
#   <form action="" method="post" enctype="multipart/form-data">
#     <input type="file" name="fileToUpload" id="fileToUpload">
#     <input type="submit" value="Upload File" name="submit">
#   </form>
#
# Or, use curl to upload files via the terminal:
#
#   curl http://localhost:8080/cgi-bin/upload.sh -F "MyFile=@/path/to/a/file"
#
#======================================

# This scripts needs the following env vars:

# DOCUMENT_ROOT          # the web server root folder (usually /var/www/)
# REQUEST_METHOD        # GET or POST
# CONTENT_TYPE              # 'multipart/form-data' or 'application/x-www-form-urlencoded'
# CONTENT_LENGTH         # length of POST data

function error500 {
  echo 'Content-type: text/html; charset=UTF-8'
  echo 'Status: 500 Internal Server Error'
  echo ''
  echo ''
}

if [ ! -d "${DOCUMENT_ROOT}" ] || \
   [ "$REQUEST_METHOD" != "POST" ] || \
   [ "$(echo "$CONTENT_TYPE" | grep -m1 'multipart/form-data;')" = "" ] || \
   [ "$CONTENT_LENGTH" -eq 0 ]; then
  error500
  exit 1
fi

#if [ ! -d ${DOCUMENT_ROOT}/downloads/ ]then
  mkdir ${DOCUMENT_ROOT}/downloads/ &>/dev/null
  chmod 744 ${DOCUMENT_ROOT}/downloads/ &>/dev/null
  chown nobody:nobody ${DOCUMENT_ROOT}/downloads/ &>/dev/null
#fi

# all POST vars are received as std input
POST_DATA="$(cat)"

# get the file meta info and contents
boundary=$(echo -n "$POST_DATA" | head -1 | tr -d '\r\n');
filename=$(echo "$POST_DATA" | sed -n '2!d;s/\(.*filename=\"\)\(.*\)\".*$/\2/;p')
file=$(echo "$POST_DATA" | sed -n "1,/$boundary/p" | sed '1,4d;$d')

# save the file
echo "$file" > ${DOCUMENT_ROOT}/downloads/"$filename" || \
{
  error500
  exit 1
}

chmod 755 ${DOCUMENT_ROOT}/downloads/"$filename"

#--------------------------

# BEGIN OUTPUT
echo 'Content-type: text/html; charset=UTF-8'
echo 'Status: 200 OK'
echo ''
echo ''

echo "File '$filename' uploaded OK"

exit 0
Last edited by sc0ttman on Wed 30 Jan 2019, 22:41, edited 12 times in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#2 Post by sc0ttman »

To run the webserver with better security, you can hide most of your environment
variables by prefixing the httpd command with an empty environment.

Like so:

Code: Select all

env - httpd -p 127.0.0.1:8080
Or, to include only $PATH in the exported environment:

Code: Select all

env - PATH="$PATH" httpd -p 127.0.0.1:8080
For all the info on httpd settings and using /etc/httpd.conf, see https://git.busybox.net/busybox/tree/networking/httpd.c
Last edited by sc0ttman on Sun 27 Jan 2019, 23:25, edited 1 time in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#3 Post by sc0ttman »

Related scripts and functions:

URL encode and decode BASH functions:

Code: Select all

# https://unix.stackexchange.com/questions/159253/decoding-url-encoding-percent-encoding
urlencode() {
    # urlencode <string>
    local LC_CTYPE=C  # fix multibyte characters (thanks MochiMoppel)
    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c"
        esac
    done
}

urldecode() {
    # urldecode <string>
    local LC_CTYPE=C # fix multibyte characters (thanks MochiMoppel)
    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}
slugify.sh

Code: Select all

#!/bin/bash

# usage: slugify.sh "some string"

# converts strings to santised, lower case, dash separated strings with
# whitespace and special characters removed.

# See these links for more info:
#  https://automatthias.wordpress.com/2007/05/21/slugify-in-a-shell-script/
#  https://stackoverflow.com/questions/47050589/create-url-friendly-slug-with-pure-bash
#  https://gist.github.com/oneohthree/f528c7ae1e701ad990e6

slugified="$(echo -n "${@}" | sed -e 's/[^[:alnum:]]/-/g' 2>/dev/null | tr -s '-' | tr A-Z a-z | sed -e 's/-$//g' 2>/dev/null)"
RETVAL=$?

if [ "$slugified" = "" ] || [ $RETVAL -gt 0 ]
then
  slugified="$(echo "$1" | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)"
  RETVAL=$?
fi

[ "$slugified" != "" ] && echo "$slugified"

exit $RETVAL
Last edited by sc0ttman on Wed 30 Jan 2019, 22:01, edited 3 times in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#4 Post by sc0ttman »

Tutorial: Using SQLite3 databases in Bash CGI scripts

Seems like an easy way to add database support.

Sqlite3 is small, fast, powerful and included in most Puppies by default (I think!).

See near the end.. Skip the awk examples..
Last edited by sc0ttman on Mon 28 Jan 2019, 21:48, edited 1 time in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
puppy_apprentice
Posts: 299
Joined: Tue 07 Feb 2012, 20:32

#5 Post by puppy_apprentice »

Puppy without X but with web interface is closer. I can imagine some day Puppy on routers or IoT devices ;)

I wonder if we could use httpd and CGI scripts with mdviewer as a GUI for desktop programs?
Last edited by puppy_apprentice on Sun 27 Jan 2019, 20:36, edited 1 time in total.

User avatar
rufwoof
Posts: 3690
Joined: Mon 24 Feb 2014, 17:47

#6 Post by rufwoof »

Really cool sc0ttman. Hadn't even realised busybox contained httpd until I saw this thread. Thanks.
[size=75]( ͡° ͜ʖ ͡°) :wq[/size]
[url=http://murga-linux.com/puppy/viewtopic.php?p=1028256#1028256][size=75]Fatdog multi-session usb[/url][/size]
[size=75][url=https://hashbang.sh]echo url|sed -e 's/^/(c/' -e 's/$/ hashbang.sh)/'|sh[/url][/size]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

Haserl

#7 Post by sc0ttman »

Even easier (but requires an extra dependency) is Haserl

Haserl is something like a simple, tiny PHP..

Homepage: http://haserl.sourceforge.net/

Tutorial: http://duke-blog.appspot.com/id/20130807094549293

Example:

1. Add this line in /etc/httpd.conf:

Code: Select all

*.hs:/usr/local/bin/haserl
* or whatever the path to 'haserl' is on your system

Scripts ending in .hs should now use Haserl instead of Bash when run by httpd.

2. Now we need a Haserl script to put in the cgi-bin folder:

File: myfile.hs:

Code: Select all

#!/usr/local/bin/haserl
Content-Type: text/html
 
<html>
<body>
 
<% if [ $REQUEST_METHOD == "POST" ]; then %>
 
<%   if [ $POST_twins == "sagill" ]; then %>
correct
<%   else %>
error
<%   fi %>
 
<% else %>
 
<form method="post" action="./test.tt" >
  twins: <input type="text" name="twins"/><br/>
  <input type="submit" value="Submit" />
</form>
 
<% fi %>
 
</body>
</html>

Differences compared to Bash CGI:

* automatic handling of GET and POST vars
* no need to echo the HTML
* much cleaner code

Haserl is available in the Debian repos.. probably in the repos of most other popular distros too.

NOTE:

With some of my code above (parsing GET and POST) as well as some good redirection
stuff (removing the need to 'echo' everything), it should be possible to achieve nice clean Bash CGI
code, making Haserl more of a "nice to have" option.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
MochiMoppel
Posts: 2084
Joined: Wed 26 Jan 2011, 09:06
Location: Japan

#8 Post by MochiMoppel »

sc0ttman wrote:URL encode and decode BASH functions:

Code: Select all

# https://unix.stackexchange.com/questions/159253/decoding-url-encoding-percent-encoding
urlencode() {
    # urlencode <string>
    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c"
        esac
    done
}

urldecode() {
    # urldecode <string>
    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}
Does not work correctly with multibyte characters.
For example the Euro sign € should be encoded to %E2%82%AC. Above code produces only %AC.
Works if you add local LC_CTYPE=C

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#9 Post by sc0ttman »

Thanks MochiMoppel.. I knew it wasn't bulletproof.. But that is a nice small fix!
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#10 Post by sc0ttman »

For super fast pages, you could even do it in C or C++

Tutorial: https://linuxconfig.org/simple-cgi-and- ... untu-linux

From the link above:

File: example-c.c

Code: Select all

#include <stdio.h>

int main(void)
{
    printf("Content-Type: text/plain \n\n");
    printf("Hello world \n");
}
Save the code above to ~/www/example-c.c and compile it like so:

Code: Select all

gcc -o ~/www/cgi-bin/example-c example-c.c
Now you should be able to access your C compiled CGI script with:

http://localhost/cgi-bin/example-c
Last edited by sc0ttman on Tue 29 Jan 2019, 12:03, edited 2 times in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#11 Post by sc0ttman »

Another good resource on BASH CGI scripts: http://www.icosaedro.it/apache/cgi-bash.html (in Italian, but easy enough)

From the link above:

Example of showing an image:

Code: Select all

 #!/bin/bash
echo "Content-Type: image/gif"
echo
cat figura.gif
Example of setting cookies:

Code: Select all

        #!/bin/bash


        function setcookie()
        #
        # $1 = nome variabile
        # $2 = valore variabile
        # $3 = durata (secondi)
        # $4 = path (opzionale)
        #
        {
                value=$( echo -n "$2" | urlencode )
                if [ -z "$4" ]; then
                        path=""
                else
                        path="; Path=$4"
                fi
                echo -n "Set-Cookie: $1=$value$path; expires="
                date -u --date="$3 seconds" "+%a, %d-%b-%y %H:%M:%S GMT"
        }

        # Intestazione MIME:
        echo "Content-Type: text/plain"
        setcookie tuocodice 1234567 60
        setcookie tuonome   "Mario" 60
        setcookie tuocogn   "Rossi" 60
        echo

        # Corpo del messaggio:
        echo "Cookie ritornato dal browser: $HTTP_COOKIE"
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#12 Post by sc0ttman »

A simple example using redirection to avoid using lots of echos:

Code: Select all

#!/bin/bash
echo "Content-type: text/html"
echo ""

cat << 'EOF'
<!DOCTYPE html>
<html>
  <head>
    <title>Template</title>
  </head>
  <body>
    <h1>Hello, world</h1>
  </body>
</html>
EOF
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#13 Post by sc0ttman »

More examples here: https://github.com/m13253/bash-cgi

These scripts above show how to:
* use caching and some other stuff

-------------------------

BashLib: http://bashlib.sourceforge.net/
bashlib is a shell script that makes CGI programming in the bash shell easier, or at least more tolerable. It contains a few functions that get called automatically and place form elements (from POSTs and GETs) and cookies in your environment. It also contains complete documentation on how to use these variables and how to set cookies manually.
This is a great library to help writing CGI scripts.. It has influences many of the others.

Usage:
Using bashlib is pretty straight-forward. More important, however, is knowing what to do with the variables once they come into your script and knowing how to write CGI scripts. (This script is not running here, for obvious reasons.)

Code: Select all

#!/bin/bash

# this sources bashlib into your current environment
. /usr/local/lib/bashlib

echo "Content-type: text/html"
echo ""

# OK, so we've sent the header... now send some content
echo "<html><title>Crack This Server</title><body>"

# print a "hello" if the username is filled out
username=`param username`
if [ -n "x$username" != "x" ] ; then
    echo "<h1>Hello, $username</h1>
fi

echo "<h2>Users on `/bin/hostname`</h2>"
echo "<ul>"

# for each user in the passwd file, print their login and full name
# bold them if they are the current user
for user in $(cat /etc/passwd | awk -F: '{print $1 "\t" $5}') ; do
    echo "<li>"
    if [ "$username" = "$user" ] ; then
        echo "<strong>$user</strong>"
    else
        echo "$user"
    fi
    echo "</li>"
done
echo "</ul>"
echo "</body></html>"

-------------------------

Also see cgibashopts: https://github.com/ColasNahaboo/cgibashopts

"A BASH library to parse web forms parameters for bash shell web CGI scripts, even with binary file uploads "

It's a nice library that makes handling GET, POST, and file uploads easier.
Last edited by sc0ttman on Tue 29 Jan 2019, 20:57, edited 1 time in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#14 Post by sc0ttman »

Bash on Steroids: a simple web framework in Bash

Allows much cleaner code in your CGI files.
(similar to Haserl, above, but in pure Bash - no extra deps)

Homepage: https://github.com/tinoschroeter/bash_on_steroids


Features:

* embed shell code in your HTML using <?bash ... ?> or <? ... ?> tags
* GET and POST vars available as bash variables
* Example: `myfile.cgi?name=bob&age=21` becomes ${name} and ${age}
* use the bos.sh script to build a regular Bash CGI file


Usage:

Create a file like this one:

File: index.htsh

Code: Select all

<!DOCTYPE html>
<html>
 <body>
 <ul>
    <?bash
      for x in John Paul George Ringo; do
        echo "<li>$x</li>"
      done
      ?>
</ul>
</body>
</html>
Then, run the bos.sh script from the same dir as your .htsh file,
the .cgi file that you put in your cgi-bin folder will be generated for you:

Code: Select all

$ ./bos.sh 
$ index.htsh --->> /usr/lib/cgi-bin/index.cgi

NOTE: I had to edit the bos.sh files a little to make it work:

1. At the top of bos.sh, I changed the path to my cgi-bin

2. In index.htsh, I changed the form attribute from action="/" to action=""

.. then the generated .cgi files worked for me :)
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#15 Post by sc0ttman »

Bash solution for Markdown to HTML:

(from https://gist.github.com/jaburns/33d88f4aa99bb4ab6ad6)

Caution:

This script uses the GitHub API to do the conversion.. Therefore, it requires an internet
connection and you should not convert any Markdown files which contain sensitive or
private information.

Usage:

Code: Select all

md2html.sh <markdown file>   # print HTML to terminal (stdout)
or

Code: Select all

md2html.sh file.md > file.html  # save as HTML file 
To use it:

Save the code below as md2html.sh, make it executable.

Code: Select all

#!/usr/bin/env bash

# Markdown to HTML (https://gist.github.com/jaburns/33d88f4aa99bb4ab6ad6)

# NOTE: This script uses the GitHub API to convert the markdown to HTML,
#       and therefore requires an internet connection.

# Usage examples:

#  md2html file.md              # print HTML to stdout
#  md2html file.md > file.html  # create HTML file


# escape slashes and new lines in the given markdown
data="$(
    cat "$1" \
      | sed 's/"/\\"/g' \
      | sed ':a;N;$!ba;s/\n/\\n/g' \
)"

if [[ -z "$2" ]]; then
    context=''
else
    context=",\"context\":\"$2\""
fi


#echo '<!DOCTYPE html>'
#echo '<html>'
#echo '<head>'
#echo '<title>Page Title</title>'
#echo '</head>'
#echo '<body>'

# use the GitHub API to do our conversion for us
curl -s --data "{\"text\":\"$data\",\"mode\":\"gfm\"$context}" 'https://api.github.com/markdown'

#echo '</body>'
#echo '</html>'

unset data
unset context
unset html

...and here's a very simple markdown file to test the conversion:

Save as test.md:

Code: Select all

# Hello

This is a list:

- one
- two

## Iam an h2

Some more para text

```bash
# some bash code
echo "hello"
```

### h3 above table

| foo | bar | baz |
| --- | --- | --- |
| 1   | 2   | 3   |
| 3   | 4   | 5   |

More text.

Another para.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#16 Post by sc0ttman »

Happy to take ideas for good stuff we could make using Bash, CGI, busybox httpd, sqlite3, related shell scripts:

* web based GUIs
* system monitoring/management/setup tools
* build tools (blog builders, documentation/wiki builders, etc)
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#17 Post by sc0ttman »

A modified version of my web server loader script...

Aside from loading your busybox httpd web server, it also does the following:

* runs the web server as user nobody (better security)
* runs with a minimal set of env vars (better security)
* sets correct owner and permission for the given web root
* adds $DOCUMENT_ROOT and other common CGI environment vars (some scripts require them)
* gives an easy way to kill the web server

Usage:

Code: Select all

webserver [dir] [port]
Without options it defaults to

Code: Select all

webserver /var/www 8080

Here is the script:

Code: Select all

#!/bin/ash
# simple web server script, which depends on Busybox only

# Usage:    webserver [DIR] [PORT]
#
# ..where DIR is directory to use as the the web root
# (defaults to /var/www)

# use `kill_webserver` to kill the server

if [ "$1" = '-h' ] || [ "$1" = '--help' ];then
  echo "Usage:"
  echo
  echo "  webserver <path-to-webroot> <port>"
  echo
  echo "Note, if no options given, the defaults will be:"
  echo
  echo "  webserver /var/www/ 8080"
  echo
  exit 0
fi

# set DIR and PORT
dir="${1:-/var/www}"
portnum="${2:-8080}"

# create $dir if needed
[ "$dir" != "."  ] && \
[ "$dir" != ".." ] && \
[  ! -d "$dir"   ] && \
  mkdir -p "$dir" 2>/dev/null

chmod -R 755 "$(realpath "$dir")"
chown -R nobody:nobody "$(realpath "$dir")"

httpd=$(which httpd)

if [ "$httpd" = "" ];then
  echo "Error: command 'httpd' not installed."
  exit 1
fi

# run the webserver with a restricted environment, allowing only a limited
# set of variables to be exposed to the webserver:
#
#   env -           reset/clear the environment
#   PATH            paths to commands (obviously)
#   DOCUMENT_ROOT   the web root folder (needed/expected by many scripts)
#   SERVER_NAME     the host name of the server, may be dot-decimal IP address
#   SERVER_PORT     the port being used by the server

echo "env - \
  PATH=\"$PATH\" \
  DOCUMENT_ROOT=\"$dir\" \
  SERVER_NAME=localhost \
  SERVER_PORT=$portnum \
  $httpd \
    -p 127.0.0.1:${portnum} \
    -h \"${dir}\"

" > /tmp/httpd_cmd

# run the web server as user 'nobody'
su -pm nobody -c "$(cat /tmp/httpd_cmd)" &

sleep 0.2

# get the PID of the running web server
httpd_pid=$(ps -e | grep httpd | cut -f1 -d' ')

if [ "$httpd_pid" != "" ];then
  echo '  => busybox httpd -p 127.0.0.1:'$portnum' -h "'$dir'" -u nobody:nobody &'
  echo
  echo "Started server in $(realpath ${dir:-/var/www}) (pid $httpd_pid)"

  echo "#!/bin/bash"     > ~/bin/kill_webserver
  echo "kill $httpd_pid" > ~/bin/kill_webserver

  chmod +x ~/bin/kill_webserver

  echo
  echo "Kill it with:"
  echo "  kill_webserver"
fi

# clean up
unset dir
unset portnum
unset httpd
unset httpd_pid
unset host_name

exit 0
Last edited by sc0ttman on Fri 01 Feb 2019, 10:25, edited 2 times in total.
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
puppy_apprentice
Posts: 299
Joined: Tue 07 Feb 2012, 20:32

#18 Post by puppy_apprentice »

On Slacko64 6.3.2:

Code: Select all

# ./webserv 
  => busybox httpd -p 127.0.0.1:8080 -h "/var/www" -u nobody:nobody &

Started server in /var/www (pid 6565)
./webserv: line 75: can't create /root/bin/kill_webserver: nonexistent directory
./webserv: line 75: can't create /root/bin/kill_webserver: nonexistent directory
chmod: cannot access ‘/root/bin/kill_webserver’: No such file or directory

Kill it with:
  kill_webserver

User avatar
sc0ttman
Posts: 2812
Joined: Wed 16 Sep 2009, 05:44
Location: UK

#19 Post by sc0ttman »

puppy_apprentice wrote:On Slacko64 6.3.2:

Code: Select all

# ./webserv 
  => busybox httpd -p 127.0.0.1:8080 -h "/var/www" -u nobody:nobody &

Started server in /var/www (pid 6565)
./webserv: line 75: can't create /root/bin/kill_webserver: nonexistent directory
./webserv: line 75: can't create /root/bin/kill_webserver: nonexistent directory
chmod: cannot access ‘/root/bin/kill_webserver’: No such file or directory

Kill it with:
  kill_webserver
Oh... Doh! I forgot ...

You'll need to create ~/bin/ and add it to your $PATH:

Code: Select all

mkdir /root/bin
export PATH=/root/bin:$PATH
I'll add that to the main post..
[b][url=https://bit.ly/2KjtxoD]Pkg[/url], [url=https://bit.ly/2U6dzxV]mdsh[/url], [url=https://bit.ly/2G49OE8]Woofy[/url], [url=http://goo.gl/bzBU1]Akita[/url], [url=http://goo.gl/SO5ug]VLC-GTK[/url], [url=https://tiny.cc/c2hnfz]Search[/url][/b]

User avatar
technosaurus
Posts: 4853
Joined: Mon 19 May 2008, 01:24
Location: Blue Springs, MO
Contact:

#20 Post by technosaurus »

I did some stuff like this ~8 years ago in the bashbox thread and have been meaning to resurrect it after having tried slitaz. The idea was to be able to edit system configuration in a meaningful way without being reliant on a specific GUI toolkit, so for console it meant a web server with cgi-scripts and minimal usage of javascript (only for supplemental niceties and then only a subset that is supported by console based browsers like edbrowse, links/elinks and netsurf-framebuffer)

I have links to slitaz's tools in my web programming thread which also has the basis for a javascript based desktop - some of which could be rewritten for use with cgi scripts (just the css and click based stuff, not the drag based stuff-that would be too laggy)

Of course this doesn't need to be limited to system configuration, most gtkdialog programs could be ported.

BTW the most recent version of busybox just added support for builtin scripts (not sure how they handle duplicate names though- such as /init and /sbin/init)

Edit: Re: server startup - consider using httpd.conf to default to only allowing localhost (127.0.0.1) with options to allow 192.168.0.* and 10.?.?.? (i can't remember what that one is at the moment) localhost for security and the others to allow headless operation of things like a raspberry pi or other IOT device

This would be a good basis to resurrect Quirky (if Barry agrees). I'd be on board if you could convince goingnuts and/or amigo to be involved.
Check out my [url=https://github.com/technosaurus]github repositories[/url]. I may eventually get around to updating my [url=http://bashismal.blogspot.com]blogspot[/url].

Post Reply