#!/usr/local/bin/bash
# vim: expandtab:ts=4:sw=4

: << =cut

=head1 NAME

http_response - Monitor HTTP response statistics

=head1 CONFIGURATION

The following environment variables are used

 sites           - Sites to check
                     - separated by spaces
                     - can contain basic auth credentials
                     - defaults to "http://localhost/"
 max_time        - Timeout for each site check in seconds
                     - defaults to 5 seconds
 short_label     - Switch for shortening the label below the graph
                     - defaults to false
 follow_redirect - Follow http redirects
                     - defaults to false

=head2 CONFIGURATION EXAMPLE

 [http_response]
  env.sites http://example.com/ https://user:secret@example2.de
  env.max_time 20
  env.short_label true
  env.follow_redirect true

=head1 PREREQUISITES

This plugin needs at least bash version 4 to run

=head1 NOTES

This plugin unifies the functionalities of the following plugins into one
multigraph plugin

 http_loadtime     - https://gallery.munin-monitoring.org/plugins/munin/http_loadtime/
 http_responsecode - https://gallery.munin-monitoring.org/plugins/munin-contrib/http_responsecode/

In contrast to using these two plugins with the same configuration, this plugin
performs only one request per site and munin run to gather its statistics.

=head1 AUTHOR

Copyright (C) 2020 Klaus Sperner

=head1 LICENSE

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 dated June,
1991.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

=head1 MAGIC MARKERS

 #%# family=manual

=cut

. "$MUNIN_LIBDIR/plugins/plugin.sh"

readonly uri_regex='^(https?://)([^:]*):(.*)@(.*)$'

strip_credentials_from_url() {
    if [[ "$1" =~ $uri_regex ]]; then
        echo "${BASH_REMATCH[1]}${BASH_REMATCH[4]}"
    else
        echo "$1"
    fi
}

extract_username_from_url() {
    if [[ "$1" =~ $uri_regex ]]; then
        echo "${BASH_REMATCH[2]}"
    else
        echo ""
    fi
}

extract_password_from_url() {
    if [[ "$1" =~ $uri_regex ]]; then
        echo "${BASH_REMATCH[3]}"
    else
        echo ""
    fi
}

compute_label() {
    if [[ "${short_label,,}" == "true" || "${short_label,,}" == "yes" ]]; then
        if [[ ${#1} -gt 33 ]]; then
            echo "${1:0:30}..."
        else
            echo "$1"
        fi
    else
        echo "$1"
    fi
}

if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
    >&2 echo "The plugin http_response needs at least bash version 4"
    exit 1
fi

sites=${sites:-"http://localhost/"}
max_time=${max_time:-5}
short_label=${short_label:-"false"}
follow_redirect=${follow_redirect:-"false"}

if [[ "$1" == "config" ]]; then
    echo 'multigraph http_response_code'
    echo 'graph_args --base 1000 -l 0 -u 511'
    echo 'graph_title HTTP Response Codes'
    echo 'graph_vlabel Response Code'
    echo 'graph_category network'
    echo 'graph_info This graph shows HTTP response code statistics'
    echo 'graph_printf %3.0lf'
    for site in $sites; do
        site_without_credentials=$( strip_credentials_from_url "$site" )
        siteid="$( clean_fieldname "$site_without_credentials" )"
        echo "$siteid.label $( compute_label "$site_without_credentials" )"
        echo "$siteid.info HTTP response code statistics for $site_without_credentials"
        echo "$siteid.critical 99:399";
    done
    echo 'multigraph http_response_time'
    echo 'graph_args --base 1000 -l 0'
    echo 'graph_title HTTP Response Times'
    echo 'graph_vlabel Response Time in seconds'
    echo 'graph_category network'
    echo 'graph_info This graph shows HTTP response time statistics'
    for site in $sites; do
        site_without_credentials=$( strip_credentials_from_url "$site" )
        siteid="$( clean_fieldname "$site_without_credentials" )"
        echo "$siteid.label $( compute_label "$site_without_credentials" )"
        echo "$siteid.info HTTP response time statistics for $site_without_credentials"
    done
    exit 0
fi

declare -A response_codes
declare -A response_times

for site in $sites; do
    site_without_credentials=$( strip_credentials_from_url "$site" )
    username=$( extract_username_from_url "$site" )
    password=$( extract_password_from_url "$site" )

    curl_config_file=""
    curl_auth_opt=()
    if [ -n "$username" ]; then
        if [ -z "$password" ]; then
            >&2 echo "Invalid configuration: username specified without password"
            exit 1
        fi
        curl_config_file=$(mktemp) || exit 1
        trap 'rm -f "$curl_config_file"' EXIT
        echo "user=${username}:${password}" >> "$curl_config_file"
        curl_auth_opt=(--config "$curl_config_file")
    fi

    curl_arg=""
    if $follow_redirect; then
        curl_arg="--location"
    fi

    siteid="$( clean_fieldname "$site_without_credentials" )"
    statuscode=
    loadtime=
    start=$(date +%s.%N)
    statuscode=$( curl "${curl_auth_opt[@]}" --write-out '%{http_code}' --max-time "$max_time" $curl_arg --silent --output /dev/null "$site_without_credentials" )
    returncode=$?
    loadtime=$( echo "$start" "$(date +%s.%N)" | awk '{ print($2 - $1); }' )
    if [[ $returncode -ne 0 ]]; then
        loadtime="U"
        statuscode="U"
    fi
    response_codes+=(["$siteid"]="$statuscode")
    response_times+=(["$siteid"]="$loadtime")

    if [ -n "$curl_config_file" ]; then
        rm -f "$curl_config_file"
    fi
done

echo 'multigraph http_response_code'
for siteid in "${!response_codes[@]}"; do
    echo "${siteid}.value ${response_codes[${siteid}]}"
done

echo 'multigraph http_response_time'
for siteid in "${!response_times[@]}"; do
    echo "${siteid}.value ${response_times[${siteid}]}"
done

