Annotation of libwww/Library/src/HTRules.c, revision 2.61

2.26      frystyk     1: /*                                                                   HTRules.c
                      2: **     CONFIGURATION MANAGER FOR CLIENTS
                      3: **
2.32      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.26      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.61    ! frystyk     6: **     @(#) $Id: HTRules.c,v 2.60 1999/02/19 23:09:35 frystyk Exp $
2.1       timbl       7: **
2.40      frystyk     8: **     This module manages rule files in the Library
2.1       timbl       9: **
                     10: ** History:
                     11: **      3 Jun 91       Written TBL
                     12: **     10 Aug 91       Authorisation added after Daniel Martin (pass, fail)
                     13: **                     Rule order in file changed
                     14: **                     Comments allowed with # on 1st char of rule line
                     15: **      17 Jun 92       Bug fix: pass and fail failed if didn't contain '*' TBL
2.9       secret     16: **       1 Sep 93       Bug fix: no memory check - Nathan Torkington
                     17: **                      BYTE_ADDRESSING removed - Arthur Secret
2.12      luotonen   18: **     11 Sep 93  MD   Changed %i into %d in debug printf. 
2.10      duns       19: **                     VMS does not recognize %i.
                     20: **                     Bug Fix: in case of PASS, only one parameter to printf.
2.12      luotonen   21: **     19 Sep 93  AL   Added Access Authorization stuff.
                     22: **      1 Nov 93  AL   Added htbin.
2.15      luotonen   23: **     30 Nov 93  AL   Added HTTranslateReq().
2.19      luotonen   24: **      4 Feb 94  AL   Took away all the daemon-specific stuff.
2.36      frystyk    25: **      28 Sep 94  HWL  Added field to HTPresentation_add call
2.40      frystyk    26: **     15 Nov 95  HFN  Made a stream, fixed interface and made new translater
2.11      luotonen   27: **
2.40      frystyk    28: ** BUGS: We only have one wildcard match pr rule!
2.1       timbl      29: */
                     30: 
2.28      frystyk    31: /* Library include files */
2.34      frystyk    32: #include "WWWLib.h"
2.59      frystyk    33: #include "WWWFile.h"
2.40      frystyk    34: #include "HTProxy.h"
2.26      frystyk    35: #include "HTRules.h"                                    /* Implemented here */
2.1       timbl      36: 
2.40      frystyk    37: struct _HTStream {
2.48      frystyk    38:     const HTStreamClass *      isa;
2.40      frystyk    39:     HTRequest *                        request;
                     40:     HTChunk *                  buffer;
2.49      frystyk    41:     HTEOLState                 EOLstate;
2.40      frystyk    42: };
                     43: 
                     44: struct _HTRule {
                     45:     HTRuleOp   op;
                     46:     char *     pattern;
                     47:     char *     replace;
                     48:     int        insert;                /* Index into any wildcard in replace */
                     49: };
                     50: 
                     51: PRIVATE HTList * rules = NULL;
                     52: 
                     53: /* ------------------------------------------------------------------------- */
                     54: 
                     55: /*
                     56: **     Rules are handled as list as everything else that has to do with
                     57: **     preferences. We provide two functions for getting and setting the
                     58: **     global rules
2.1       timbl      59: */
2.40      frystyk    60: PUBLIC HTList * HTRule_global (void)
                     61: {
                     62:     if (!rules) rules = HTList_new();
                     63:     return rules;
                     64: }
