#! /bin/sh
# PCP QA Test No. 660
# checks basic pmwebd functionality
#
# Copyright (c) 2013-2016 Red Hat, Inc.  All Rights Reserved.
#
seq=`basename $0`
echo "QA output created by $seq"

. ./common.webapi

which curl >/dev/null 2>&1 || _notrun "No curl binary installed"
[ -f ${PCP_BINADM_DIR}/pmwebd ] || _notrun "pmwebd package not installed"
# nb: wget dispreferred because of its processing of .. relative links,
# so it's harder to stress pmwebd's base-directory-escaping logic

# only restart pmwebd if it was running before the QA test starts
#
if [ -n "`_get_pids_by_name pmwebd`" ]
then
    restart_pmwebd=true
else
    restart_pmwebd=false
fi

# move to a new port as pmproxy is going to take over the care and
# feeding of port 44323
#
PORT=44324

$sudo rm -fr $tmp.dir
$sudo rm -f $tmp.*
rm -f $seq.full

signal=$PCP_BINADM_DIR/pmsignal
status=1	# failure is the default!
username=`id -u -n`

_cleanup()
{
    $sudo rm -f $here/src/index.html
    $sudo rm -fr $tmp.dir
    $sudo $signal -a pmwebd >/dev/null 2>&1
    _restore_auto_restart pmwebd
    $restart_pmwebd && _service pmwebd restart >/dev/null 2>&1
    $sudo rm -f $tmp.*
}
trap "_cleanup; exit \$status" 0 1 2 3 15

#
# on one QA host (bozo) where bind is running (may or not be related)
# the test emits
# * Hostname was NOT found in DNS cache
# instead of
# * About to connect() to LOCALHOST port $PORT (####)
# but otherwise works.
# This error message apparently comes from deep inside the non-PCP code.
# So filter to remove both variants to ensure the test is deemed to
# have passed.
#
# Also there is some other noise from a similar source but different
# causes, e.g.
#
# * Connected to LOCALHOST (LOCALADDR) port $PORT (####)
# * HTTP 1.1 or later with persistent connection, pipelining supported
# * additional stuff not fine transfer.c:1037: 0 0
# *   Trying LOCALADDR...
# * Connection refused
# * connect to ::1 port $PORT failed: Connection refused
# * Mark bundle as not supporting multiuse
# WARNING: gnome-keyring:: couldn't connect to: ...
# * TCP_NODELAY set
# * Curl_http_done: called premature == 0
# * [othewise blank line]
# [blank line]
#
_filter()
{
    sed \
	-e '/Hostname was NOT found in DNS cache/d' \
	-e "/About to connect() to LOCALHOST port $PORT (####)/d" \
	-e "/^\* Connected to LOCALHOST (LOCALADDR) port $PORT/d" \
	-e '/^\* HTTP 1.1 or later with persistent connection/d' \
	-e '/^\* additional stuff not fine/d' \
	-e '/^\*  *Trying LOCALADDR/d' \
	-e '/^\* Connection refused/d' \
	-e '/^\* connect to .*: Connection refused/d' \
	-e '/^\* Mark bundle as not supporting multiuse/d' \
	-e '/WARNING: gnome-keyring::/d' \
	-e '/^\* TCP_NODELAY set/d' \
	-e '/^\* Curl_http_done: called premature == 0/d' \
	-e '/^\* Expire in /d' \
	-e "s/LOCALHOST:$PORT/LOCALHOST:PORT/" \
	-e '/^\*$/d' \
	-e '/^[ 	]*$/d'
}

# lines like
# [Fri Mar 29 08:44:17] pmwebd(15404): [127.0.0.1:35852] url.size() 3 not 4 url[1]="pmapi" url[2]="", new_contexts_p=0
#
_filter_log_url()
{
    sed \
	-e 's/[A-Z][a-z][a-z] [A-Z][a-z][a-z]  *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/DATE/' \
	-e 's/pmwebd([0-9][0-9]*)/pmwebd(PID)/' \
	-e 's/:[0-9][0-9]*]/:PORT]/' \
	-e 's/ \[.*:PORT/ [HOST:PORT/' \
    # end
}

ipv6local=`_ipv6_localhost 2>>$seq.full`
echo "ipv6local=$ipv6local" >>$seq.full

_stop_auto_restart pmwebd # see GH #394
_service pmwebd stop >/dev/null 2>&1
$sudo $signal -a pmwebd >/dev/null 2>&1

webargs="-U $username -P"

echo | tee -a $seq.full
echo "=== pmwebd default startup  ===" | tee -a $seq.full
$PCP_BINADM_DIR/pmwebd $webargs -p $PORT -D libweb -l $tmp.log -v -t10 &

echo "pid=$!" >>$seq.full
_wait_for_pmwebd_logfile $tmp.log $PORT

