summaryrefslogtreecommitdiff
path: root/rc/bin/rc-httpd
diff options
context:
space:
mode:
authorstanley lieber <stanley.lieber@gmail.com>2013-02-04 16:40:05 -0600
committerstanley lieber <stanley.lieber@gmail.com>2013-02-04 16:40:05 -0600
commitc877493fb00717de1a22860d88efb75ebf14ebec (patch)
treecb3cb0e47598e2880cdd20367925102856d41a5d /rc/bin/rc-httpd
parent0b212ed5054cd08bbc14a12936c07bc1ff5890a2 (diff)
downloadplan9front-c877493fb00717de1a22860d88efb75ebf14ebec.tar.xz
add rc-httpd
Diffstat (limited to 'rc/bin/rc-httpd')
-rwxr-xr-xrc/bin/rc-httpd/handlers/cgi54
-rwxr-xr-xrc/bin/rc-httpd/handlers/dir-index111
-rwxr-xr-xrc/bin/rc-httpd/handlers/error38
-rwxr-xr-xrc/bin/rc-httpd/handlers/redirect30
-rwxr-xr-xrc/bin/rc-httpd/handlers/serve-static30
-rwxr-xr-xrc/bin/rc-httpd/handlers/static-or-cgi14
-rwxr-xr-xrc/bin/rc-httpd/handlers/static-or-index5
-rwxr-xr-xrc/bin/rc-httpd/rc-httpd86
8 files changed, 368 insertions, 0 deletions
diff --git a/rc/bin/rc-httpd/handlers/cgi b/rc/bin/rc-httpd/handlers/cgi
new file mode 100755
index 000000000..96707630c
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/cgi
@@ -0,0 +1,54 @@
+#!/bin/rc
+fn filter_headers{
+ response='HTTP/1.1 200 OK'^$cr
+ lines=''
+ done=false
+ while(~ $done false){
+ line=`{read}
+ head=`{echo $line | awk '{print tolower($1)}'}
+ if(~ $head status:*){
+ tmp=`{echo $line | awk '{$1="" ; print}'}
+ response='HTTP/1.1 '^$"tmp^$cr
+ }
+ if not if(~ $line '')
+ done=true
+ if not
+ lines=$"lines^$"line^$cr^'
+'
+ }
+ echo $response
+ echo -n $"lines
+}
+
+fn run_cgi {
+ path=$cgi_path exec $"cgi_bin $params
+}
+
+cgi_bin=$1
+if(! ~ $cgi_bin /*){
+ pwd=`{pwd}
+ cgi_bin=$"pwd ^ / ^ $cgi_bin
+}
+
+cgi_dir=$*($#*)
+if(! test -d $cgi_dir){
+ cgi_dir=`{basename -d $cgi_dir}
+ cgi_dir=$"cgi_dir
+}
+
+if(! test -d $"cgi_dir){
+ error 500
+ exit
+}
+if(! test -f $cgi_bin -x $cgi_bin){
+ error 500
+ exit
+}
+do_log 200
+builtin cd $"cgi_dir
+run_cgi | {
+ filter_headers
+ emit_extra_headers
+ echo $cr
+ exec cat
+}
diff --git a/rc/bin/rc-httpd/handlers/dir-index b/rc/bin/rc-httpd/handlers/dir-index
new file mode 100755
index 000000000..39452bfd7
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/dir-index
@@ -0,0 +1,111 @@
+#!/bin/rc
+PATH_INFO=`{echo $PATH_INFO | urlencode -d}
+full_path=$"FS_ROOT^$"PATH_INFO
+full_path=$"full_path
+if(! test -d $full_path){
+ error 404
+ exit
+}
+if(! test -r $full_path -x $full_path){
+ error 503
+ exit
+}
+do_log 200
+builtin cd $full_path
+if(~ $"NOINDEXFILE ^ $"NOINDEX ''){
+ ifile=index.htm*
+ if(! ~ $ifile(1) *'*'){
+ PATH_INFO=$ifile(1)
+ FS_ROOT=''
+ exec serve-static
+ }
+}
+title=`{echo $SITE_TITLE | sed s,%s,^$"PATH_INFO^,}
+title=$"title
+lso=()
+switch($2){
+case size
+ # ls has no option to sort by size
+ # could pipe it through sort, I suppose
+case date
+ lso=-t
+}
+echo 'HTTP/1.1 200 OK'^$cr
+emit_extra_headers
+echo 'Content-type: text/html'^$cr
+echo $cr
+echo '<html>
+<head>
+<title>'^$title^'</title>
+<style type="text/css">
+ .size {
+ text-align: right;
+ padding-right: 4pt;
+ }
+ .day {
+ text-align: right;
+ padding-right: 3pt;
+ }
+ .datetime {
+ text-align: right;
+ }
+ .name {
+ text-align: right;
+ padding-left: 3pt;
+ }
+</style>
+</head>
+<body>'
+echo '<h1>'^$title^'</h1>'
+if(! ~ $PATH_INFO /)
+ echo '<a href="../">Parent directory</a>'
+echo '<table>'
+ls -lQ $lso | awk '
+function urlencode(loc){
+ # very minimal encoding, just enough for our static-file purposes
+ url=loc
+ gsub("%", "%25", url) # this one first!
+ gsub("\\$", "%24", url)
+ gsub("&", "%26", url)
+ gsub("\\+", "%2B", url)
+ gsub("\\?", "%3F", url)
+ gsub(" ", "%20", url)
+ gsub("\"", "%22", url)
+ gsub("#", "%23", url)
+ return url
+}
+function hrsize(size){
+ if(size > 1073741824) return sprintf("%.1fGB", size/1073741824)
+ if(size > 10485760) return sprintf("%iMB", size/1048576)
+ if(size > 1048576) return sprintf("%.1fMB", size/1048576)
+ if(size > 10240) return sprintf("%iKB", size/1024)
+ if(size > 1024) return sprintf("%.1fKB", size/1024)
+ return sprintf("%iB", size)
+}
+/^-/ {
+ print "<tr>"
+ print "<td class=\"size\">"hrsize($6)"</td>"
+ print "<td class=\"month\">"$7"</td>"
+ print "<td class=\"day\">"$8"</td>"
+ print "<td class=\"datetime\">"$9"</td>"
+ $1="" ; $2="" ; $3="" ; $4="" ; $5="" ; $6="" ; $7="" ; $8="" ; $9=""
+ sub("^ *?", "")
+ print "<td><a class=\"file name\" href=\""urlencode($0)"\">"$0"</a></td>"
+ print "</tr>"
+ $0=""
+}
+/^d/ {
+ print "<tr>"
+ print "<td class=\"size\"> </td>"
+ print "<td class=\"month\">"$7"</td>"
+ print "<td class=\"day\">"$8"</td>"
+ print "<td class=\"datetime\">"$9"</td>"
+ $1="" ; $2="" ; $3="" ; $4="" ; $5="" ; $6="" ; $7="" ; $8="" ; $9=""
+ sub("^ *?", "")
+ print "<td><a class=\"dir name\" href=\""urlencode($0)"/\">"$0"/</a></td>"
+ print "</tr>"
+}'
+echo '</table>
+
+</body>
+</html>'
diff --git a/rc/bin/rc-httpd/handlers/error b/rc/bin/rc-httpd/handlers/error
new file mode 100755
index 000000000..e38d41f01
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/error
@@ -0,0 +1,38 @@
+#!/bin/rc
+# DO NOT make this script callable directly from the web!
+fn do_error{
+ echo 'HTTP/1.1 '^$1^$cr
+ emit_extra_headers
+ echo 'Content-type: text/html'^$cr
+ echo $cr
+ echo '<html>
+<head>
+<title>'^$1^'</title>
+</head>
+<body>
+<h1>'^$1^'</h1>'
+ echo $2
+ echo '<p><i>rc-httpd at' $SERVER_NAME '</i>'
+ echo '
+ </body>
+ </html>
+ '
+}
+
+fn 404{
+ do_error '404 Not Found' \
+ 'The requested path '^$"location^' was not found on this server.'
+}
+
+fn 500{
+ do_error '500 Internal Server Error' \
+ 'The server has encountered an internal misconfiguration and is unable to satisfy your request.'
+}
+
+fn 503{
+ do_error '503 Forbidden' \
+ 'You do not have permission to access '^$"location^' on this server.'
+}
+
+do_log $1
+$1
diff --git a/rc/bin/rc-httpd/handlers/redirect b/rc/bin/rc-httpd/handlers/redirect
new file mode 100755
index 000000000..e223091eb
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/redirect
@@ -0,0 +1,30 @@
+#!/bin/rc
+if(~ $#2 0){
+ error 500
+ exit
+}
+switch($1){
+case perm*
+ do_log 301
+ echo 'HTTP/1.1 301 Moved Permanently'^$cr
+case temp*
+ do_log 302
+ echo 'HTTP/1.1 302 Moved Temporarily'^$cr
+case seeother
+ do_log 303
+ echo 'HTTP/1.1 303 See Other'^$cr
+case *
+ error 500
+ exit
+}
+echo 'Location: ' ^ $2 ^ $cr
+emit_extra_headers
+echo 'Content-type: text/html'^$cr
+echo $cr
+echo '<html><body>'
+if(~ $#3 0)
+ echo 'Browser did not accept redirect.'
+if not
+ echo $3
+echo '<a href="'^$"location^'/">Click here</a>'
+echo '</body></html>'
diff --git a/rc/bin/rc-httpd/handlers/serve-static b/rc/bin/rc-httpd/handlers/serve-static
new file mode 100755
index 000000000..3f7544286
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/serve-static
@@ -0,0 +1,30 @@
+#!/bin/rc
+full_path=`{echo $"FS_ROOT^$"PATH_INFO | urlencode -d}
+full_path=$"full_path
+if(~ $full_path */)
+ error 503
+if(test -d $full_path){
+ redirect perm $"location^'/' \
+ 'URL not quite right, and browser did not accept redirect.'
+ exit
+}
+if(! test -e $full_path){
+ error 404
+ exit
+}
+if(! test -r $full_path){
+ error 503
+ exit
+}
+do_log 200
+type=`{file -m $full_path}
+if(~ $type text/*)
+ max_age=3600 # 1 hour
+if not
+ max_age=604800 # 1 week
+echo 'HTTP/1.1 200 OK'^$cr
+emit_extra_headers
+echo 'Content-type: '^$type^$cr
+echo 'Cache-control: max-age='^$max_age^$cr
+echo $cr
+exec cat $full_path
diff --git a/rc/bin/rc-httpd/handlers/static-or-cgi b/rc/bin/rc-httpd/handlers/static-or-cgi
new file mode 100755
index 000000000..4d8a2d44a
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/static-or-cgi
@@ -0,0 +1,14 @@
+#!/bin/rc
+cgiargs=$*
+
+fn error{
+ if(~ $1 404)
+ exec cgi $cgiargs
+ if not
+ $rc_httpd_dir/handlers/error $1
+}
+
+if(~ $location */)
+ exec cgi $cgiargs
+if not
+ exec serve-static
diff --git a/rc/bin/rc-httpd/handlers/static-or-index b/rc/bin/rc-httpd/handlers/static-or-index
new file mode 100755
index 000000000..f0904f8a9
--- /dev/null
+++ b/rc/bin/rc-httpd/handlers/static-or-index
@@ -0,0 +1,5 @@
+#!/bin/rc
+if(~ $PATH_INFO */)
+ exec dir-index $params
+if not
+ exec serve-static
diff --git a/rc/bin/rc-httpd/rc-httpd b/rc/bin/rc-httpd/rc-httpd
new file mode 100755
index 000000000..e2a64948c
--- /dev/null
+++ b/rc/bin/rc-httpd/rc-httpd
@@ -0,0 +1,86 @@
+#!/bin/rc
+rc_httpd_dir=/rc/bin/rc-httpd
+path=(/bin $rc_httpd_dir/handlers)
+cgi_path=/bin
+SERVER_PORT=80 # default for CGI scripts, may be overridden by the Host header
+extra_headers='Server: rc-httpd'
+cr=
+
+fn do_log{
+ echo `{date} :: $SERVER_NAME :: $request :: \
+ $HTTP_USER_AGENT :: $1 :: $HTTP_REFERER >[1=2]
+}
+
+fn emit_extra_headers{
+ for(header in $extra_headers)
+ echo $"header^$cr
+}
+
+fn getline{ read | sed 's/'^$"cr^'$//g' }
+
+fn terminate{
+ echo `{date} connection terminated >[1=2]
+ exit terminate
+}
+
+fn trim_input{ read -c $CONTENT_LENGTH }
+
+request=`{getline}
+if(~ $#request 0)
+ terminate
+REQUEST_METHOD=$request(1)
+REQUEST_URI=$request(2)
+reqlines=''
+HTTP_COOKIE=''
+done=false
+while(~ $"done false){
+ line=`{getline}
+ if(~ $#line 0)
+ done=true
+ reqlines=$"reqlines$"line'
+'
+ h=`{echo $line | awk '{print tolower($1)}'}
+ switch($h){
+ case ''
+ done=true
+ case host:
+ tmp=`{echo $line(2) | sed 's/:/ /'}
+ SERVER_NAME=$tmp(1)
+ if(! ~ $#tmp 1)
+ SERVER_PORT=$tmp(2)
+ case referer:
+ HTTP_REFERER=$line(2)
+ case user-agent:
+ HTTP_USER_AGENT=`{echo $line | sed 's;[^:]+:[ ]+;;'}
+ case content-length:
+ CONTENT_LENGTH=$line(2)
+ case cookie:
+ cookie=`{echo $line | sed 's;^[^:]+:[ ]*;;'}
+ HTTP_COOKIE=$"HTTP_COOKIE^$"cookie^'; '
+ }
+}
+if(~ $REQUEST_URI http://*){
+ SERVER_NAME=`{echo $REQUEST_URI | sed '
+ s;^http://;;
+ s;/.*;;
+ '}
+ REQUEST_URI=`{echo $REQUEST_URI | sed 's;^http://[^/]+/?;/;'}
+}
+QUERY_STRING=`{echo $REQUEST_URI | sed 's;[^?]*\??;;'}
+params=`{echo $QUERY_STRING | sed 's;\+; ;g'}
+location=`{echo $REQUEST_URI | sed 's;\?.*;;'}
+location=`{echo $location | sed '
+ s;[^/]+/\.\./;/;g
+ s;/\./;/;g
+ s;//+;/;g
+'}
+if(~ $REQUEST_METHOD POST){
+ if(! ~ $"CONTENT_LENGTH '')
+ trim_input | exec $rc_httpd_dir/select-handler
+ if not{
+ echo 'POST without content-length, assuming no keep-alive.' >[1=2]
+ exec $rc_httpd_dir/select-handler
+ }
+}
+if not
+ . $rc_httpd_dir/select-handler