2.1       timbl      65: 
2.40      frystyk    66: PUBLIC BOOL HTRule_setGlobal(HTList * list)
                     67: {
                     68:     if (rules) HTRule_deleteAll(rules);
                     69:     rules = list;
                     70:     return YES;
2.53      frystyk    71: }
                     72: 
                     73: PUBLIC BOOL HTRule_addGlobal(HTRuleOp op,
                     74:                             const char * pattern, const char * replace)
                     75: {
                     76:     if (!rules) rules = HTList_new();
                     77:     return HTRule_add(rules, op, pattern, replace);
2.40      frystyk    78: }
2.1       timbl      79: 
2.40      frystyk    80: /*     Add rule to the list
2.1       timbl      81: **     --------------------
2.40      frystyk    82: **     This function adds a rule to the list of rules. The
                     83: **     pattern is a 0-terminated string containing a single
                     84: **     "*". <CODE>equiv</CODE> points to the equivalent string with * for the
                     85: **     place where the text matched by * goes.
2.1       timbl      86: **  On entry,
                     87: **     pattern         points to 0-terminated string containing a single "*"
2.40      frystyk    88: **     replace         points to the equivalent string with * for the
2.1       timbl      89: **                     place where the text matched by * goes.
                     90: **  On exit,
2.40      frystyk    91: **     returns         YES if OK, else NO
2.1       timbl      92: */
2.40      frystyk    93: PUBLIC BOOL HTRule_add (HTList * list, HTRuleOp op,
2.48      frystyk    94:                        const char * pattern, const char * replace)
2.39      frystyk    95: {
2.40      frystyk    96:     if (list && pattern) {
2.45      frystyk    97:        HTRule * me;
                     98:        if ((me = (HTRule  *) HT_CALLOC(1, sizeof(HTRule))) == NULL)
                     99:            HT_OUTOFMEM("HTRule_add");
2.40      frystyk   100:        me->op = op;
                    101:        StrAllocCopy(me->pattern, pattern);
                    102:        if (replace) {
                    103:            char *ptr = strchr(replace, '*');
                    104:            StrAllocCopy(me->replace, replace);
                    105:            me->insert = ptr ? ptr-replace : -1;
2.61    ! frystyk   106:            HTTRACE(APP_TRACE, "Rule Add.... For `%s\' op %d `%s\'\n" _ 
        !           107:                         pattern _ op _ replace);
2.57      frystyk   108:        } else {
2.61    ! frystyk   109:            HTTRACE(APP_TRACE, "Rule Add.... For `%s\' op %d\n" _ pattern _ op);
2.57      frystyk   110:        }
2.54      frystyk   111:        return HTList_appendObject(list, (void *) me);
2.10      duns      112:     }
2.40      frystyk   113:     return NO;
2.1       timbl     114: }
                    115: 
2.40      frystyk   116: /*     Delete all rules
                    117: **     ----------------
                    118: **     Deletes all the rules registered by this module
2.1       timbl     119: */
2.40      frystyk   120: PUBLIC BOOL HTRule_deleteAll (HTList * list)
2.1       timbl     121: {
2.40      frystyk   122:     if (list) {
                    123:        HTList *cur = list;
                    124:        HTRule *pres;
                    125:        while ((pres = (HTRule *) HTList_nextObject(cur))) {
2.45      frystyk   126:            HT_FREE(pres->pattern);
                    127:            HT_FREE(pres->replace);
                    128:            HT_FREE(pres);
2.40      frystyk   129:        }
                    130:        return HTList_delete(list);
2.1       timbl     131:     }
2.40      frystyk   132:     return NO;
2.1       timbl     133: }
                    134: 
2.40      frystyk   135: /*     Translate by rules
2.1       timbl     136: **     ------------------
2.15      luotonen  137: **     The most recently defined rules are applied last.
2.40      frystyk   138: **     This function walks through the list of rules and translates the
                    139: **     reference when matches are found. The list is traversed in order
                    140: **     starting from the head of the list. It returns the address of the
                    141: **     equivalent string allocated from the heap which the CALLER MUST
                    142: **     FREE.
2.1       timbl     143: */
2.48      frystyk   144: PUBLIC char * HTRule_translate (HTList * list, const char * token,
2.40      frystyk   145:                                BOOL ignore_case)
2.1       timbl     146: {
2.40      frystyk   147:     HTRule * pres;
                    148:     char * replace = NULL;
                    149:     if (!token || !list) return NULL;
2.61    ! frystyk   150:     HTTRACE(APP_TRACE, "Check rules. for `%s\'\n" _ token);
2.40      frystyk   151:     while ((pres = (HTRule *) HTList_nextObject(list))) {
                    152:        char * rest = ignore_case ? HTStrCaseMatch(pres->pattern, token) :
                    153:            HTStrMatch(pres->pattern, token);
                    154:        if (!rest) continue;                              /* No match at all */
                    155:     
                    156:        /* We found a match for this entry, now do operation */
                    157:        switch (pres->op) {
                    158: 
                    159:           case HT_Pass:
                    160:          case HT_Map:
                    161:            if (!pres->replace) {                              /* No replace */
                    162:                StrAllocCopy(replace, token);
                    163: 
                    164:            } else if (*rest && pres->insert >= 0) {
2.45      frystyk   165:                if ((replace = (char  *) HT_MALLOC(strlen(pres->replace)+strlen(rest))) == NULL)
                    166:                    HT_OUTOFMEM("HTRule_translate");
2.40      frystyk   167:                strcpy(replace, pres->replace);
                    168:                strcpy(replace+pres->insert, rest);
                    169: 
                    170:            } else {                   /* Perfect match or no insetion point */
                    171:                StrAllocCopy(replace, pres->replace);
                    172:            }
                    173: 
                    174:            if (pres->op == HT_Pass) {
2.61    ! frystyk   175:                HTTRACE(APP_TRACE, "............ map into `%s'\n" _ replace);
2.40      frystyk   176:                return replace;
                    177:            }
                    178:            break;
                    179:            
                    180:          case HT_Fail:
                    181: 
                    182:          default:
2.61    ! frystyk   183:            HTTRACE(APP_TRACE, "............ FAIL `%s'\n" _ token);
2.40      frystyk   184:            return NULL;
2.1       timbl     185:        }
2.40      frystyk   186:     }
                    187:     if (!replace) StrAllocCopy(replace, token);
                    188:     return replace;
2.15      luotonen  189: }
                    190: 