# prepare the expected output file based on detected mode
cat $tmp.log >>$seq.full
rm -f $seq.out
if grep -q IPv6 $tmp.log; then
    grep -q IPv4 $tmp.log || _notrun "QA host running in IPv6 mode only"
    ln $seq.out.46 $seq.out	# ipv6 + ipv4
else
    ln $seq.out.4 $seq.out	# ipv4 only
fi

curl -s -S "http://localhost:$PORT/pmapi/context?local=ANYTHING" \
| tee -a $seq.full \
| awk '{print $2}'
echo >>$seq.full
if grep -q IPv6 $tmp.log; then
    curl -s -S "http://$ipv6local:$PORT/pmapi/context?local=ANYTHING" \
    | tee -a $seq.full \
    | awk '{print $2}'
fi

echo | tee -a $seq.full
echo "=== pmwebd security constraints, file service ===" | tee -a $seq.full
$sudo $signal -a pmwebd >/dev/null 2>&1
sleep 2		# let it shutdown

cat $tmp.log >> $seq.full
$PCP_BINADM_DIR/pmwebd $webargs -p $PORT -D libweb -R `pwd` -c 2222 -L -h localhost -N -vv -l $tmp.log >$tmp.err 2>&1 &
sleep 2		# let it start up
cat $tmp.err >> $seq.full

# Note on curl use:
# extra echo because line from curl may be missing a \n and this
# breaks some sed implementations (in _webapi_response_filter), and
# then need post-filter sed to remove empty line (if any)
#
echo "+++ should fail due to -N" | tee -a $seq.full
( curl -s -S "http://localhost:$PORT/pmapi/context?local=anything"; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d'
echo | tee -a $seq.full

echo "+++ should fail due to nonexistent context#" | tee -a $seq.full
( curl -s -S "http://localhost:$PORT/pmapi/2225/_fetch"; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d'
echo | tee -a $seq.full

echo "+++ should fail with a different error (insufficient elements; ie pmFetch failed)" | tee -a $seq.full
# NB: the curl -v part reports http headers too, for ACAO presence assertion
( curl -s -v -S "http://localhost:$PORT/pmapi/2222/_fetch?names=" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _filter
echo | tee -a $seq.full

echo "+++ should fail with a different error (insufficient elements; ie pmFetch failed)" | tee -a $seq.full
( curl -s -S "http://localhost:$PORT/pmapi/2223/_fetch?pmids="; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d'
echo | tee -a $seq.full

# filter for responses from newer microhttpd libraries, where
# symlink paths are rewritten (with verbose diagnostics that
# indicate this, also).
# Note: the request below must still generate a 400 response.
_symlink_response_filter()
{
    sed \
	-e 's,/../../etc/passwd,/etc/passwd,g' \
	-e '/Rebuilt URL to:.*\/etc\/passwd/d' \
    #end
}

echo "+++ should fail due to suspicious pmresapi path name" | tee -a $seq.full
( curl -s -v -S "http://localhost:$PORT/../../etc/passwd" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _symlink_response_filter \
| _filter
echo | tee -a $seq.full

echo "+++ should fail due to non-enablement of graphite" | tee -a $seq.full
( curl -s -v -S "http://localhost:$PORT/graphite/render?target=*" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _filter

echo | tee -a $seq.full
echo "+++ should pass, feed this very script" | tee -a $seq.full
curl -s -S "http://localhost:$PORT/$seq" > $tmp.out2
diff $tmp.out2 $0 && echo file service ok

echo "+++ should not fail after patch from GH PR594" | tee -a $seq.full
( curl -s -v -S "http://localhost:$PORT/pmapi/1/metrics" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _filter
echo | tee -a $seq.full

echo "+++ should fail with incomplete pmapi request url.size=2" | tee -a $seq.full
( curl -s -v -S "http://localhost:$PORT/pmapi" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _filter
grep 'url\.size.* 2' $tmp.log | _filter_log_url
echo | tee -a $seq.full

echo "+++ should fail with incomplete pmapi request url.size=3" | tee -a $seq.full
( curl -s -v -S "http://localhost:$PORT/pmapi/12345" 2>&1; echo ) \
| tee -a $seq.full \
| _webapi_response_filter \
| sed -e '/^$/d' \
| _filter
grep 'url\.size.* 3 .*12345' $tmp.log | _filter_log_url
echo | tee -a $seq.full

echo "--- pmwebd log for main QA tests ---" >> $seq.full
cat $tmp.log >> $seq.full

# look for fd leak in src/ -> src/index.html redirection
echo OK > $here/src/index.html
c=0
maxfd=`ulimit -n`
while [ $c -lt $maxfd ]; do
   curl -s -L -S "http://localhost:$PORT/src/" > $tmp.out
   c=`expr $c + 1`
done

grep -q PMWEBD.error $tmp.out && echo fd leak || echo no fd leak
grep -q OK $tmp.out && echo redirected file ok || echo redirected file bad

echo "--- output for fd leak tests ---" >> $seq.full
cat $tmp.out >> $seq.full


status=0
exit
