"Fossies" - the Fresh Open Source Software Archive

Member "delegate9.9.13/filters/cfi.c" (9 Jun 2014, 24795 Bytes) of package /linux/misc/old/delegate9.9.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cfi.c" see the Fossies "Dox" file reference documentation.

    1 /*////////////////////////////////////////////////////////////////////////
    2 Copyright (c) 1996-2000 Yutaka Sato and ETL,AIST,MITI
    3 Copyright (c) 2001-2006 National Institute of Advanced Industrial Science and Technology (AIST)
    4 AIST-Product-ID: 2000-ETL-198715-01, H14PRO-049, H15PRO-165, H18PRO-443
    5 
    6 Permission to use this material for noncommercial and/or evaluation
    7 purpose, copy this material for your own use, and distribute the copies
    8 via publicly accessible on-line media, without fee, is hereby granted
    9 provided that the above copyright notice and this permission notice
   10 appear in all copies.
   11 AIST MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS
   12 MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS
   13 OR IMPLIED WARRANTIES.
   14 /////////////////////////////////////////////////////////////////////////
   15 Content-Type:   program/C; charset=US-ASCII
   16 Program:    cfi.c (Common Filter Interface)
   17 Author:     Yutaka Sato <ysato@etl.go.jp>
   18 Description:
   19 History:
   20     960130  created
   21     960203  renamed from approxy (application protocol translation library)
   22 //////////////////////////////////////////////////////////////////////#*/
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include "config.h"
   26 #include "ystring.h"
   27 #include "fpoll.h"
   28 #include "file.h"
   29 #include "dglib.h"
   30 #include <ctype.h>
   31 
   32 int builtin_filter(DGC*ctx,PCStr(what),PCStr(filter),FILE *in,FILE *out,FILE *in1,FILE *out1);
   33 void system_CGI(DGC*ctx,PCStr(conninfo),PCStr(oreq),PCStr(req),PVStr(head),PCStr(cgi),FILE *in,FILE *out);
   34 int systemFilter(PCStr(command),FILE *in,FILE *out);
   35 int HTTP_putMIMEmsg(DGC*Conn,FILE *in,FILE *out);
   36 void genheadf(PCStr(fmt),PVStr(out),int siz);
   37 UTag RFC822_readHeaderU(FILE *in,int seeEOR);
   38 
   39 #define getFieldValue(str,fld,buf,siz) getFieldValue2(str,fld,ZVStr(buf,siz),siz)
   40 #define getFV(str,fld,buf)             getFieldValue2(str,fld,AVStr(buf),sizeof(buf))
   41 #define OPgetFV(spc,pre,fld,buf)  OPgetFieldValue(spc,pre,fld,AVStr(buf),sizeof(buf))
   42 #define FTOCL_FIELD "X-Request"
   43 
   44 /*
   45  * ARGUMENTS
   46  *
   47  *  in   input
   48  *  out  output
   49  *  conninfo information about the client/server connection
   50  *  convspec specification of conversion
   51  *
   52  * RETURN value
   53  *
   54  *  -1 error
   55  *   0 no translation
   56  *   1 translated
   57  */
   58 static int http_conv(DGC *ctx,FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec),PCStr(clproto),PVStr(statline),PVStr(head),int withbody);
   59 int non_http_conv(DGC *ctx,FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec),PCStr(clproto));
   60 void filter_msgs(DGC *ctx,int isresp,PCStr(clproto),FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec));
   61 
   62 /*
   63  * read RFC822 header without buffering.
   64  */
   65 static char *readHeader(FILE *in){
   66     int pch,ch;
   67     CStr(buf,MAX_MIMEHEAD);
   68     refQStr(bp,buf);
   69     char chb[1];
   70     char *test;
   71 
   72     pch = '\n';
   73     test = getenv("WIN_CFI_TEST");
   74     for(;;){
   75         if( test || 0 < ready_cc(in) ){
   76             if( (ch = getc(in)) == EOF )
   77                 break;
   78         }else{
   79             if( read(fileno(in),chb,1) < 1 )
   80                 break;
   81             ch = chb[0];
   82         }
   83         setVStrPtrInc(bp,ch);
   84         if( ch == '\n' && pch == '\n' )
   85             break;
   86         if( ch != '\r' )
   87             pch = ch;
   88     }
   89     setVStrPtrInc(bp,0);
   90     if( test ){
   91         sv1log("##CFI readHeader() -- isreg=%d ready_cc=%d\n",
   92             file_isreg(fileno(in)),ready_cc(in));
   93     }
   94     return stralloc(buf);
   95 }
   96 
   97 int cfi(DGC *ctx,int isresp,FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec))
   98 {   CStr(statline,1024);
   99     defQStr(head); /*alloc*/
  100     FILE *tmp;
  101     CStr(clproto,64);
  102     int withhead;
  103     int withbody;
  104     int rcode;
  105 
  106     if( getFV(conninfo,"Client-Protocol",clproto) == 0 )
  107         strcpy(clproto,"http");
  108 
  109 sv1log("## CFI/%s ##\n",clproto);
  110 
  111     if( strcaseeq(clproto,"nntp")
  112      || strcaseeq(clproto,"smtp")
  113      || strcaseeq(clproto,"pop") )
  114     {
  115         filter_msgs(ctx,isresp,clproto,in,out,conninfo,convspec);
  116         return 0;
  117     }
  118 
  119     /*
  120     if(!strcaseeq(clproto,"http") ){
  121     */
  122     if( !strncaseeq(clproto,"http",4) ){
  123         if( non_http_conv(ctx,in,out,conninfo,convspec,clproto) ){
  124             sv1log("## NON-MIME-RELAY\n");
  125             return 1;
  126         }else{
  127             sv1log("## SIMPLE-RELAY\n");
  128             simple_relayf(in,out);
  129             return 0;
  130         }
  131     }
  132 
  133     /*
  134      *  HTTP
  135      */
  136     if( isWindows() ){
  137         /* suppress buffering HTTP body to let systemFilter() work... */
  138         setbuf(in,NULL);
  139     }
  140     withhead = 1;
  141     withbody = 1;
  142     if( isresp ){
  143         /*
  144          *  Pass through non-HTTP stream
  145          */
  146 
  147         /* 9.6.3-pre1 for test */ {
  148         /* should use PollIns(in,out) to detect disconn. of out */
  149         int ifd = fileno(in);
  150         int ofd = fileno(out);
  151         int ni;
  152         for( ni = 0; ni < 20; ni++ ){
  153             if( 0 < fPollIn(in,3*1000) )
  154                 break;
  155             porting_dbg("--CFI timeout? (%d/%d/%d,%d/%d/%d)",
  156                 SocketOf(ifd),ifd,IsAlive(ifd),
  157                 SocketOf(ofd),ofd,IsAlive(ofd)
  158             );
  159             if( file_isSOCKET(ifd) && !IsAlive(ifd) ){
  160                 _exit(-1);
  161             }
  162             if( file_isSOCKET(ofd) && !IsAlive(ofd) ){
  163                 _exit(-1);
  164             }
  165         }
  166         /*
  167         if( fPollIn(in,1000) <= 0 ){
  168             _exit(-1);
  169         }
  170         */
  171         }
  172 
  173         if( fPollIn(in,0) < 0 )
  174             exit(-1);
  175         if( fread(statline,1,5,in) <= 0 )
  176             return -1;
  177 
  178         if( strncmp(statline,"HTTP/",5) != 0 ){
  179             IGNRETP write(fileno(out),statline,5);
  180             simple_relayf(in,out);
  181             return 0;
  182         }
  183         /*
  184          *  Read status line and response header
  185          */
  186         if( Xfgets(DVStr(statline,5),sizeof(statline)-5,in) == NULL )
  187             return -1;
  188 
  189         if( sscanf(statline,"HTTP/%*s %d",&rcode) )
  190             if( rcode == 304 || rcode == 204 || rcode/100 == 1 ) 
  191                 withbody = 0;
  192     }else{
  193         fgets(statline,sizeof(statline),in);
  194         if( strncmp(statline,"POST",4) != 0
  195          && strncmp(statline,"PUT", 3) != 0 )
  196             withbody = 0;
  197         if( strstr(statline,"HTTP/") == NULL ){
  198             withhead = 0;
  199             withbody = 0;
  200         }
  201     }
  202     if( withhead ){
  203         if( isWindows() ){
  204             head = readHeader(in);
  205         }else
  206         head = RFC822_readHeader(in,0);
  207         if( isresp ){
  208             CStr(req,4096);
  209             if( getFV(head,"X-Request",req) )
  210                 if( strncmp(req,"HEAD",4) == 0 )
  211                     withbody = 0;
  212         }
  213     }else   head = stralloc("");
  214     if( isWindows() ){
  215         int ch = EOF;
  216         /* restart buffering ... */
  217         if( ready_cc(in) ){
  218             ch = getc(in);
  219         }
  220         in = fdopen(fileno(in),"r");
  221         if( ch != EOF ){
  222             ungetc(ch,in);
  223         }
  224     }
  225     setQStr(head,(char*)realloc((char*)head,
  226 strlen(head)+2048),
  227 strlen(head)+2048); /* make space for rewriting */
  228 
  229     /*
  230      *  pass through if not to be filterd
  231      */
  232     if( http_conv(ctx,in,out,conninfo,convspec,clproto,AVStr(statline),AVStr(head),withbody) == 0 ){
  233         fputs(statline,out);
  234         removeFields(AVStr(head),FTOCL_FIELD,1);
  235         fputs(head,out);
  236         simple_relayf(in,out);
  237         return 0;
  238     }
  239     return 1;
  240 }
  241 
  242 #define IsHttpResp(stat)    strneq(stat,"HTTP/",5)
  243 #define IsHttpReqWithBody(req) (strneq(req,"POST ",5) || strneq(req,"PUT ",4))
  244 
  245 /*
  246  * matching with CGI environment as:
  247  *   REQUEST_METHOD: POST
  248  *   SERVER_NAME: xxx.yyy
  249  *   PATH_INFO: /path/of/dir/
  250  */
  251 static int isCGIENV(PCStr(name)){
  252     const char *np;
  253     char ch;
  254     int nus = 0;
  255     for( np = name; ch = *np; np++ ){
  256         if( ch == '_' ) nus++; else
  257         if( !isupper(ch) )
  258             return 0;
  259     }
  260     return nus;
  261 }
  262 static int matchEnviron(PCStr(spec)){
  263     const char *sp;
  264     char sc;
  265     const char *env;
  266     CStr(name,128);
  267     CStr(body,1024);
  268 
  269     for( sp = spec; sc = *sp; ){
  270         fieldScan(sp,name,body);
  271         if( 'A' <= name[0] && name[0] <= 'Z' )
  272         if( 'A' <= name[1] && name[1] <= 'Z' )
  273         if( isCGIENV(name) )
  274         {
  275             env = getenv(name);
  276             if( env == 0 )
  277                 env = "";
  278             if( matchFields(spec,name,env) == 0 )
  279                 return 0;
  280         }
  281         if( (sp = strchr(sp,'\n')) == 0 )
  282             break;
  283         sp++;
  284     }
  285     return 1;
  286 }
  287 
  288 /*
  289 const char *searchSpec(PCStr(conninfo),PCStr(specs),PCStr(statline),PCStr(head))
  290 */
  291 const char *CFI_searchSpec(PCStr(conninfo),PCStr(specs),PCStr(statline),PCStr(head),int silent)
  292 {   CStr(ictype,1024);
  293     CStr(iagent,1024);
  294     CStr(iserver,1024);
  295     CStr(iencode,1024);
  296     CStr(request,2048);
  297     CStr(imethod,256);
  298     CStr(iurl,2048);
  299     CStr(iver,256);
  300     CStr(from,256);
  301     CStr(orequest,2048);
  302     CStr(iomethod,32);
  303     CStr(iourl,2048);
  304     CStr(rver,256);
  305     CStr(rstat,256);
  306     CStr(rcode,32);
  307     const char *dp;
  308     CStr(clhost,256);
  309     CStr(svhost,256);
  310     CStr(clproto,256);
  311     CStr(svproto,256);
  312     int top;
  313     const char *spec1;
  314     const char *np;
  315     const char *delp;
  316     char delc;
  317 
  318     orequest[0] = iourl[0] = 0;
  319     getFV(head,"X-Request-Original",orequest);
  320     dp = wordScan(orequest,iomethod);
  321     dp = wordScan(dp,iourl);
  322 
  323     request[0] = 0;
  324     if( !IsHttpResp(statline) )
  325         lineScan(statline,request);
  326     else
  327     getFV(head,"X-Request",request);
  328     dp = wordScan(request,imethod);
  329     dp = wordScan(dp,iurl);
  330     dp = wordScan(dp,iver);
  331 
  332     getFV(head,"X-Request-User-Agent",iagent);
  333     if( iagent[0] == 0 )
  334         getFV(head,"User-Agent",iagent);
  335 
  336     if( IsHttpResp(statline) ){
  337         dp = wordScan(statline,rver);
  338         dp = wordScan(dp,rcode);
  339     }else{
  340         rver[0] = 0;
  341         rcode[0] = 0;
  342     }
  343 
  344     getFV(head,"Server",iserver);
  345     getFV(head,"Content-Type",ictype);
  346     getFV(head,"Content-Encoding",iencode);
  347     getFV(conninfo,"Client-Host",clhost);
  348     getFV(conninfo,"Client-Protocol",clproto);
  349     getFV(conninfo,"Server-Host",svhost);
  350     getFV(conninfo,"Server-Protocol",svproto);
  351 
  352     getFV(head,"From",from);
  353     
  354     spec1 = (char*)specs; /* should be "const" */
  355     delp = 0;
  356     for( spec1 = (char*)specs; *spec1; spec1 = np ){ /* should be "const" */
  357         top = 1;
  358         if( delp ){ /* restore the delimiter char. */ *(char*)delp = delc; } /**/
  359         for( np = (char*)spec1; *np; np++ ){
  360             if( top ){
  361                 if( *np == '.' && (np[1]=='\r' || np[1] == '\n')
  362                  || *np == '-' && np[1]=='-' && (np[2]=='\r'||np[2]=='\n')
  363                 ){
  364                     if( *np == '-' )
  365                         np += 2;
  366                     else    np += 1;
  367 
  368                     while( np[1] == '\r' || np[1] == '\n' )
  369                         np++;
  370                     delp = np;
  371                     delc = *delp;
  372                     *(char*)np++ = 0;
  373                     break;
  374                 }
  375             }
  376             top = (*np == '\n');
  377         }
  378 
  379         while( isspace(*spec1) )
  380             spec1++;
  381         if( *spec1 == 0 )
  382             continue;
  383 
  384         if( !silent )
  385         sv1vlog("////////////////////////////\n%s\n",spec1);
  386 
  387         if( !matchFields(spec1,"User-Agent",iagent) ) continue;
  388         if( !matchFields(spec1,"Server",iserver) ) continue;
  389         if( !matchFields(spec1,"Content-Type",ictype) ) continue;
  390         if( !matchFields(spec1,"Content-Encoding",iencode) ) continue;
  391         if( !matchFields(spec1,"Req-Method",imethod) ) continue;
  392         if( !matchFields(spec1,"Req-Url",iurl) ) continue;
  393         if( !matchFields(spec1,"Req-Version",iver) ) continue;
  394         if( !matchFields(spec1,"Req-Url-Orig",iourl) ) continue;
  395 
  396         if( !matchFields(spec1,"X-Request",request) ) continue;
  397         if( !matchFields(spec1,"X-Request-Method",imethod) ) continue;
  398         if( !matchFields(spec1,"X-Request-URL",iurl) ) continue;
  399         if( !matchFields(spec1,"X-Request-Ver",iver) ) continue;
  400         if( !matchFields(spec1,"X-Request-URL-Orig",iourl) ) continue;
  401 
  402         if( !matchFields(spec1,"Res-Version",rver) ) continue;
  403         if( !matchFields(spec1,"Res-Status",rstat) ) continue;
  404 
  405         if( !matchFields(spec1,"X-Status",rstat) ) continue;
  406         if( !matchFields(spec1,"X-Status-Ver",rver) ) continue;
  407         if( !matchFields(spec1,"X-Status-Code",rcode) ) continue;
  408 
  409         if( !matchFields(spec1,"Client-Host",clhost) ) continue;
  410         if( !matchFields(spec1,"Client-Protocol",clproto) ) continue;
  411         if( !matchFields(spec1,"Server-Host",svhost) ) continue;
  412         if( !matchFields(spec1,"Server-Protocol",svproto) ) continue;
  413         if( !matchFields(spec1,"From",from) ) continue;
  414 
  415         if( !matchEnviron(spec1) ) continue;
  416 
  417         if( !silent )
  418         sv1vlog("///////// MATCHED //////////\n");
  419         if( delp ){
  420             const char *sp1;
  421             sp1 = spec1;
  422             /* skip the heading in the first alternative */
  423             {
  424                 if( strneq(sp1,"#!cfi",5) )
  425                     sp1 += 5;
  426                 while( isspace(*sp1) )
  427                     sp1++;
  428             }
  429             spec1 = stralloc(sp1);
  430             /*
  431             spec1 = stralloc(spec1);
  432             */
  433         }
  434         if( delp ){ /* restore the delimiter char. */ *(char*)delp = delc; } /**/
  435         return spec1;
  436     }
  437     return NULL;
  438 }
  439 #define searchSpec(ci,sp,st,head)   CFI_searchSpec(ci,sp,st,head,0)
  440 
  441 static const char *OPgetFieldValue(PCStr(spec),PCStr(prefix),PCStr(fname),PVStr(value),int size)
  442 {   const char *vp;
  443     CStr(field,256);
  444 
  445     sprintf(field,"%s/%s",prefix,fname);
  446     if( vp = getFieldValue(spec,field,value,size) )
  447         return vp;
  448 
  449     sprintf(field,"%s-%s",prefix,fname); /* obsolete ... */
  450     if( vp = getFieldValue(spec,field,value,size) )
  451         return vp;
  452 
  453     return NULL;
  454 }
  455 
  456 static void substitute(FILE *fp,PCStr(conninfo),PCStr(spec),PCStr(ftype),PCStr(fname),PCStr(statline),PCStr(head))
  457 {   CStr(fvalue,1024);
  458     const char *sp;
  459     char sc;
  460     const char *hp;
  461     CStr(hname,1024);
  462     CStr(hvalue,1024);
  463     CStr(tmp,1024);
  464 
  465     OPgetFV(spec,ftype,fname,fvalue);
  466     for( sp = fvalue; sc = *sp; sp++ ){
  467         if( sc == '#' ){
  468             while( sp[1] && sp[1] != '\n' )
  469                 sp++;
  470             continue;
  471         }else
  472         if( sc == '$' && sp[1] == '{' ){
  473             Xsscanf(sp,"${%[^}]",AVStr(hname));
  474             if( sp[2+strlen(hname)] == '}' ){
  475                 if( strcasecmp(hname,"head") == 0 )
  476                     fputs(head,fp);
  477                 else
  478                 if( strncasecmp(hname,"icon.",5) == 0 ){
  479                     getFV(conninfo,"Client-IF-Host",tmp);
  480                     fprintf(fp,"//%s/-/builtin/icons/ysato/%s",tmp,hname+5);
  481                 }else
  482                 if( strcasecmp(hname,"Req-Url-Orig") == 0 ){
  483                     const char *url;
  484                     const char *dp;
  485 
  486                     getFV(head,"X-Request-Original",hvalue);
  487                     url = tmp;
  488                     dp = wordScan(hvalue,tmp);
  489                     dp = wordScan(dp,tmp);
  490                     if( strncmp(url,"/-_-",4) == 0 )
  491                         url += 4;
  492                     fputs(url,fp);
  493                 }else
  494                 if( getFV(conninfo,hname,hvalue) ){
  495                     fputs(hvalue,fp);
  496                 }else
  497                 if( getFV(head,hname,hvalue) )
  498                     fputs(hvalue,fp);
  499                 else{
  500                     fputc(sc,fp);
  501                     continue;
  502                 }
  503                 sp += 2 + strlen(hname);
  504                 continue;
  505             }
  506         }
  507         fputc(sc,fp);
  508     }
  509     if( *fvalue )
  510         fputs("\r\n\r\n",fp);
  511 }
  512 
  513 /*
  514  * read a messge to its logical end
  515  */
  516 static int HTTP_getBody(PCStr(statline),PCStr(head),FILE *in,FILE *out)
  517 {   CStr(cleng,128);
  518     int leng,rcc,ch,timeout;
  519 
  520     if( strncmp(statline,"POST ",5) != 0 )
  521         return 0;
  522 
  523     leng = 0;
  524     if( getFV(head,"Content-Length",cleng) )
  525         leng = atoi(cleng);
  526 
  527     ch = 0;
  528     rcc = 0;
  529     timeout = 3*1000;
  530     while( 0 < fPollIn(in,timeout) ){
  531         ch = getc(in);
  532         if( ch == EOF )
  533             break;
  534         putc(ch,out);
  535         rcc++;
  536         if( leng <= rcc )
  537             timeout = 100;
  538     }
  539 
  540     sv1log("## CFI-getBody[%d/%d] EOF=0x%X\n",rcc,leng,ch&0xFF);
  541     fflush(out);
  542     fseek(out,0,0);
  543     return 1;
  544 }
  545 void removeVaryCE(PVStr(head))
  546 {   CStr(vary,64);
  547 
  548     if( getFieldValue2(head,"Vary",AVStr(vary),sizeof(vary)) ){
  549         if( strcaseeq(vary,"Accept-Encoding") )
  550             removeFields(AVStr(head),"Vary",0);
  551     }
  552 }
  553 void System(DGC *ctx,PCStr(command),FILE *in,FILE *out);
  554 static int http_conv(DGC *ctx,FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec),PCStr(clproto),PVStr(statline),xPVStr(head),int withbody)
  555 {   const char *spec;
  556     CStr(octype,1024);
  557     CStr(ochset,256);
  558     CStr(oetype,256);
  559     CStr(ostatus,256);
  560     CStr(oheader,1024);
  561     CStr(prefix,1024);
  562     CStr(postfix,1024);
  563     CStr(filter,1024);
  564     CStr(cgi,1024);
  565     FILE *intmp,*tmp;
  566     const char *xhead;
  567     int bodyoff;
  568     const char *ohead;
  569     const char *nhead;
  570     const char *savhead;
  571     CStr(enc,64);
  572 
  573     spec = searchSpec(conninfo,convspec,statline,head); /* should be "const" */
  574     if( spec == NULL )
  575     {
  576         /* seems never happen because spec includes the #!cfi line */
  577         return 0;
  578     }
  579 
  580     savhead = stralloc(head);
  581 
  582     /*
  583      *  Rewrite Content-Type field
  584      */
  585     if( OPgetFV(spec,"Output","Content-Type",octype) )
  586         replaceFieldValue(AVStr(head),"Content-Type",octype);
  587 
  588     if( OPgetFV(spec,"Output","Charset",ochset) )
  589         replace_charset(AVStr(head),ochset);
  590 
  591     if( OPgetFV(spec,"Output","Content-Encoding",oetype) )
  592         replaceFieldValue(AVStr(head),"Content-Encoding",oetype);
  593 
  594     if( strncmp(statline,"HTTP/",5) == 0 ){
  595         int code;
  596         CStr(ver,32);
  597         CStr(xstat,1024);
  598         strcpy(xstat,"X-Status: ");
  599         linescanX(statline,TVStr(xstat),sizeof(xstat));
  600         strcat(xstat,"\r\n");
  601         RFC822_addHeaderField(AVStr(head),xstat);
  602 
  603         wordScan(statline,ver);
  604         sscanf(statline,"%*s %d",&code);
  605         sprintf(xstat,"X-Status-Ver: %s\r\n",ver);
  606         RFC822_addHeaderField(AVStr(head),xstat);
  607         sprintf(xstat,"X-Status-Code: %d\r\n",code);
  608         RFC822_addHeaderField(AVStr(head),xstat);
  609     }
  610 
  611     filterFields(spec,AVStr(head));
  612 
  613     if( !IsHttpResp(statline) && IsHttpReqWithBody(statline) ){
  614         FILE *sin = in;
  615         in = TMPFILE("Request-Body");
  616         HTTP_getBody(statline,head,sin,in);
  617         fclose(sin);
  618     }
  619     if( getFieldValue2(head,"Content-Encoding",AVStr(enc),sizeof(enc)) ){
  620         FILE *sin = in;
  621         in = Gunzip(enc,in);
  622         if( in != sin ){
  623             removeFields(AVStr(head),"Content-Encoding",0);
  624             removeVaryCE(AVStr(head));
  625         }
  626     }
  627 
  628     tmp = TMPFILE("CFI-CONV");
  629 
  630     ohead = nhead = head;
  631     if( getFV(spec,"Header/Filter",filter)
  632      || getFV(spec,"Header-Filter",filter)
  633     ){
  634         FILE *htmp;
  635         int nhsize;
  636         CStr(line,1024);
  637         const char *crlf;
  638         CStr(crlfb,4);
  639 
  640         htmp = TMPFILE("CFI-Header/Filter");
  641 
  642         if( strncmp(statline,"HTTP/",5) == 0 )
  643             fprintf(htmp,"Status-Line: %s",statline);
  644         else
  645         if( statline[0] && strstr(statline,"HTTP/") ){
  646             fprintf(htmp,"Request-Line: %s",statline);
  647             syslog_DEBUG("Request-Line: %s",statline);
  648         }
  649 
  650         fputs(head,htmp); fflush(htmp); fseek(htmp,0,0);
  651         System(ctx,filter,htmp,tmp);
  652         fclose(htmp);
  653         fflush(tmp); fseek(tmp,0,0);
  654         nhsize = file_size(fileno(tmp));
  655         nhead = (char*)malloc(nhsize+2);
  656         IGNRETP fread((char*)nhead,1,nhsize,tmp); /**/
  657         ((char*)nhead)[nhsize] = 0;
  658         fseek(tmp,0,0);
  659         Ftruncate(tmp,0,0);
  660         setPStr(head,(char*)nhead,nhsize+2);
  661 
  662         if( getFV(head,"Status-Line",line)
  663          || getFV(head,"Request-Line",line) ){
  664             removeFields(AVStr(head),"Request-Line",0);
  665             removeFields(AVStr(head),"Status-Line",0);
  666             if( strstr(line,"HTTP/") ){
  667                 if( crlf = strpbrk(statline,"\r\n") )
  668                     strncpy(crlfb,crlf,sizeof(crlfb));
  669                 strcpy(statline,line);
  670                 if( crlf )
  671                     strcat(statline,crlfb);
  672                 syslog_ERROR(">>start-line: %s",statline);
  673             }
  674         }
  675     }
  676 
  677     intmp = NULL; 
  678     xhead = NULL;
  679 
  680     if( getFV(spec,"CGI",cgi) ){
  681         CStr(oreq,4096);
  682         CStr(req,4096);
  683 
  684         intmp = TMPFILE("CFI-CGI");
  685         getFV(head,"X-Request-Original",oreq);
  686         getFV(head,"X-Request",req);
  687 
  688         if( !IsHttpResp(statline) && !IsHttpReqWithBody(statline) )
  689             in = TMPFILE("Empty-Request-Body\n");
  690 
  691         system_CGI(ctx,conninfo,oreq,req,AVStr(head),cgi,in,intmp);
  692         fseek(intmp,0,0);
  693         if( IsHttpResp(statline) ){
  694             fgets(statline,1024,intmp);
  695         }else{
  696             CStr(stat,1024);
  697             fgets(stat,sizeof(stat),intmp);
  698             /* it should be the rewritten Request line ... */
  699         }
  700         xhead = RFC822_readHeader(intmp,0);
  701         setPStr(head,(char*)xhead,strlen(xhead)+1);
  702         in = intmp;
  703     }
  704     if( getFV(spec,"SSI",cgi) ){
  705         intmp = TMPFILE("CFI-SSI");
  706 /*
  707         system_SSI(conninfo,in,intmp);
  708 */
  709         in = intmp;
  710     }
  711 
  712     if( OPgetFV(spec,"Output","Status",ostatus) )
  713         fprintf(tmp,"%s %s\r\n","HTTP/1.0",ostatus);
  714     else    fputs(statline,tmp);
  715 
  716     if( getFV(spec,"Output-Header",oheader) ){
  717         CStr(buf,1024);
  718         genheadf(oheader,AVStr(buf),sizeof(buf));
  719         fputs(buf,tmp);
  720         /*
  721         fputs(oheader,tmp);
  722         */
  723         fputs("\r\n",tmp);
  724     }
  725 
  726     removeFields(AVStr(head),FTOCL_FIELD,1);
  727     removeFields(AVStr(head),"X-Status",1);
  728     if( *savhead == 0 && withbody ){
  729         /* v9.9.9 fix-140609c maybe "body" (for NNTP) */
  730     }else{
  731     fputs(head,tmp);
  732     }
  733     fflush(tmp);
  734     bodyoff = ftell(tmp);
  735 
  736     /*
  737      *  Translate
  738      */
  739     if( withbody ){
  740         int respTHRU = 0;
  741         FILE *stmp = tmp;
  742         CStr(opts,128);
  743         if( getFV(spec,"Options",opts) )
  744         if( isinListX(opts,"NoPerfection","cw") ){
  745             respTHRU = 1;
  746             sv1log("---- in NoPerfection BEGIN\n");
  747             Ftruncate(tmp,bodyoff,0);
  748             fseek(tmp,0,0);
  749             copyfile1(tmp,out);
  750             Ftruncate(tmp,0,0);
  751             tmp = out;
  752             /* if with Message-Filter, it must be invoked
  753              * as a filter process connected with this process
  754              * getting input from a pipe.
  755              * On Windows, the output to socket should be done
  756              * by DeleGate. So, this part for "withbody" should
  757              * be spawned as a pipelined process.
  758              */
  759         }
  760 
  761         if( getFV(spec,"Output-Prefix",prefix) )
  762             substitute(tmp,conninfo,spec,"Output","Prefix",statline,savhead);
  763 
  764         if( getFV(spec,"Filter",filter)
  765          || getFV(spec,"Body-Filter",filter) )
  766         {   FILE *inbody;
  767 
  768             inbody = TMPFILE("CFI-MESSAGE-BODY");
  769             if( HTTP_getBody(statline,head,in,inbody) ){
  770                 fclose(in);
  771                 in = inbody;
  772             }
  773             System(ctx,filter,in,tmp);
  774         }
  775         else{
  776             if( HTTP_getBody(statline,head,in,tmp) ){
  777             }else{
  778                 copyfile1(in,tmp);
  779             }
  780         }
  781 
  782         if( getFV(spec,"Output-Postfix",postfix) )
  783             substitute(tmp,conninfo,spec,"Output","Postfix",statline,savhead);
  784         if( respTHRU ){
  785             tmp = stmp;
  786             fflush(out);
  787             sv1log("---- in NoPerfection END\n");
  788             truncVStr(savhead);
  789         }
  790     }
  791     if( getFV(spec,"MIME-Filter",filter) ){
  792         FILE *inmsg;
  793         inmsg = TMPFILE("CFI-MIME-MESSAGE");
  794         fseek(tmp,0,0);
  795         if( statline[0] ){
  796             CStr(tmpstat,1024);
  797             if( fgets(tmpstat,sizeof(tmpstat),tmp) != NULL ){
  798                 fputs(tmpstat,inmsg);
  799             }
  800         }
  801         System(ctx,filter,tmp,inmsg);
  802         fclose(tmp);
  803         tmp = inmsg;
  804     }
  805     if( getFV(spec,"Message-Filter",filter) ){
  806         FILE *inmsg;
  807         inmsg = TMPFILE("CFI-MESSAGE");
  808         fseek(tmp,0,0);
  809         System(ctx,filter,tmp,inmsg);
  810         fclose(tmp);
  811         tmp = inmsg;
  812     }
  813 
  814 /*
  815     fflush(tmp);
  816     fseek(tmp,bodyoff,0);
  817     if( fgets(statline,SIZEOF(statline),tmp) != NULL ){
  818         if( strncmp(statline,"CFI/",4) == 0 ){
  819             const char *head;
  820 
  821             sv1log("CFI-CONTROL: %s\n",statline);
  822             if( head = RFC822_readHeader(tmp,0) ){
  823                 sv1log("CFI-CONTROL: %s\n",head);
  824                 free((char*)head);
  825             }
  826         }
  827     }
  828 */
  829 
  830     fseek(tmp,0,0);
  831     if( *savhead && withbody ) /* both head & body exist */
  832         HTTP_putMIMEmsg(NULL,tmp,out);
  833     else    copyfile1(tmp,out);
  834     fflush(out);
  835     fclose(tmp);
  836     if( intmp ){
  837         fclose(intmp);
  838         free((char*)xhead);
  839     }
  840     free((char*)savhead);
  841     return 1;
  842 }
  843 
  844 int non_http_conv(DGC *ctx,FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec),PCStr(clproto))
  845 {   const char *spec;
  846     CStr(filter,1024);
  847 
  848     spec = searchSpec(conninfo,convspec,"",conninfo);
  849     if( spec == NULL )
  850         return 0;
  851 
  852     if( getFV(spec,"Filter",filter)
  853      || getFV(spec,"Message-Filter",filter) )
  854         System(ctx,filter,in,out);
  855     else    simple_relayf(in,out);
  856     return 1;
  857 }
  858 
  859 void System(DGC *ctx,PCStr(command),FILE *in,FILE *out)
  860 {
  861     if( 0 <= builtin_filter(ctx,NULL,command,in,out,NULL,NULL) )
  862         return;
  863 
  864     systemFilter(command,in,out);
  865 }
  866 
  867 int putMESSAGEline(FILE *fp,PCStr(type),PCStr(comment))
  868 {
  869     return fprintf(fp,"--MESSAGE/%s %s\r\n",type,comment);
  870 }
  871 int getMESSAGEline(PCStr(line),PVStr(type),PVStr(comment))
  872 {
  873     if( strncmp(line,"--MESSAGE/",10) == 0 )
  874         return Xsscanf(line,"--MESSAGE/%s %[^\r\n]",AVStr(type),AVStr(comment));
  875     else    return 0;
  876 }
  877 
  878 /*    FILTER_MSGS
  879  *  Filter a series of mesages which start with a line headed by
  880  *    "--MESSAGE/line"
  881  *    "--MESSAGE/head"
  882  *    "--MESSAGE/body"
  883  *    "--MESSAGE/mime"
  884  *  and end with a line
  885  *    "." CRLF
  886  */
  887 
  888 void filter_msgs(DGC *ctx,int isresp,PCStr(clproto),FILE *in,FILE *out,PCStr(conninfo),PCStr(convspec))
  889 {   FILE *tmp;
  890     CStr(msgstat,1024);
  891     int nostat;
  892     CStr(statline,1024);
  893     CStr(type,128);
  894     CStr(comment,128);
  895     UTag Uhead; /* v9.9.9 fix-140605b */
  896     const char *head; /**/
  897     int body;
  898     const char *eoh;
  899     CStr(eohb,1024);
  900     CStr(endline,1024);
  901 
  902     tmp = TMPFILE("CFI-MESSAGES");
  903 
  904 sv1log("## CFI/MSGS ##\n");
  905 
  906     for(;;){
  907         if( fPollIn(in,10) == 0 )
  908             fflush(out);
  909         if( fgets(msgstat,sizeof(msgstat),in) == NULL )
  910             break;
  911 
  912 sv1log("CFI/MSGS ---- %s",msgstat);
  913 
  914         /*
  915          *  out of scoope of the filter
  916          */
  917         if( getMESSAGEline(msgstat,AVStr(type),AVStr(comment)) == 0 ){
  918             fputs(msgstat,out);
  919             continue;
  920         }
  921 
  922 /*
  923  {
  924     CStr(filter,1024);
  925     if( getFV(convspec,"Control-Filter",filter) ){
  926     }
  927  }
  928 */
  929 
  930         /*
  931          *  only status line
  932          */
  933         if( strcmp(type,"line") == 0 ){
  934             fgets(statline,sizeof(statline),in);
  935             fputs(statline,out);
  936             continue;
  937         }
  938 
  939         /*
  940          *  status line and [head][body].CRLF
  941          */
  942         nostat = 0;
  943         /* if( !isresp ) */
  944         if( strcaseeq(clproto,"nntp") ){
  945             if( strncasecmp(comment,"POST",4) == 0 )
  946                 nostat = 1;
  947         }else
  948         if( strcaseeq(clproto,"smtp") ){
  949             if( strncasecmp(comment,"DATA",4) == 0 )
  950                 nostat = 1;
  951         }
  952         if( nostat )
  953             statline[0] = 0;
  954         else    fgets(statline,sizeof(statline),in);
  955 
  956         if( strcmp(type,"head") == 0 ){
  957             Uhead = RFC822_readHeaderU(in,1);
  958             body = 0;
  959         }else
  960         if( strcmp(type,"mime") == 0 ){
  961             Uhead = RFC822_readHeaderU(in,1);
  962             body = 1;
  963         }else
  964         if( strcmp(type,"body") == 0 ){
  965             /* v9.9.9 fix-140609b */
  966             Uhead = UTalloc(SB_CONN,MAX_MIMEHEAD,1);
  967             setVStrEnd(Uhead.ut_addr,0);
  968             body = 1;
  969         }else{
  970 sv1log("CFI/MSG ---- unknown type: %s\n",type);
  971             exit(1);
  972         }
  973         head = Uhead.ut_addr;
  974         eoh = strSeekEOH(head);
  975         if( *eoh == '.' ){
  976             strcpy(eohb,eoh);
  977             truncVStr(eoh);
  978         }else   eohb[0] = 0;
  979 
  980         endline[0] = 0;
  981         fseek(tmp,0,0);
  982         if( body ){
  983             relayRESPBODY(in,tmp,AVStr(endline),sizeof(endline));
  984             fflush(tmp);
  985             /*
  986             Ftruncate(tmp,0,2);
  987             */
  988             Ftruncate(tmp,0,1);
  989             fseek(tmp,0,0);
  990         }else{
  991             Ftruncate(tmp,0,0);
  992         }
  993 
  994         fflush(out); /* fix-140609d if buffered output remain, it
  995             * will be inherited by System()->system()->fork()
  996             * then flushed in the child process (maybe before
  997             * exec()) to make duplicated output.
  998             */
  999 
 1000         if( http_conv(ctx,tmp,out,conninfo,convspec,clproto,
 1001             AVStr(statline),AVStr(Uhead.ut_addr),body) == 0 ){
 1002             fputs(statline,out);
 1003             fputs(head,out);
 1004             simple_relayf(tmp,out);
 1005         }
 1006         /*
 1007          * this eohb+endline (maybe ".CRLF") must be suppressed if
 1008          * the status or command is rewritten not to include the body
 1009          * to be ended with ".CRLF"
 1010          * also the body filtered by the external command should be
 1011          * checked not to include such line.
 1012          * a possible solution is passing the endline to the filter
 1013          * command...
 1014          */
 1015         fputs(eohb,out);
 1016         fputs(endline,out);
 1017 
 1018         UTfree(&Uhead);
 1019     }
 1020 }