2.7       timbl     191: /*     Load one line of configuration
                    192: **     ------------------------------
                    193: **     Call this, for example, to load a X resource with config info.
2.40      frystyk   194: **     Returns YES if line OK, else NO
2.7       timbl     195: */
2.48      frystyk   196: PUBLIC BOOL HTRule_parseLine (HTList * list, const char * config)
2.7       timbl     197: {
                    198:     HTRuleOp op;
                    199:     char * line = NULL;
2.40      frystyk   200:     char * ptr;
                    201:     char * word1, * word2, * word3;
2.7       timbl     202:     int status;
2.57      frystyk   203:     if (!config) return NO;
2.40      frystyk   204:     if ((ptr = strchr(config, '#'))) *ptr = '\0';
                    205:     StrAllocCopy(line, config);                                 /* Get our own copy */
                    206:     ptr = line;
2.61    ! frystyk   207:     HTTRACE(APP_TRACE, "Rule Parse.. `%s\'\n" _ config ? config : "<null>");
2.40      frystyk   208:     if ((word1 = HTNextField(&ptr)) == NULL) {                /* Empty line */
2.45      frystyk   209:        HT_FREE(line);
2.40      frystyk   210:        return YES;
2.7       timbl     211:     }
2.40      frystyk   212:     if ((word2 = HTNextField(&ptr)) == NULL) {
2.61    ! frystyk   213:        HTTRACE(APP_TRACE, "Rule Parse.. Insufficient operands: `%s\'\n" _ line);
2.45      frystyk   214:        HT_FREE(line);
2.40      frystyk   215:        return NO;
2.7       timbl     216:     }
2.40      frystyk   217:     word3 = HTNextField(&ptr);
2.7       timbl     218: 
2.40      frystyk   219:     /* Look for things we recognize */
                    220:     if (!strcasecomp(word1, "addtype")) {
                    221:        double quality;
                    222:         char * encoding = HTNextField(&ptr);
                    223:        status = ptr ? sscanf(ptr, "%lf", &quality) : 0;
2.37      frystyk   224:        HTBind_add(word2,                               /* suffix */
                    225:                   word3,                               /* type */
                    226:                   encoding ? encoding : "binary",      /* encoding */
2.50      frystyk   227:                   NULL,                                /* cte */
2.40      frystyk   228:                   NULL,                                /* language */
2.37      frystyk   229:                   status >= 1? quality : 1.0);         /* quality */
2.7       timbl     230: 
2.40      frystyk   231:     } else if (!strcasecomp(word1, "addencoding")) {
                    232:        double quality;
                    233:        status = ptr ? sscanf(ptr, "%lf", &quality) : 0;
                    234:        HTBind_addEncoding(word2, word3, status >= 1 ? quality : 1.0);
                    235: 
                    236:     } else if (!strcasecomp(word1, "addlanguage")) {
                    237:        double quality;
                    238:        status = ptr ? sscanf(ptr, "%lf", &quality) : 0;
                    239:        HTBind_addLanguage(word2, word3, status >= 1 ? quality : 1.0);
                    240: 
                    241:     } else if (!strcasecomp(word1, "presentation")) {
                    242:        HTList * converters = HTFormat_conversion();
                    243:        double quality, secs, secs_per_byte;
                    244:         status = ptr ? sscanf(ptr,"%lf%lf%lf",&quality,&secs,&secs_per_byte):0;
2.36      frystyk   245:        HTPresentation_add(converters, word2, word3, NULL,
2.40      frystyk   246:                           status >= 1 ? quality : 1.0,
                    247:                           status >= 2 ? secs : 0.0,
                    248:                           status >= 3 ? secs_per_byte : 0.0);
                    249: 
                    250:     } else if (!strcasecomp(word1, "proxy")) {
                    251:        HTProxy_add(word2, word3);
                    252:        
                    253:     } else if (!strcasecomp(word1, "noproxy")) {
                    254:        int port = 0;
                    255:         status = ptr ? sscanf(ptr, "%d", &port) : 0;
                    256:        HTNoProxy_add(word2, word3, port);
                    257: 
                    258:     } else if (!strcasecomp(word1, "gateway")) {
                    259:        HTGateway_add(word2, word3);
2.12      luotonen  260: 
2.7       timbl     261:     } else {
                    262:        op =    0==strcasecomp(word1, "map")  ? HT_Map
                    263:            :   0==strcasecomp(word1, "pass") ? HT_Pass
                    264:            :   0==strcasecomp(word1, "fail") ? HT_Fail
2.19      luotonen  265:            :                                   HT_Invalid;
2.40      frystyk   266:        if (op == HT_Invalid) {
2.61    ! frystyk   267:            HTTRACE(APP_TRACE, "Rule Parse.. Bad or unknown: `%s'\n" _ config);
2.40      frystyk   268:        } else
                    269:            HTRule_add(list, op, word2, word3);
2.7       timbl     270:     }
2.45      frystyk   271:     HT_FREE(line);
2.40      frystyk   272:     return YES;
2.7       timbl     273: }
                    274: 
