7b8bada6b4
care has to be taken when splitting the host into SERVER_NAME and SERVER_PORT, as ipv6 uses : in the host part. also do it consistently, the host can be set thru the request uri and the host header. set REMOTE_USER to empty string to prevent accidents. we do not handle chunked transfer encoding, just assuming the client doesnt do keep alive is wrong. we have to reject the post when the client tries chunked post with 411 "Length required" error.
102 lines
2.2 KiB
Bash
Executable file
102 lines
2.2 KiB
Bash
Executable file
#!/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=''
|
|
REMOTE_USER=''
|
|
done=false
|
|
chunked=no
|
|
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:
|
|
SERVER_NAME=$line(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 content-type:
|
|
CONTENT_TYPE=$line(2)
|
|
case cookie:
|
|
cookie=`{echo $line | sed 's;^[^:]+:[ ]*;;'}
|
|
HTTP_COOKIE=$"HTTP_COOKIE^$"cookie^'; '
|
|
case authorization:
|
|
REMOTE_USER=`{auth/httpauth $line(3)}
|
|
case transfer-encoding:
|
|
~ $line(2) chunked && chunked=yes
|
|
}
|
|
}
|
|
if(~ $REQUEST_URI *://* //*){
|
|
SERVER_NAME=`{echo $REQUEST_URI | sed '
|
|
s;^[^:]+:;;
|
|
s;^//([^/]+).*;\1;'}
|
|
REQUEST_URI=`{echo $REQUEST_URI | sed '
|
|
s;^[^:]+:;;
|
|
s;^//[^/]+/?;/;'}
|
|
}
|
|
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
|
|
'}
|
|
SERVER_NAME=`{echo $SERVER_NAME | sed 's;^(\[[^\]]+\]|[^:]+)\:([0-9]+)$;\1 \2;'}
|
|
if(~ $#SERVER_NAME 2){
|
|
SERVER_PORT=$SERVER_NAME(2)
|
|
SERVER_NAME=$SERVER_NAME(1)
|
|
}
|
|
if(~ $REQUEST_METHOD (PUT POST)){
|
|
if(! ~ $"CONTENT_LENGTH '')
|
|
trim_input | exec $rc_httpd_dir/select-handler
|
|
if not{
|
|
if(~ $chunked yes){
|
|
echo 'HTTP/1.1 411 Length required'^$cr
|
|
echo $cr
|
|
exit
|
|
}
|
|
exec $rc_httpd_dir/select-handler
|
|
}
|
|
}
|
|
if not
|
|
. $rc_httpd_dir/select-handler
|