* Experimental CGI program using only HP COBOL II/iX source code * Lars Appel, 25-Mar-98 / 11-Apr-98 (inspired by iprof 98 visit) * This program creates a very simple CGI response by echoing * a few parameters and then writing a number of lines back to * the client. It handles http Method GET and Method POST. * GET example URL is http://your.server/cgi-bin/cobcgi?nnn * where nnn is the loop count (in range 1 through 1000) * POST example URL is http://your.server/cgi-bin/cobcgi * with HTML form sending the loop count and and optional * text message similar to "mytext=bla+bla&myloop=100". * Compile with * COB85XL source,object [,$null] * Link with * LINK object, ./cobcgi ;rl=/lib/libc.a ;posix ;share * Test GET in Shell * export REQUEST_METHOD=GET * export QUERY_STRING=10 * ./cobcgi | cat -v * Test POST in Shell * export REQUEST_METHOD=POST * export CONTENT_LENGTH=22 * echo "mytext=hello&myloop=10" | ./cobcgi | cat -v $control post85 identification division. program-id. demo. environment division. configuration section. special-names. symbolic characters NUL is 1, LF is 11, CR is 14. data division. working-storage section. * buffer for composing output and calling print intrinsic 01 print-buf pic x(8000). 01 print-pos pic s9(9) comp value 1. 01 print-len pic s9(9) comp. * buffers for reading env vars via getenv() from Posix C lib 01 env-name pic x(80). 01 env-pointer pic s9(9) comp. 01 env-text pic x(80). 01 env-length pic s9(9) comp. * counter for the test loop writing lines back to client 01 loop-count pic 9(9). * buffers for reading client input from stdin (Method POST) 01 post-length pic s9(9) comp. 01 post-buf pic x(80). 01 post-get pic s9(9) comp. 01 post-got pic 9(9). 01 post-pos pic s9(9) comp. * buffers for extracting "field1=value1&field2=value2..." 01 field-name pic x(80). 01 field-name-len pic s9(9) comp. 01 field-value pic x(80). 01 field-value-len pic s9(9) comp. * message for the test loop (only passed with Method POST) 01 test-msg pic x(80). 01 test-msg-len pic s9(9) comp. * MAIN PROGRAM * First send http header to signal HTML type document, then send * some level one HTML headline, branch to body handler depending * on REQUEST_TYPE and finally add footing to the HTML page, which * also helps to emphasise the end-of-test-page visually. procedure division. main-body. string "Content-Type: text/html" CR LF CR LF delimited by size into print-buf with pointer print-pos perform my-print string "
GET Method needs valid QUERY_STRING
" CR LF delimited by size into print-buf with pointer print-pos perform my-print else string "GET Method received QUERY_STRING as " env-text (1:env-length) "
" CR LF delimited by size into print-buf with pointer print-pos perform my-print compute loop-count = function numval (env-text) if loop-count < 1 then move 1 to loop-count string "Loop Count was less than one
" CR LF delimited by size into print-buf with pointer print-pos perform my-print end-if if loop-count > 1000 then move 1000 to loop-count string "Loop Count was greater than 1000
" CR LF delimited by size into print-buf with pointer print-pos perform my-print end-if * Now return the (loop-count) lines to the web client string "" CR LF
delimited by size into print-buf with pointer print-pos
perform my-print
perform with test before until loop-count < 1
string "Test message loop countdown at " loop-count CR LF
delimited by size into print-buf with pointer print-pos
perform my-print
subtract 1 from loop-count
end-perform
string "" CR LF
delimited by size into print-buf with pointer print-pos
perform my-print
end-if.
* HANDLE-POST: Handle an http Method POST request from client
* First retrieve the CONTENT_LENGTH Posix env var and echo it back
* to the client. Then read that number of bytes from stdin, unless
* it is more than our buffer can hold, and echo it back to the web
* page. Parse the input string for fields named MYTEXT and MYLOOP,
* supplying default values in case they are missing. Finally send
* output lines with MYTEXT according to the MYLOOP count.
* Notice that the output loop does not call the PRINT intrinsic
* for every line but tries to combine as many lines as possible
* in the (relatively large) output buffer. This might improve the
* performance and reduce the resource consumption. The loops in
* handle-post and handle-get have been implemented differently to
* allow comparing them easily (try 1000 loops, for example).
handle-post.
string "CONTENT_LENGTH" NUL
delimited by size into env-name
perform my-getenv
string "POST Method received CONTENT_LENGTH as " env-text (1 : env-length) "
" CR LF delimited by size into print-buf with pointer print-pos perform my-print compute post-length = function numval (env-text) if post-length > function length (post-buf) then string "Too much data for my POST buffer
" CR LF delimited by size into print-buf with pointer print-pos perform my-print else compute post-get = - post-length call intrinsic "readx" using post-buf , post-get giving post-got string "Received " post-got " bytes with " post-buf (1 : post-got) "
" CR LF delimited by size into print-buf with pointer print-pos perform my-print * Use defaults if MYLOOP and/or MYTEXT missing in HTML Form move 10 to loop-count move "Default Test Message" to test-msg move 20 to test-msg-len * Terminate the buffer string for easier parsing loop move "&" to post-buf (post-got + 1 : 1) * Begin parsing to extract MYLOOP and MYTEXT fields move 1 to post-pos perform with test before until post-length <= 0 initialize field-name initialize field-value unstring post-buf delimited by "=" into field-name count in field-name-len with pointer post-pos unstring post-buf delimited by "&" into field-value count in field-value-len with pointer post-pos evaluate field-name when "mytext" move field-value to test-msg move field-value-len to test-msg-len when "myloop" compute loop-count = function numval (field-value) end-evaluate subtract field-name-len from post-length subtract field-value-len from post-length subtract 2 from post-length end-perform * Now return the (loop-count) lines to the web client, * but utilize our buffer to use fewer calls to PRINT string "" CR LF
delimited by size into print-buf with pointer print-pos
perform my-print
perform with test before until loop-count <= 0
if print-pos
+ function length ("Countdown at ")
+ function length (loop-count)
+ function length (" with message ")
+ test-msg-len + 2
> function length (print-buf)
then
perform my-print
end-if
string "Countdown at " loop-count
" with message " test-msg (1 : test-msg-len) CR LF
delimited by size into print-buf with pointer print-pos
subtract 1 from loop-count
end-perform
perform my-print
string "" CR LF
delimited by size into print-buf with pointer print-pos
perform my-print
end-if.
* HANDLE-ERR: Return error to client for unknown REQUEST-METHOD
handle-err.
string "Unknown REQUEST_METHOD " env-text (1 : env-length) " received
" CR LF delimited by size into print-buf with pointer print-pos perform my-print. * MY-PRINT: send print buffer to client by calling intrinsic * assumes print-buf has been composed with string verb using * print-pos as "cursor" pointer. computes length parm for the * intrinsic call and resets print-pos to 1 for convenience. * notice that this version does not check condition code (ouch) my-print. compute print-len = - ( print-pos - 1 ) if print-len <> 0 then call intrinsic "print" using print-buf , print-len , 0 end-if move 1 to print-pos. * MY-GETENV: retrieve Posix env var using Posix C lib functions * getenv() returns pointer to C string, strlen() determines * string length and strncpy() copies appropriate number of * characters to a buffer var in our working-storage section. * notice that this version silently clips "too long" input * and returns a zero-length string for undefined env vars. my-getenv. initialize env-text call "getenv" using env-name giving env-pointer if env-pointer <> 0 then call "strlen" using \env-pointer\ giving env-length if env-length > function length(env-text) then compute env-length = function length(env-text) end-if call "strncpy" using env-text , \env-pointer\ , \env-length\ else move 0 to env-length end-if. end program demo.