2.40      frystyk   275: /*
                    276: **     Folding is either of CF LWS, LF LWS, CRLF LWS
                    277: */
2.48      frystyk   278: PRIVATE int HTRule_put_block (HTStream * me, const char * b, int l)
2.40      frystyk   279: {
                    280:     while (l > 0) {
                    281:        if (me->EOLstate == EOL_FCR) {
                    282:            if (*b == LF)                                            /* CRLF */
                    283:                me->EOLstate = EOL_FLF;
2.56      frystyk   284:            else if (isspace((int) *b))                            /* Folding: CR SP */
2.40      frystyk   285:                me->EOLstate = EOL_DOT;
                    286:            else {                                               /* New line */
2.42      frystyk   287:                HTRule_parseLine(rules, HTChunk_data(me->buffer));
2.40      frystyk   288:                me->EOLstate = EOL_BEGIN;
2.42      frystyk   289:                HTChunk_clear(me->buffer);
2.40      frystyk   290:                continue;
                    291:            }
                    292:        } else if (me->EOLstate == EOL_FLF) {
2.56      frystyk   293:            if (isspace((int) *b))                     /* Folding: LF SP or CR LF SP */
2.40      frystyk   294:                me->EOLstate = EOL_DOT;
                    295:            else {                                              /* New line */
2.42      frystyk   296:                HTRule_parseLine(rules, HTChunk_data(me->buffer));
2.40      frystyk   297:                me->EOLstate = EOL_BEGIN;
2.42      frystyk   298:                HTChunk_clear(me->buffer);
2.40      frystyk   299:                continue;
                    300:            }
                    301:        } else if (me->EOLstate == EOL_DOT) {
2.56      frystyk   302:            if (isspace((int) *b)) {
2.40      frystyk   303:                me->EOLstate = EOL_BEGIN;
2.42      frystyk   304:                HTChunk_putc(me->buffer, ' ');
2.40      frystyk   305:            } else {
2.42      frystyk   306:                HTRule_parseLine(rules, HTChunk_data(me->buffer));
2.40      frystyk   307:                me->EOLstate = EOL_BEGIN;
2.42      frystyk   308:                HTChunk_clear(me->buffer);
2.40      frystyk   309:                continue;
                    310:            }
                    311:        } else if (*b == CR) {
                    312:            me->EOLstate = EOL_FCR;
                    313:        } else if (*b == LF) {
                    314:            me->EOLstate = EOL_FLF;                            /* Line found */
                    315:        } else
2.42      frystyk   316:            HTChunk_putc(me->buffer, *b);
2.40      frystyk   317:        l--; b++;
                    318:     }
                    319:     return HT_OK;
                    320: }
2.1       timbl     321: 
2.40      frystyk   322: PRIVATE int HTRule_put_character (HTStream * me, char c)
                    323: {
                    324:     return HTRule_put_block(me, &c, 1);
                    325: }
                    326: 
