home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / srev13h.zip / sreproxy.80 < prev    next >
Text File  |  1999-10-31  |  15KB  |  507 lines

  1. /* 27 June 1999 
  2.  
  3.    SRE-http: A "proxy-like" front end for sre-http ver 1.3h.
  4.  
  5.    Provides local cache for sre-http, and returns  http/1.1 
  6.    responses.  This is NOT an http (1.0 or 1.1) compliant proxy --
  7.    but it has proxy-like features. Plus -- it has limited ssi capabilities,
  8.    can do some user-name/pwd lookup, and does all the sre-http postfiltering.
  9.  
  10.    See SREPROXY.DOC for details. 
  11.  
  12.    There is one user changable parameter:
  13.       SAY_IS_PROXY:
  14.          If say_is_proxy=1, then a '[@proxy]' is added to the SERVER: response header
  15.          This can be a useful debugging trick (but it does slow things down a little bit)
  16. */
  17. parse arg source, request , seloriginal
  18. sel3=seloriginal
  19. request0=request
  20. jsend=0       
  21.  
  22. if request='' then return 'NODATA NOWAIT NORESPONSE'
  23.  
  24. SAY_IS_PROXY=1
  25.  
  26. /*set exception handler */
  27.  
  28. signal on syntax name goterr;signal on error name goterr
  29. signal on halt name goterr;call on failure name goterr2
  30.  
  31. parse var source myaddr port transaction who whoport . /* Often useful */
  32. parse var request verb uri protocol .        /* split up the request line */
  33.  
  34. sreproxy=value('SREF_PROXY',,'os2environment')
  35. moreinfo=''
  36. enmadd="SREF_"||port||"_"
  37.  
  38. IF TRANSACTION=1 THEN DO
  39.   if sreproxy='' then aa=value('SREF_PROXY',-2,'os2environment')  /* -2 signals initialize */
  40. end
  41.  
  42. dodebug=value("SREF_DEBUG",,'os2environment')
  43. verbose=get_value('VERBOSE')
  44.  
  45. if dodebug=1 then say "!DEB:PXY "||left(transaction,5)' 'left(time('l'),11)' 'left(seloriginal,25)
  46.  
  47.  
  48. if sreproxy<>1 then signal gomain
  49.  
  50. if abbrev(seloriginal,'!')=1 then do
  51.   signal gomain 
  52. end
  53.  
  54. if upper(verb)<>'GET' then signal gomain  /* only do it for GET */
  55.  
  56. foo=make_semmi()
  57. if foo=-1 then signal gomain
  58. /* check cache */
  59.  
  60. hname=get_host_info(protocol)           /* get host nickname */
  61.  
  62.  
  63. if moreinfo=-1 then signal gomain       /* let main handle errors */
  64.  
  65. reqnum=extract('request')
  66.  
  67. /* check cache, if not here, gomain */
  68. dastuff=check_cache(hname,seloriginal)
  69.  
  70. if dastuff=-1 then moreinfo=''
  71. if dastuff=-1  | dastuff=0 then signal gomain /* -1= error, 0=no found */
  72.  
  73. /* if te: header, that contains gzip or identity;q=0, then proxy can't do it */
  74. ote=reqfield('TE')
  75. if ote<>'' then do
  76.   if pos('GZIP',upper(ote))>0 then do
  77.      if value('SREF_SUPPRESS_GZIP_TE',,'os2environment')=0 then signal gomain
  78.   end
  79. end
  80.  
  81. if verbose>3 then call pmprintf_sref('SREPROXY: from cache: 'seloriginal)
  82.  
  83. /* if Unmodified-Since of If-Match, then gomain (odd conditions) */
  84. if reqfield('Unmodified-Since')<>'' | reqfield('If-Match')<>'' then signal gomain
  85.  
  86. crlf='0d0a'x
  87. parse var dastuff cshtype0 (crlf) dafile0 (crlf) ctype (crlf) ,
  88.       lastmod (crlf) etag (crlf) ,
  89.       amaxage(crlf) headers
  90. parse var amaxage maxage ',' nopostf
  91. parse var cshtype0 cshtype goscache ','reqprivs
  92. cshtype=strip(cshtype); goscache=strip(goscache)
  93.  
  94. parse var dafile0 dafile ','trigfile;dafile=strip(dafile); trigfile=striP(trigfile)
  95. if trigfile<>'' then do          /* check stamp of dafile against dastamp */
  96.    foo=sysfiletree(dafile,'goo1','T')
  97.    if goo1.0=0 then signal gomain       /* no such cached file */
  98.    parse var goo1.1 cstamp . ; cstamp=strip(cstamp)
  99.    lapse=0
  100.    if abbrev(trigfile,'!TIME'!)=1 then do
  101.           tstamp=strip(substr(trigfile,7))
  102.           if compdate(cstamp,tstamp)>0 then lapse=1   /* current date > "when cached" date */
  103.    end
  104.    else do
  105.       foo=sysfiletree(trigfile,'goo1','T')
  106.       if goo1.0=0 then signal gomain       /* no such cached file */
  107.       parse var goo1.1 tstamp . ; tstamp=strip(tstamp)
  108.       if compdate(tstamp,cstamp)>0 then lapse=1  /* trigger (original) file newer then cached version of file */
  109.    end
  110.    if lapse=1 then do
  111.       if verbose>2 then call pmprintf_Sref('SREPROXY -- trigger file newer then cached file')
  112.       signal gomain  /* trigger file newer then cache */
  113.    end
  114.    if verbose>2 then call pmprintf_sref(' SREPROXY using 'dafile' ('trigfile')')
  115. end
  116.  
  117. /* note: cshtype: 0= public static , 1= public semi-dynamic 
  118.                   2= private static , 3=private semi-dynamic 
  119.                 0 1= public static w/ goserve cache */
  120.  
  121. /* perhaps use etag and lastmod for conditional gets */
  122. ifnone=reqfield("If-none-match")
  123. if ifnone<>'' then do                   /* check If-none-match */
  124.     ifnone=translate(ifnone,' ','",')
  125.     etagmatch=wordpos(upper(etag),upper(ifnone))
  126.     if etagmatch=0 then etagmatch=wordpos('*',ifnone)
  127.     if etagmatch>0 then do
  128.          'RESPONSE HTTP/1.1 304 Not Modified Etag'
  129.          'HEADER ADD Content-type: 'ctype
  130.          'NODATA '
  131.          rstatus='304 0'
  132.          if verbose>3 then call pmprintf_sref(' SREPROXY using 304 etag ')
  133.          signal gopostf
  134.     end
  135. end
  136. else do                         /* check if-modified-since */
  137.    ifmod=reqfield('If-modified-since')
  138.    if ifmod<>'' then do
  139.      fatt=sref_gmt(,lastmod,'J')
  140.      modabs=sref_gmt(,ifmod,'J') 
  141.      numeric digits 11
  142.      if fatt<=modabs then do
  143.        'RESPONSE HTTP/1.1 304 Not Modified '
  144.        'HEADER ADD Content-type: 'ctype
  145.        'NODATA '
  146.         rstatus='304 0'
  147.         if verbose>3 then call pmprintf_sref(' SREPROXY using 304 not modified ')
  148.         signal gopostf
  149.      end           
  150.    end
  151. end                     
  152.  
  153. /*if private (cshtype>1), then quick check on privileges etc. may be needed */
  154. if cshtype>1 then do
  155.    checklog=get_value('CHECKLOG')
  156.    allow_access=strip(upper(get_value('ALLOW_ACCESS')))
  157.    aok=sref_check_allowed(reqprivs,mysem,myqueue,enmadd,transaction,hname,checklog,allow_access)
  158.    if aok=0 then signal gomain
  159. end
  160.  
  161. /* if here, do return file from cache -- possibly range */
  162. if verbose>3 then call pmprintf_sref(' SREPROXY cache hit is 'dafile)
  163. adate=sref_gmt()
  164. filen=stream(dafile,'c','query size')
  165.  
  166. tempdata_dir=get_value('TEMPDATA_DIR')
  167. tdir=strip(TEMPDATA_DIR,'t','\')||'\'
  168. tempfile2=tdir'$'reqnum'.'port                      /* For use in postfilter  */
  169.  
  170. /* check allow range */
  171. rstatus=0
  172.  
  173. if cshtype=0 then do
  174.   alrange=upper(get_value('ACCEPT_RANGE'))
  175.   if wordpos(alrange,'Y YES 1')>0 then do   /* check for ranges header */
  176.     oo=reqfield('range')
  177.     if oo<>'' then do            /* see if it can be handled */
  178.        i00=extract('bytessent')
  179.        'HEADER NOAUTO ADD Date: 'adate
  180.        'HEADER ADD Cache-Control: public,max-age='maxage
  181.        if say_is_proxy=1 then headers=mod_headers(headers)
  182.        if headers<>'' then 'HEADER ADD 'headers
  183.        rstatus=sref_process_range(dafile,ctype,filen,lastmod,etag,verbose)
  184.        if rstatus=416 then signal gomain       /* accept error, let main handle it*/
  185.     end
  186.   end
  187. end
  188.    
  189.  
  190. /* not a range request */
  191. if rstatus=0 then do
  192.    'RESPONSE HTTP/1.1 200 Ok.'           /*http/1.1 is now the default response */
  193.    'HEADER NOAUTO ADD Date: 'adate
  194.    'HEADER ADD Cache-Control: public,max-age='maxage
  195.    if say_is_proxy=1 then headers=mod_headers(headers)
  196.    if headers<>'' then    do
  197.      'HEADER ADD 'headers
  198.    end
  199.  
  200.  
  201.    goo=extract('bytessent')
  202.  
  203.     if cshtype=1 | cshtype=3 then do        /* do semi-dynamic ssis */
  204.         if verbose>3 then call pmprintf_sref(' SREPROXY: semi-dynamic hit ')
  205.         if stream(dafile,'c','query exists')='' then signal gomain /* missing cache file */
  206.         vvs=sref_semi_ssis(dafile,seloriginal,who,mysem,myqueue,enmadd, ,
  207.                            transaction,servername,port)
  208.         'var type 'ctype ' name vvs'
  209.         if rc=-7 then 
  210.            jsend=extract('bytessent')-goo
  211.          else 
  212.            jsend=length(vvs)
  213.          rstatus='200 '||jsend
  214.     end
  215.     else do
  216.        noc='nocache ' 
  217.        if goscache=1 then noc=' ' 
  218.        'FILE 'noc' type 'ctype ' name 'dafile
  219.        if rc=-7 then
  220.           jsend=extract('bytessent')-goo
  221.        else
  222.           jsend=stream(dafile,'c','query size')
  223.        rstatus='200 '||jsend
  224.     end
  225. end
  226.  
  227. /* DO POSTFILTERING */
  228. gopostf: nop
  229. if dodebug=1 then say "!DEB:PX2 "||left(transaction,5)' 'left(time('l'),11)' posfilter'
  230.  
  231. if verbose>2 then call pmprintf_sref(' SREPROXY status: 'rstatus)
  232.  
  233. ssize=value('SREF_PROXY_BYTES',,'os2environment')
  234. if datatype(ssize)<>'NUM' then ssize=0
  235. foo=value('SREF_PROXY_BYTES',ssize+jsend,'os2environment')
  236. sct=value('SREF_PROXY_HITS',,'os2environment')
  237. if sct='' then sct=0
  238. foo=value('SREF_PROXY_HITS',sct+1,'os2environment')
  239.  
  240.  
  241.  
  242. if nopostf<>1 then call do_post_filter
  243.  
  244. return ' '  
  245.  
  246.  
  247. /* here if not in cache, or error, or ... */
  248. gomain:
  249. if sreproxy<>1 then do
  250.   if verbose>2 then  say ' SREPROXY: Calling SREFILTR'
  251.   FOO=SREFILTR(SOURCE,REQUEST,SEL3)
  252. end
  253. else do
  254.   if verbose>2 then call pmprintf_sref(' SREPROXY: Calling SREFILTR-macrospace for: 'sel3)
  255.   goon=extract('bytessent')
  256.   foo=sref_srefiltr(source,request,sel3,moreinfo)
  257.   goon2=extract('bytessent')
  258.   jsend=goon2-goon
  259. end
  260.  
  261. ssize=value('SREF_PROXY_BYTES2',,'os2environment')
  262. if ssize='' then ssize=0
  263. foo=value('SREF_PROXY_BYTES2',ssize+jsend,'os2environment')
  264. sct=value('SREF_PROXY_HITS2',,'os2environment')
  265. if sct='' then sct=0
  266. foo=value('SREF_PROXY_HITS2',sct+1,'os2environment')
  267.  
  268. return ''
  269.  
  270.  
  271. /********/
  272. /* here on error */
  273. goterr:
  274. say " error in sreproxy filter "sigl', 'rc
  275.  
  276. call pmprintf(" error in sreproxy filter "sigl', 'rc)
  277. exit
  278.  
  279.  
  280. /*****************************/
  281. /* get host,datadir, & servername for this requesete */
  282. get_host_info:procedure expose moreinfo SELORIginal uri enmadd myaddr servername 
  283.  
  284. parse arg protocol
  285.  
  286. stuff=sref_host_info(myaddr,enmadd,uri,protocol)
  287. if strip(stuff)='BAD' then return -1           /* if http/1.1 client did not include at host: header */
  288.  
  289. if stuff<>0 then do
  290.       parse var stuff  servername ',' host_nickname  ',' ddir
  291.       host_nickname=strip(host_nickname); ddir=strip(ddir)
  292.       servername=strip(servername)
  293. end
  294. else do
  295.     ddir=datadir()
  296.     servername=servername()
  297.     host_nickname=' '
  298.     STUFF=servername ',' host_nickname  ',' ddir
  299.  
  300. end
  301. if abbrev(upper(uri),'HTTP://')>0 then do
  302.           parse var uri . '//' . '/' uri
  303.           if uri='' then uri='/'
  304.           parse var seloriginal . '//'  . '/' seloriginal
  305. end        
  306. moreinfo=stuff
  307. return host_nickname
  308.  
  309.  
  310. /********************************/
  311. /* checks sreproxy cache */
  312. check_cache:procedure expose enmadd mysem myqueue reqnum 
  313. parse arg hname,sel
  314.  
  315. if left(sel,1)='!' then do
  316.   if abbrev(upper(sel),'!SEND')<>1 then return 0  /* do NOT cache special codes */
  317. end
  318.  
  319. if hname<>'' then
  320.   eek=hname'//'sel
  321. else
  322.   eek=sel
  323. eek=upper(eek)
  324. goober='SREF_SREPROXY'
  325. a=rxqueue('s',goober)
  326. queue  reqnum','myqueue','mysem',L,'EEK
  327. a=eventsem_reset(mysem)
  328. dothread='\SEM32\SREF_SREPROXY'
  329. a=eventsem_post(dothread)
  330.  
  331. a=eventsem_wait(mysem)
  332. if a<>0 then do
  333.    sss=sref_error(' A Fatal Semaphore failure in SREPROXY: 'a,1)
  334.    return -1
  335. end
  336. a=rxqueue('s',myqueue)
  337.  
  338. parse pull aline
  339. PARSE VAR ALINE idnum ',' aline
  340. idnum=strip(translate(idnum,' ','000d0a'x));TRANSACTION=STRIP(TRANSACTION)
  341. if idnum<>reqnum then  do /*wierd error: got someone else's message, give up */
  342.       say ' Read odd id from sreproxy queue :' idnum0 ',' idnum
  343.       return -1
  344. end
  345.  
  346. aline=strip(aline)
  347. return aline
  348.  
  349.  
  350.  
  351. /***************/
  352. /* create a personallized queue & semaphore */
  353. make_semmi:procedure expose mysem myqueue enmadd 
  354.  
  355. mytid=dostid()
  356. mysem='\SEM32\'||enmadd||"t"||mytid
  357. myqueue=enmadd||'t'||mytid
  358.  
  359. a=rxqueue('s',myqueue)
  360. signal off syntax ; signal off error ;signal on syntax name badq ; signal on error name badq
  361. queue 0
  362.  
  363. yyq=queued()
  364. if yyq>100 then return -1  /* gunked up, let main to it */
  365. do mmy=1 to yyq
  366.     pull poo .
  367. end
  368.  
  369. wow=eventsem_query(mysem)
  370. if wow=-187 then return -1      /* odd semaphore, let main do it */
  371. foo=eventsem_reset(MYSEM)
  372.  
  373. signal off syntax ; signal off error
  374. signal on syntax name goterr;signal on error name goterr
  375. return 1
  376.  
  377. badq:
  378. return -1
  379.  
  380.  
  381.  
  382. /* ----------- */
  383. /* get environment value, possibly host specific
  384. hname=0 -- do not look under hostname
  385. hname=1 -- do not look under default
  386.  */
  387. /* ------------ */
  388. get_value: procedure expose enmadd hname
  389. parse arg vname
  390. vname=strip(vname) ;
  391. if hname<>' ' then do
  392.    booger=strip(enmadd||vname||'.'||hname)
  393.    aval=value(booger,,'os2environment')
  394.    if aval<>' ' Then return aval
  395. end
  396. aval=value(enmadd||vname,,'os2environment')
  397. return aval
  398.  
  399.  
  400.  
  401. /*****************/
  402. /* jump here for postfilter */
  403. do_post_filter:
  404. postfilter_name=get_value('POSTFILTER_NAME')
  405. post_filter=strip(get_value('POST_FILTER'))
  406. write_logs=strip(get_value('WRITE_LOGS'))
  407.  
  408. /* save some extra stuff to the request specific variables (if a post_filter might
  409.    use it */
  410. if post_filter=1 then do
  411.   if pos(',',seloriginal||request)=0 then do
  412.      foo=sref_value('SOURCE  SEL REQUEST ',source','sel3','request,'REQ',reqnum,,enmadd)
  413.   end
  414.   else do
  415.     foo=sref_value('SOURCE',source,'REQ',reqnum,,enmadd)
  416.     foo=sref_value('SEL',sel3,'REQ',reqnum,,enmadd)
  417.     foo=sref_value('REQUEST',request,'REQ',reqnum,,enmadd)
  418.   end
  419. end
  420.  
  421. record_option=strip(get_value('RECORD_OPTION'))
  422.  
  423. /* check for owner suppression */
  424. chkowner=get_value('HIT_OWNER_SUPPRESS')
  425. if chkowner=1 then do
  426.    owners=get_value('Owners')
  427.   if wordpos(who,owners)>0 then record_option='NO'
  428. end
  429.  
  430. if (record_option="NO" & post_filter=0  & write_logs=0) then do /* nothing to do in post filter */
  431.     return ' '
  432. end
  433.  
  434. record_all_file=get_value('RECORD_ALL_FILE',0)
  435.  
  436. selrec=sref_replacestrg(sel3,',','%2c','ALL')
  437. request0=sref_replacestrg(request,',','%2c','ALL')
  438. post_filter_message='SREPROXY resolved request: 'rstatus
  439.  
  440. browser=' ';authuser=' '
  441. thereferer=reqfield('referer')
  442.  
  443. clientname0=sref_clientname(who,mysem,myqueue,'/SEM32/'||enmadd,enmadd,transaction)
  444. browser=reqfield('user-agent')
  445. authuser='-'
  446. dec=sref_extract_upwd()
  447. if dec<>'' then parse upper var dec authuser ':' .      /* split to userid, if basic */
  448.  
  449. a=rxqueue('s',enmadd||'POSTF')
  450. queue  record_option ',' record_all_file ',' post_filter ',' postfilter_name ',' port ',' ,
  451.                  post_filter_message ',' source ',' request0 ',' 0' 'selrec ',' ,
  452.                 tempfile2 ','  servername ',' hname ',' afile ',' who ',' ,
  453.                 enmadd ',' thereferer ',' reqnum ',' RSTATUS ',' write_logs ',' ,
  454.                 clientname0 ',' authuser ',' browser ',' verbose
  455.  
  456. aa=eventsem_post('/SEM32/'||enmadd||'POSTF')
  457.  
  458. return ' '  /* note that postfilter and recorder don't need to tell the filter anything*/
  459.  
  460.  
  461.  
  462. /**************************/
  463. /**************************/
  464.  
  465. /******************/
  466. /* add " @pxy " to server: header */
  467. mod_headers:procedure expose crlf
  468. parse arg ah
  469. ah0=''
  470. do until ah=""
  471.   parse var ah a1 (crlf) ah
  472.   if a1='' then iterate
  473.   a1a=strip(upper(a1))
  474.   if abbrev(a1a,'SERVER')=0 then do
  475.       if ah0="" then
  476.          ah0=ah0||a1
  477.       else
  478.          ah0=ah0||crlf||a1
  479.       iterate
  480.   end
  481.   ah0=ah0||crlf||a1||' [@proxy]'
  482. end
  483. return ah0
  484.  
  485.  
  486.  
  487. /*****************/
  488. /* compare "ordered" (yy/mm/dd/hh/ss) dates, with y2k correction */
  489. compdate:procedure
  490. parse arg a,b
  491. a=strip(a); b=strip(b)
  492.  if left(a,2)<80 then
  493.      a="1"||a
  494.  else
  495.      a='0'||a
  496.  
  497.  if left(b,2)<80 then
  498.      b="1"||b
  499.  else
  500.      b='0'||b
  501.  
  502. if a>b then return 1
  503. return 0
  504.  
  505.  
  506.  
  507.