77PROG=xinetd_http_service
88DESCRIPTION=" bash script called by xinetd to service a HTTP request; a farmework for reporting on health"
99SYNOPSIS=" ${PROG} [options]"
10- VERSION=0.1
11- LASTMOD=20180621
12-
13- #
14- # Read the HTTP headers from standard input, and parse and store their
15- # values in environment variables.
16- #
17- while read -t 0.01 line; do
18- if [ -z " $line " ]; then break ; fi
19- if echo " ${line} " | grep -qi " ^GET\|POST\|PUT\|DELETE" ; then
20- # GET /test123?r=123 HTTP/1.1
21- export HTTP_REQUEST=" ${line} "
22- export HTTP_REQ_METHOD=" $( echo ${line} | cut -d" " -f 1) "
23- export HTTP_REQ_URI=" $( echo ${line} | cut -d" " -f 2) "
24- export HTTP_REQ_URI_PATH=" $( echo ${HTTP_REQ_URI} | cut -d" ?" -f 1) "
25- if echo " $HTTP_REQ_URI " | grep -q ' ?' ; then
26- export HTTP_REQ_URI_PARAMS=" $( echo ${HTTP_REQ_URI} | cut -d" ?" -f 2-) "
27- else
28- export HTTP_REQ_URI_PARAMS=" "
29- fi
30- export HTTP_REQ_VERSION=" $( echo ${line} | cut -d" " -f 3-) "
31- elif echo " ${line} " | grep -qi " ^User-Agent:" ; then
32- # User-Agent: curl/7.29.0
33- export HTTP_USER_AGENT=" $( echo ${line} | cut -d" " -f 2-) "
34- elif echo " ${line} " | grep -qi " ^Host:" ; then
35- # Host: 0.0.0.0:8081
36- export HTTP_SERVER=" $( echo ${line} | cut -d" " -f 2-) "
37- elif echo " ${line} " | grep -qi " ^Accept::" ; then
38- # Accept: */*
39- export HTTP_ACCEPT=" $( echo ${line} | cut -d" " -f 2-) "
40- else
41- break
42- fi
43- done
44-
45- #
46- # A function to parse HTTP_REQ_URI_PARAMS and return the value of a given
47- # parameter name
48- # Example:
49- # param_value=$(get_http_req_uri_params_value "param_name")
50- # if [ "$?" -eq 1 ]; then echo "param_name" not provided; fi
51- #
52- get_http_req_uri_params_value () {
53- # Example: "a=123&b=456&c&d=789"
54- PARAM_NAME=$1
55- IFS=' &' read -r -a params <<< " $HTTP_REQ_URI_PARAMS"
56- for element in " ${params[@]} " ; do
57- element_name=$( echo $element | cut -d" =" -f 1)
58- if [ " $element_name " == " $PARAM_NAME " ]; then
59- if echo " $element " | grep -q " =" ; then
60- element_value=$( echo $element | cut -d" =" -f 2-)
61- echo " $element_value "
62- else
63- echo " "
64- fi
65- exit 0
66- fi
67- done
68- exit 1
69- }
10+ VERSION=0.2
11+ LASTMOD=20180822
12+ MAX_HTTP_POST_LENGTH=200
7013
7114#
7215# Handle the program's usage documentation
@@ -77,6 +20,8 @@ print_usage () {
7720}
7821
7922print_help () {
23+ print_version
24+ echo
8025 print_usage
8126 cat << EOF
8227
10247
10348print_version () {
10449 echo " $PROG $VERSION "
50+ echo " https://github.com/rglaue/xinetd_bash_http_service"
10551 echo " Copyright (C) 2018 Russell Glaue, CAIT, WIU <http://www.cait.org>"
10652}
10753
@@ -110,6 +56,7 @@ print_version () {
11056#
11157
11258# Set the default values before parsing the parameters
59+ : ${VERBOSE:= 0}
11360: ${OPT_HTTP_STATUS:= 0}
11461: ${OPT_HEALTH_VALUE:= 0}
11562: ${OPT_WEIGHT_VALUE:= 0}
@@ -154,6 +101,117 @@ while true ; do
154101 esac
155102done
156103
104+ #
105+ # Read the HTTP headers from standard input, and parse and store their
106+ # values in environment variables.
107+ #
108+ while read -t 0.01 line; do
109+ line=${line// $' \r ' }
110+ if [ $VERBOSE -ge 1 ]; then
111+ echo " H: $line "
112+ fi
113+ if [ -z " $line " ]; then break ; fi
114+ if echo " ${line} " | grep -qi " ^GET\|POST\|PUT\|DELETE" ; then
115+ # GET /test123?r=123 HTTP/1.1
116+ export HTTP_REQUEST=" ${line} "
117+ export HTTP_REQ_METHOD=" $( echo " ${line} " | cut -d" " -f 1) "
118+ export HTTP_REQ_URI=" $( echo " ${line} " | cut -d" " -f 2) "
119+ export HTTP_REQ_URI_PATH=" $( echo " ${HTTP_REQ_URI} " | cut -d" ?" -f 1) "
120+ if echo " $HTTP_REQ_URI " | grep -q ' ?' ; then
121+ export HTTP_REQ_URI_PARAMS=" $( echo " ${HTTP_REQ_URI} " | cut -d" ?" -f 2-) "
122+ else
123+ export HTTP_REQ_URI_PARAMS=" "
124+ fi
125+ export HTTP_REQ_VERSION=" $( echo " ${line} " | cut -d" " -f 3-) "
126+ elif echo " ${line} " | grep -qi " ^User-Agent:" ; then
127+ # User-Agent: curl/7.29.0
128+ export HTTP_USER_AGENT=" $( echo " ${line} " | cut -d" " -f 2-) "
129+ elif echo " ${line} " | grep -qi " ^Host:" ; then
130+ # Host: 0.0.0.0:8081
131+ export HTTP_SERVER=" $( echo " ${line} " | cut -d" " -f 2-) "
132+ elif echo " ${line} " | grep -qi " ^Accept:" ; then
133+ # Accept: */*
134+ export HTTP_ACCEPT=" $( echo " ${line} " | cut -d" " -f 2-) "
135+ # continue
136+ elif echo " ${line} " | grep -qi " ^Content-Length:" ; then
137+ # Content-Length: 5
138+ export HTTP_CONTENT_LENGTH=" $( echo " ${line} " | cut -d" " -f 2-) "
139+ elif echo " ${line} " | grep -qi " ^Content-Type:" ; then
140+ # Content-Type: application/x-www-form-urlencoded
141+ export HTTP_CONTENT_TYPE=" $( echo " ${line} " | cut -d" " -f 2-) "
142+ elif [ ${# line} -ge 1 ]; then
143+ # <any header>
144+ continue
145+ else
146+ break
147+ # continue
148+ fi
149+ done
150+
151+ #
152+ # Read the HTTP POST data from standard input
153+ # This does not support a Content-type of multipart/mixed
154+ # This does not support chunking. It expects, and only allows, posted data to
155+ # be the size of the Content-Length.
156+ #
157+ if [ " ${HTTP_REQ_METHOD} " == " POST" ] && [ ${HTTP_CONTENT_LENGTH} -ge 1 ]; then
158+ export HTTP_POST_CONTENT=" "
159+ DATA_LENGTH=$HTTP_CONTENT_LENGTH
160+ if [ ${DATA_LENGTH} -gt ${MAX_HTTP_POST_LENGTH} ]; then
161+ DATA_LENGTH=$MAX_HTTP_POST_LENGTH
162+ fi
163+ # If the value of Content-Length is greater than the actual content, then
164+ # read will timeout and never allow the collection from standard input.
165+ # This is overcome by reading one character at a time.
166+ # READ_BUFFER_LENGTH=1
167+ # If you are sure the value of Content-Length always equals the length of the
168+ # content, then all of standard input can be read in at one time
169+ READ_BUFFER_LENGTH=$DATA_LENGTH
170+ #
171+ # Read POST data via standard input
172+ while IFS= read -N $READ_BUFFER_LENGTH -r -t 0.01 post_buffer; do
173+ let " DATA_LENGTH = DATA_LENGTH - READ_BUFFER_LENGTH"
174+ HTTP_POST_CONTENT=" ${HTTP_POST_CONTENT}${post_buffer} "
175+ # Stop reading if we reach the content length, max length, or expected length
176+ if [ ${# HTTP_POST_CONTENT} -ge ${HTTP_CONTENT_LENGTH} ]; then
177+ break ;
178+ elif [ ${# HTTP_POST_CONTENT} -ge ${MAX_HTTP_POST_LENGTH} ]; then
179+ break ;
180+ elif [ ${DATA_LENGTH} -le 0 ]; then
181+ break ;
182+ fi
183+ done
184+ if [ $VERBOSE -ge 1 ]; then
185+ echo -e " D: $HTTP_POST_CONTENT "
186+ fi
187+ fi
188+
189+ #
190+ # A function to parse HTTP_REQ_URI_PARAMS and return the value of a given
191+ # parameter name
192+ # Example:
193+ # param_value=$(get_http_req_uri_params_value "param_name")
194+ # if [ "$?" -eq 1 ]; then echo "param_name" not provided; fi
195+ #
196+ get_http_req_uri_params_value () {
197+ # Example: "a=123&b=456&c&d=789"
198+ PARAM_NAME=$1
199+ IFS=' &' read -r -a params <<< " $HTTP_REQ_URI_PARAMS"
200+ for element in " ${params[@]} " ; do
201+ element_name=" $( echo " $element " | cut -d" =" -f 1) "
202+ if [ " $element_name " == " $PARAM_NAME " ]; then
203+ if echo " $element " | grep -q " =" ; then
204+ element_value=" $( echo " $element " | cut -d" =" -f 2-) "
205+ echo " $element_value "
206+ else
207+ echo " "
208+ fi
209+ exit 0
210+ fi
211+ done
212+ exit 1
213+ }
214+
157215#
158216# Parse parameters from the HTTP request
159217#
@@ -240,13 +298,15 @@ display_health_value () {
240298 fi
241299}
242300
243-
244301#
245302# --show-headers
246303# Show the HTTP headers as parsed into the environment variables
247304#
248305if [ $OPT_SHOW_HEADERS -eq 1 ]; then
249306 THIS_HEADERS=" $( env | grep ' ^HTTP' ) "
307+ if [ ! -z " $HTTP_POST_CONTENT " ]; then
308+ THIS_HEADERS=" ${THIS_HEADERS} \n--BEGIN:HTTP_POST_CONTENT--\n${HTTP_POST_CONTENT} \n--END:HTTP_POST_CONTENT--\n"
309+ fi
250310 if echo $THIS_HEADERS | grep -q ' ^HTTP' ; then
251311 http_response 200 " $THIS_HEADERS "
252312 else
265325# If something unhealthy was detected, then:
266326decrease_health_value
267327
268- # display response
328+ # display health value response, and exit
269329display_health_value
330+
331+ # send a http_response of 200
270332http_response 200 " Success"
271333
272334# End of program
273-
0 commit comments