2.48      frystyk   327: PRIVATE int HTRule_put_string (HTStream * me, const char * s)
2.40      frystyk   328: {
                    329:     return HTRule_put_block(me, s, (int) strlen(s));
                    330: }
                    331: 
                    332: PRIVATE int HTRule_flush (HTStream * me)
                    333: {
2.51      frystyk   334:     if (me) {
                    335:        char * flush = HTChunk_data(me->buffer);
                    336:        if (flush) HTRule_parseLine(rules, flush);
                    337:        HTChunk_clear(me->buffer);
                    338:     }
                    339:     return HT_OK;
2.40      frystyk   340: }
                    341: 
                    342: PRIVATE int HTRule_free (HTStream * me)
                    343: {
2.51      frystyk   344:     if (me) {
                    345:        int status = HTRule_flush(me);
2.61    ! frystyk   346:        HTTRACE(APP_TRACE, "Rules....... FREEING....\n");
2.51      frystyk   347:        HTChunk_delete(me->buffer);
                    348:        HT_FREE(me);
                    349:        return status;
2.40      frystyk   350:     }
2.51      frystyk   351:     return HT_ERROR;
2.40      frystyk   352: }
                    353: 
                    354: PRIVATE int HTRule_abort (HTStream * me, HTList * e)
                    355: {
2.51      frystyk   356:     if (me) {
                    357:        int status = HT_ERROR;
2.61    ! frystyk   358:        HTTRACE(APP_TRACE, "Rules....... ABORTING...\n");
2.51      frystyk   359:        HTChunk_delete(me->buffer);
                    360:        HT_FREE(me);
                    361:        return status;
                    362:     }
                    363:     return HT_ERROR;
2.40      frystyk   364: }
                    365: 
                    366: /*     Structured Object Class
                    367: **     -----------------------
2.1       timbl     368: */
2.48      frystyk   369: PRIVATE const HTStreamClass HTRuleClass =
2.40      frystyk   370: {              
                    371:     "RuleParser",
                    372:     HTRule_flush,
                    373:     HTRule_free,
                    374:     HTRule_abort,
                    375:     HTRule_put_character,
                    376:     HTRule_put_string,
                    377:     HTRule_put_block
                    378: };
                    379: 
                    380: PUBLIC HTStream * HTRules (HTRequest * request,
                    381:                           void *       param,
                    382:                           HTFormat     input_format,
                    383:                           HTFormat     output_format,
                    384:                           HTStream *   output_stream)
2.1       timbl     385: {
2.41      frystyk   386:     HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);
2.55      frystyk   387:     
                    388:     /*
                    389:     **  If the library has been compiled so that we automatically accept
                    390:     **  rule files then it's OK not to ask the user.
                    391:     */
                    392: #ifdef HT_AUTOMATIC_RULES
                    393:     if (!cbf || (cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
                    394: #else
                    395:     if ((cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
                    396: #endif
                    397:        HTStream * me;
2.61    ! frystyk   398:        HTTRACE(APP_TRACE, "Rule file... Parser object created\n");
2.45      frystyk   399:        if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    400:            HT_OUTOFMEM("HTRules");
2.40      frystyk   401:        me->isa = &HTRuleClass;
                    402:        me->request = request;
2.42      frystyk   403:        me->buffer = HTChunk_new(512);
2.40      frystyk   404:        me->EOLstate = EOL_BEGIN;
                    405:        if (!rules) rules = HTList_new();
2.55      frystyk   406:        return me;
                    407:     } else {
                    408:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
                    409:                           NULL, 0, "HTRules");
                    410:        return HTErrorStream();
                    411:     }
2.1       timbl     412: }
2.11      luotonen  413: 
2.58      frystyk   414: /*
                    415: **  Parse a rule file - don't ask don't tell - be carefull with this one!
                    416: */
                    417: PUBLIC HTStream * HTRules_parseAutomatically (HTRequest *      request,
                    418:                                              void *            param,
                    419:                                              HTFormat          input_format,
                    420:                                              HTFormat          output_format,
                    421:                                              HTStream *        output_stream)
                    422: {
                    423:     if (request) {
                    424:        HTStream * me;
2.61    ! frystyk   425:        HTTRACE(APP_TRACE, "Rule file... Automatic parser object created\n");
2.58      frystyk   426:        if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    427:            HT_OUTOFMEM("HTRules");
                    428:        me->isa = &HTRuleClass;
                    429:        me->request = request;
                    430:        me->buffer = HTChunk_new(512);
                    431:        me->EOLstate = EOL_BEGIN;
                    432:        if (!rules) rules = HTList_new();
                    433:        return me;
                    434:     } else {
                    435:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
                    436:                           NULL, 0, "HTRules");
                    437:        return HTErrorStream();
                    438:     }
                    439: }

Webmaster