/* 24 March 1999. Daniel Hellerstein (Danielh@econ.ag.gov)
This is hereby released to the public domain.
SImple OS/2 REXX Cgi-bin script to process
HTML uploads (a "multi-part/form" submission").
It will echo back the "parts" submitted (i.e.; the
file that was uploaded)
The heart of this is the READ_MULTIPART_DATA procedure.
Use it in your own cgi-bin scripts.
For an example of an HTML document that will invoke this
form, see the bottom of this file
*/
/* get the request method */
method = value("REQUEST_METHOD",,'os2environment')
if method='GET' then do
list=value("QUERY_STRING",,'os2environment')
end
else do
tlen = value("CONTENT_LENGTH",,'os2environment')
list=charin(,,tlen)
end /* do */
/* Note: Multi-part form submissions MUST be POST */
notmulti=0
if method="GET" then do /* so this is just the normal request line */
notmulti=1
end
else do
conttype=value("CONTENT_TYPE",,'os2environment') /* Is this a multipart/form-data */
if abbrev(translate(conttype),'MULTIPART/FORM-DATA')=0 then notmulti=1
end
say "Content-type: text/html "
say
say "
The parts "
say "
"
say " Length of submission: " length(list)
say " Content-type: " ||word(conttype,1)
say
/* not a multipart form */
if notmult=1 then do
do forever
parse var list a1 '&' list
parse var a1 a1a '=' a1b
say "Variable "a1a " === " a1b
exit
end /* do */
end /* do */
/* if here, a multi part form */
n=read_multipart_data(list,conttype) /* this does the work . */
say "# of parts= " n
say "
"
/* now just echo the "parts" back to the client */
say
do mm=1 to n
elist=translate(strip(form_data.!list.mm))
say "
Vars in part "mm' = ' elist
say " Part Value:
"
call charout, form_data.mm
say "
"
end
say "
"
exit
/*************************************/
/* read data sent back by an html FORM declared with:
enctype="multipart/form-data" method="POST"
Calling syntax:
form_data.=''
nentries=read_multipart(stuff,content_type)
where:
stuff == the body of a POST request
nentries == the number of entries found. If error, nentries=0
and
form_data. == an "exposed" stem variable which will contain
variables extracted from the several parts of this
POSTed body.
The structure of FORM_DATA is:
i) FORM_DATA.0 = # of parts (in this multipart submission)
ii) FORM_DATA.!list.j = space delimited list of "variable names" in part
j (j=1.. FORM_DATA.0)
iii) FORM_DATA.!avar.j = value of the "avar" variable from the jth part;
where avar is one of the "variable names" contained
in FORM_DATA.!list.j
iv) FORM_DATA.j = the value of the part
That is:
* For each word in FORM_DATA.!list.j, there is a FORM_DATA. tail.
Thus,
if FORM_DATA.!list.2='FILENAME NAME'
then
FORM_DATA.!FILENAME.2 = the value of the "FILENAME" variable from the
"2nd" part of this requeset
FORM_DATA.!NAME.2 = the value of the "NAME" variable from the
"2nd" part of this request
and
FORM_DATA.2 = the value of this "part"
I almost all cases, the only "word" will "NAME", which will be
the "xxx" from a name="xxx" attribute of an element in
an HTML form.
You may also see a FILENAME word, which is the filename (on the
client's machine) of a file uploaded using a
element.
Notes:
* if an error occurs, a 0 is returmed, and FORM_DATA.!ERROR
will contain an error message
* a content-disposition entry, if found, is NOT included in FORM_DATA
*/
read_multipart_data:procedure expose form_data.
parse arg abody,atype
drop form_data.
crlf='0d0a'x
/* is there a content-type request header ? */
if atype="" then do
form_data.!error=" No content-type request header"
return 0
end
parse var atype thetype ";" boog 'boundary=' abound /* get the type */
if translate(thetype)<>"MULTIPART/FORM-DATA" then do
form_data.!error="No multipart/form-data in Content-type "
return 0
end
if translate(thetype)<>"MULTIPART/FORM-DATA" then do
form_data.!error=" BlendGif upload error: No boundary in multipart/form-data header "
return 0
end
abound="--"||abound /* since boundaries always start with -- */
abd2=abound||crlf
/* loop through message, pulling out blocks and storing in stem var bigstuff. */
/* Now parse the various parts.*/
parse var abody foo1 (abd2) abody /* move beyond first boundary and it's crlf */
/* check for netscape 2.0 incorrect format */
if pos(abound,abody)=0 then do /* no ending boundary, so add one */
abody=abody||crlf||abound||" -- "
end
mm=0
do until abody=""
parse var abody thestuff (abound) abody /* get a boundary defined block */
if strip(left(thestuff,4))="--" then leave /* -- signals no more */
if abody="" then leave
mm=mm+1
form_data.!list.mm='' ; form_data.mm=''
do forever /* get block headers. Stop when hit a blank line */
parse var thestuff anarg (crlf) thestuff
if anarg="" then do
leave
end
else do /* extract the arguments on this line */
do until anarg=""
parse var anarg anarg1 ";" anarg
boob1=pos(':',anarg1) ; boob2=pos('=',anarg1)
if boob1=0 then nixon=boob2
if boob2=0 then nixon=boob1
if boob1>0 & boob2>0 then nixon=min(boob1,boob2)
t1=translate(strip(strip(substr(anarg1,1,nixon-1)),,'"'))
t2=strip(strip(substr(anarg1,nixon+1)),,'"')
if t1="CONTENT-DISPOSITION" then iterate /* don't bother retaining this */
form_data.!list.mm=form_data.!list.mm' 't1
nm1='!'||t1
form_data.nm1.mm=t2
end /* exract arguments */
end /* extract args on this line */
end /* get a line */
if thestuff<>"" then do
form_data.mm=left(thestuff,length(thestuff)-2) /* strip off ending crlf */
parse var abody foo (crlf) abody /* jump past extra crlf */
end
else do
form_data.body.mm=""
end
end
return mm
/******************************************************************/
/* --- Example of FORM that will upload a file to this script */
/*
Demo of CGI-bin read of uploaded data
This demonstrates the UPCGI.CMD cgi-bin script.