home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 35 Internet
/
35-Internet.zip
/
gostats.zip
/
gofilter.80
next >
Wrap
Text File
|
1999-03-09
|
16KB
|
328 lines
/* Sample GoServe filter program for an HTTP server--see GOHTTP.DOC */
/* Be sure to start GoServe with the HTTP option to use this filter */
dir = datadir() /* Data directory (root of all data directories) */
/* [must include drive and end in '/'] */
parse arg source, request, sel /* Get arguments */
parse var source myaddr port transaction who whoport . /* Often useful */
tempfile=dir'$'transaction'.'port /* Often used */
statfile=dir'$_'transaction'.'port /* stats file name */
default = 'index.html' /* Default document (sent if none specified) */
owner = '142.72.67.160' /* Owner IP address (may send special requests) */
/* [e.g. '9.11.22.33', or 'ANY' for no checking] */
/* say time() transaction who':' request */ /* sample debug aid */
parse var request verb uri protocol . /* split up the request line */
/* Check request */
if left(protocol,4)\='HTTP' & protocol\='' then
return response('badreq', 'specified a protocol that was not HTTP')
/* Provide access to the remote control forms. Authorization can */
/* be applied to seeing the forms, or only if Apply is pressed. */
/* This assumes the pages are in the DataDir directory. */
/* You might want to change the 'keyword' in the next line, too. */
if left(translate(sel),8)='GOREMOTE' then do
if pos('/',sel)=0 then return moved(sel'/')
/* [remove next line (only) to protect both forms and Apply] */
if verb='POST' then
call authorize 'GoRemote' /* direct exit if fails */
parse var sel '/' action /* action follows the '/' */
if action='' then action='goremote' /* add top form name */
return goremote(verb, action) /* invoke forms handler */
end /* remote control request */
/* Convert empty selector to default [or use more sophisticated */
/* defaulting, here]. */
if sel='' then sel=default
/* Allow some special 'control' requests. For these, the verb is */
/* ignored (though would usually be GET) */
if left(sel,1)='!' then do
if left(sel,6)='!stats' then do /* * stats * */
'extract clientaddr'
st_type = substr(sel,8,50) /* could be !stats-this-month */
address cmd
'call c:\GoStats\GoStats.exe parse 'clientaddr' 'statfile' 'st_type
return 'FILE ERASE TYPE text/html NAME ' statfile
end
/* Special request -- only accept from allowed places. */
if who\=owner & owner\='ANY' then
return response('forbid', 'tried to use a special control')
select
when sel='!ping' then return 'STRING Ping!'
when sel='!statistics' then return 'CONTROL STATISTICS'
when sel='!save' then return 'CONTROL MOVEAUDIT'
when sel='!reset' then return 'CONTROL RESET ALL'
when sel='!dopush' then return dopush() /* server push example */
when sel='!special' then do /* protected command */
call authorize 'Demo' /* will Exit if not authorized */
return 'STRING You got the right password'
end
otherwise return response('badreq', 'asked for unknown control "'sel'"')
end
end
/* Now carry out whichever verbs we support */
file=dir||sel /* full filename */
select
when verb='GET' | verb='HEAD' then do
/* First see if it's a query or image click */
parse var sel type '?' words
if words='' then /* common case: do not have a search */ do
if stream(file, 'c', 'query exists')='' then return response('notfound',,
'asked for "'sel'", which could not be found')
return 'FILE TYPE' mediatype(file) 'NAME' file
end
/* If something after the '?' it's the result from Image or Form */
if type='globe' then return globemap(words)
/* Here if a search from GET; call function to do it */
return search(tempfile, type, words)
end /* get */
when verb='POST' then do
/* This filter only uses POSTs for queries (forms) */
'read body var words' /* get the incoming data */
if rc=-4 then /* body too large */
return response('badreq', 'sent too much data')
if rc<>0 then /* e.g., invalid HTTP header */
return response('badreq', 'sent data that could not be read')
return search(tempfile, sel, words) /* this does the search */
end /* post */
otherwise return response('badreq', 'sent an unknown verb "'verb'"')
end /* select verb */
/* [cannot reach here] */
/* ----------------------------------------------------------------------- */
/* RESPONSE: Standard [mostly error] responses. */
/* ----------------------------------------------------------------------- */
/* This routine should stay in the main filter program. */
/* Arguments are: response type and extended message information. */
/* It returns the GoServe command to handle the result file. */
response: procedure expose tempfile
parse arg request, message
select
when request='badreq' then use='400 Bad request syntax'
when request='notfound' then use='404 Not found'
when request='forbid' then use='403 Forbidden'
when request='unauth' then use='401 Unauthorized'
end /* Add others to this list as needed */
/* Now set the response and build the response file */
'RESPONSE HTTP/1.0' use /* Set HTTP response line */
'extract clientaddr'
parse var use code text
call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
call lineout tempfile, "<html><head><title>"text"</title></head>"
call lineout tempfile, "<body><h2>Oh Oh! Sorry...</h2>"
call lineout tempfile, "<p>The request from your Web client" message"."
call lineout tempfile, "<hr><em>HTTP response code:</em>" code '['text']'
call lineout tempfile, "<br><em>From server at:</em>" servername()
call lineout tempfile, "<br><em>Running:</em>" server()
call lineout tempfile, "<br><em>Your IP:</em>" clientaddr
call lineout tempfile, "</body></html>"
call lineout tempfile /* close */
return 'FILE ERASE TYPE text/html NAME' tempfile
/* ----------------------------------------------------------------------- */
/* MOVED: Return a 'moved' response */
/* ----------------------------------------------------------------------- */
/* This must be in the main filter program (uses PORT and TEMPFILE). */
/* Argument is new URL or partial URI */
/* It returns the GoServe command to handle the result file. */
moved: procedure expose port tempfile
parse arg uri
if left(uri,5)=='http:' then /* got full URI */ url=uri
else /* got partial URI */ do
if port=80 then pp=''; else pp=':'port
url='http://'servername()pp'/'uri /* relocation */
end
/* Now set the response and build the response file */
'RESPONSE HTTP/1.0 302 Moved Temporarily' /* Set HTTP response line */
'HEADER ADD Location:' url
call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
call lineout tempfile, "<html><head><title>Moved</title></head>"
call lineout tempfile, "<body><h2>Document moved...</h2>"
call lineout tempfile, "<p>This document has moved"
call lineout tempfile, "<a href="""url""">here<a>."
call lineout tempfile, "</body></html>"
call lineout tempfile /* close */
return 'FILE ERASE TYPE text/html NAME' tempfile
/* ----------------------------------------------------------------------- */
/* AUTHORIZE -- check access to data is authorized */
/* ----------------------------------------------------------------------- */
/* This routine exits directly if it needs to challenge the client, so it */
/* must be internal. If authorization is valid, it returns to caller. */
/* Argument is the Realm to which the data belongs (this tells the user */
/* which userid/password pair to use). */
/* In this sample filter, the password for the 'Demo' realm is simply the */
/* userid; in a real application, it would probably be held in a file */
/* (such as a .INI file), or possibly hard-coded here. */
authorize: procedure expose tempfile
parse arg realm . /* get the realm word */
afield=reqfield('Authorization') /* see if incoming authorization */
parse var afield . m64 . /* get the encoded cookie */
dec=pack64(m64) /* and decode it */
parse var dec user ':' pw /* split to userid and password */
/* These checks can use the USER, PW, and REALM variables. */
/* Note: a RETURN indicates success (client is authorized). */
/* [Start of password checking code here] */
if realm='Demo' & pw<>'' & pw==user then return
/* To enable remote control Applys, change the password (??????) in the */
/* next line and then remove the comment delimiters from that line. */
/* if realm='GoRemote' & pw=='??????' then return */
/* [End of password checking code] */
'header add WWW-Authenticate: Basic Realm=<'realm'>' /* challenge */
exit response('unauth', "for realm '"realm"'was not authorized")
/* ----------------------------------------------------------------------- */
/* SEARCH: Sample search function that builds a response file dynamically. */
/* ----------------------------------------------------------------------- */
/* We'd probably make it a separate Rexx program normally, for ease of */
/* maintenance. */
/* Arguments are: the unique file name, search to do, and words [UR form]. */
/* It returns the GoServe command to handle the result file. */
search: procedure
parse arg file, type, list /* could easily be uppercased */
parse var list list '&' checks /* split off all checkboxes etc. */
/* If this came with our name, use the value */
/* If came from an old form, with an ISINDEX tag, can handle that, too */
/* If this came from an old form and old client, use list as-is */
/* But if the name isn't the one we put in the form, use empty list. */
parse var list name '=' value
select
when name='searchText' then list=value /* usual case */
when name='isindex' then list=value /* for very simple forms */
when pos('=', list)=0 then nop /* as-is case */
otherwise list='' /* invalid name */
end
list=packur(list) /* pack escape sequences in list */
/* This sample function ignores TYPE except as information */
call lineout file, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
call lineout file, "<html><head><title>Response</title></head>"
call lineout file, "<body>"
call lineout file, "<h2>Response to '"type"' request</h2>"
/* Here would be a customized search. We just build a simple list. */
list=translate(list, ' ', '+'||'090a0d'x) /* Whitespace, etc. */
if list='' then call lineout file, "<p>You chose no words."
else do
call lineout file, "<p>The words you chose were:<ol>"
do while list<>''
parse var list word list /* get first */
call lineout file, "<li>"word
end
call lineout file, "</ol>"
end /* have words */
if checks<>'' then
call lineout file, "<p>Checkbox data was:" checks
call lineout file, "<hr></body></html>"
call lineout file /* close */
return 'FILE ERASE TYPE text/html NAME' file
/* ----------------------------------------------------------------------- */
/* GLOBEMAP: Sample handling of a selectable image [image map]. */
/* ----------------------------------------------------------------------- */
globemap: procedure
/* Use 'trace i' here, with PMprintf, to see the calculations */
parse arg x ',' y /* get coordinates */
radius=69/2 /* need the .GIF size for this */
/* note some browsers seem to include frame */
y=radius*2-y /* convert Y to map direction [up is plus] */
xrel=(x-radius)/radius /* both in range +/- 1.0 */
yrel=(y-radius)/radius /* .. */
if (xrel**2 + yrel**2)<=1 then onglobe=1; else onglobe=0
if \onglobe then return 'String You clicked off the globe'
crlf='0d0a'x
return 'String You clicked on the globe image at map coordinates'crlf,
crlf' ['format(xrel*100,,0)'%,' format(yrel*100,,0)'%]'crlf,
crlf'from the middle.'
/* ----------------------------------------------------------------------- */
/* DOPUSH: Sample 'server push' routine */
/* ----------------------------------------------------------------------- */
/* This sends a (very simple) "Server push" data stream. It requires a */
/* browser that accepts the internet type 'multipart/x-mixed-replace' */
dopush: procedure
/* This simple example does a full-document countdown */
crlf='0d0a'x /* useful */
bound=copies("x",11) /* boundary data for part [could be random] */
mimestart='--'bound''crlf /* starts a MIME multipart section */
mimeend ='--'bound'--'crlf /* ends a MIME multipart section */
/* Send the header and first boundary */
'set netbuffer off' /* turn off buffering */
'send type multipart/x-mixed-replace;boundary="'bound'" as Countdown'
'string' mimestart /* Or could be: 'var name mimestart' */
do num=10 to 0 by -1
/* Build document to send, with leading (mixed) Type header and */
/* terminating MIME boundary. It could be sent in smaller pieces. */
out=''
out=out||'Content-type: text/html'crlf
out=out||crlf
out=out||'<!doctype html public "-//IETF//DTD HTML 2.0//EN">'crlf
out=out||"<html><head><title>Counting...</title></head>"crlf
out=out||"<body><h2>"
if num>0 then out=out||num||'...'
else out=out||'<hr>Zero!!<hr>'
out=out||"</h2>"crlf
out=out||"</body></html>"crlf
if num=0 then out=out||mimeend /* Mime 'last data' indicator */
else out=out||mimestart /* Mime 'start data' indicator */
'VAR NAME out' /* send it */
if num>0 then 'wait seconds 0.7' /* pause */
end
'SEND Complete' /* and complete the send */
return '' /* [called as function] */
/* ----------------------------------------------------------------------- */
/* MEDIATYPE: Return the media type of a file, based on its extension. */
/* ----------------------------------------------------------------------- */
mediatype: procedure
/* First get the extension; this assumes filenames have at least one '.' */
???=translate(substr(arg(1), lastpos('.',arg(1))+1))
/* Fastpath very common types [add your own favourites] */
if ???='GIF' then return 'image/gif'
if ???='HTM' then return 'text/html'
if ???='HTML' then return 'text/html'
/* Set up the table of all types that we are interested in */
known. ='application/octet-stream' /* default type */
known.ps ='application/postscript'
known.zip='application/zip'
known.pdf='application/pdf'
known.au ='audio/basic'
known.snd='audio/basic'
known.wav='audio/x-wav'
known.mid='audio/x-midi'
known.gif='image/gif'
known.bmp='image/bmp'
known.jpg='image/jpeg'; known.jpeg='image/jpeg'
known.tif='image/tiff'; known.tiff='image/tiff'
known.htm='text/html' ; known.html='text/html'
known.txt='text/plain'
known.rex='text/plain'; known.rexx='text/plain'
known.nrx='text/plain'
known.c ='text/plain'; known.cpp ='text/plain'
known.jav='text/plain'; known.java='text/plain'
known.cmd='text/plain'; known.txt ='text/plain'
known.doc='text/plain'; known.faq ='text/plain'
known.mpg='video/mpeg'; known.mpeg='video/mpeg'
known.avi='video/x-msvideo'
/* Now it's trivial... */
return known.???