You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rb...@locus.apache.org on 2000/12/07 04:32:55 UTC

cvs commit: httpd-2.0/modules/filters mod_include.c mod_include.h

rbb         00/12/06 19:32:55

  Modified:    .        CHANGES
               modules/filters mod_include.c mod_include.h
  Log:
  Make mod_include use a hash table to associate directive tags with
  functions.  This allows modules to implement their own SSI tags easily.
  The idea is simple enough, a module can insert it's own tag and function
  combination into a hash table provided by mod_include.  While mod_include
  parses an SSI file, when it encounters a tag in the file, it does a
  hash lookup to find the function that implements that tag, and passes
  all of the relevant data to the function.  That function is then
  responsible for processing the tag and handing the remaining data back
  to mod_include for further processing.
  Submitted by:	Paul J. Reder <re...@raleigh.ibm.com>
  Reviewed by:	Ryan Bloom
  
  Revision  Changes    Path
  1.3       +10 -0     httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CHANGES	2000/12/04 19:26:04	1.2
  +++ CHANGES	2000/12/07 03:32:52	1.3
  @@ -1,4 +1,14 @@
   Changes with Apache 2.0a9
  +  *) Make mod_include use a hash table to associate directive tags with
  +     functions.  This allows modules to implement their own SSI tags easily.
  +     The idea is simple enough, a module can insert it's own tag and function
  +     combination into a hash table provided by mod_include.  While mod_include
  +     parses an SSI file, when it encounters a tag in the file, it does a
  +     hash lookup to find the function that implements that tag, and passes
  +     all of the relevant data to the function.  That function is then
  +     responsible for processing the tag and handing the remaining data back
  +     to mod_include for further processing.
  +     [Paul J. Reder <re...@raleigh.ibm.com>]
   
     *) Get rid of ap_new_apr_connection().  ap_new_connection() now has 
        fewer parameters: the local and remote socket addresses were removed
  
  
  
  1.82      +80 -99    httpd-2.0/modules/filters/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/filters/mod_include.c,v
  retrieving revision 1.81
  retrieving revision 1.82
  diff -u -r1.81 -r1.82
  --- mod_include.c	2000/11/28 23:07:01	1.81
  +++ mod_include.c	2000/12/07 03:32:54	1.82
  @@ -67,6 +67,7 @@
   #include "apr.h"
   #include "apr_strings.h"
   #include "apr_thread_proc.h"
  +#include "apr_hash.h"
   
   #define CORE_PRIVATE
   
  @@ -93,6 +94,9 @@
   #endif
   #include "util_ebcdic.h"
   
  +
  +static apr_hash_t *include_hash;
  +
   /* ------------------------ Environment function -------------------------- */
   
   /* XXX: could use ap_table_overlap here */
  @@ -180,7 +184,7 @@
                       apr_size_t  start_index;
   
                       /* We want to split the bucket at the '<'. */
  -                    ctx->state            = PARSE_TAG;
  +                    ctx->state            = PARSE_DIRECTIVE;
                       ctx->tag_length       = 0;
                       ctx->parse_pos        = 0;
                       ctx->tag_start_bucket = dptr;
  @@ -250,7 +254,7 @@
           }
           while (c - buf != len) {
               if (*c == str[ctx->parse_pos]) {
  -                if (ctx->state == PARSE_TAG) {
  +                if (ctx->state != PARSE_TAIL) {
                       ctx->state             = PARSE_TAIL;
                       ctx->tail_start_bucket = dptr;
                       ctx->tail_start_index  = c - buf;
  @@ -258,18 +262,28 @@
                   ctx->parse_pos++;
               }
               else {
  -                if (ctx->state == PARSE_TAG) {
  +                if (ctx->state == PARSE_DIRECTIVE) {
                       if (ctx->tag_length == 0) {
                           if (!apr_isspace(*c)) {
                               ctx->tag_start_bucket = dptr;
                               ctx->tag_start_index  = c - buf;
                               ctx->tag_length       = 1;
  +                            ctx->directive_length = 1;
                           }
                       }
                       else {
  +                        if (!apr_isspace(*c)) {
  +                            ctx->directive_length++;
  +                        }
  +                        else {
  +                            ctx->state = PARSE_TAG;
  +                        }
                           ctx->tag_length++;
                       }
                   }
  +                else if (ctx->state == PARSE_TAG) {
  +                    ctx->tag_length++;
  +                }
                   else {
                       if (str[ctx->parse_pos] == '\0') {
                           ap_bucket *tmp_buck = dptr;
  @@ -294,16 +308,24 @@
                            ctx->tag_length += ctx->parse_pos;
   
                            if (*c == str[0]) {
  -                             ctx->parse_pos         = 1;
                                ctx->state             = PARSE_TAIL;
                                ctx->tail_start_bucket = dptr;
                                ctx->tail_start_index  = c - buf;
  +                             ctx->tag_length       += ctx->parse_pos;
  +                             ctx->parse_pos         = 1;
                            }
                            else {
  -                             ctx->parse_pos         = 0;
  -                             ctx->state             = PARSE_TAG;
  +                             if (ctx->tag_length > ctx->directive_length) {
  +                                 ctx->state = PARSE_TAG;
  +                             }
  +                             else {
  +                                 ctx->state = PARSE_DIRECTIVE;
  +                                 ctx->directive_length += ctx->parse_pos;
  +                             }
                                ctx->tail_start_bucket = NULL;
                                ctx->tail_start_index  = 0;
  +                             ctx->tag_length       += ctx->parse_pos;
  +                             ctx->parse_pos         = 0;
                            }
                       }
                   }
  @@ -557,51 +579,7 @@
       return;
   }
   
  -static char *get_directive(include_ctx_t *ctx, dir_token_id *fnd_token)
  -{
  -    char *c = ctx->curr_tag_pos;
  -    char *dest;
  -    int len = 0;
  -
  -    SKIP_TAG_WHITESPACE(c);
  -
  -    dest = c;
  -    /* now get directive */
  -    while ((*c != '\0') && (!apr_isspace(*c))) {
  -        *c = apr_tolower(*c);
  -        c++;
  -        len++;
  -    }
  -    
  -    *c++ = '\0';
  -    ctx->curr_tag_pos = c;
  -
  -    *fnd_token = TOK_UNKNOWN;
  -    switch (len) {
  -    case 2: if      (!strcmp(dest, "if"))       *fnd_token = TOK_IF;
  -            break;
  -    case 3: if      (!strcmp(dest, "set"))      *fnd_token = TOK_SET;
  -            break;
  -    case 4: if      (!strcmp(dest, "else"))     *fnd_token = TOK_ELSE;
  -            else if (!strcmp(dest, "elif"))     *fnd_token = TOK_ELIF;
  -            else if (!strcmp(dest, "exec"))     *fnd_token = TOK_EXEC;
  -            else if (!strcmp(dest, "echo"))     *fnd_token = TOK_ECHO;
  -            break;
  -    case 5: if      (!strcmp(dest, "endif"))    *fnd_token = TOK_ENDIF;
  -            else if (!strcmp(dest, "fsize"))    *fnd_token = TOK_FSIZE;
  -            break;
  -    case 6: if      (!strcmp(dest, "config"))   *fnd_token = TOK_CONFIG;
  -            break;
  -    case 7: if      (!strcmp(dest, "include"))  *fnd_token = TOK_INCLUDE;
  -            break;
  -    case 8: if      (!strcmp(dest, "flastmod")) *fnd_token = TOK_FLASTMOD;
  -            else if (!strcmp(dest, "printenv")) *fnd_token = TOK_PRINTENV;
  -            break;
  -    }
   
  -    return (dest);
  -}
  -
   /*
    * Do variable substitution on strings
    */
  @@ -2688,7 +2666,7 @@
               }
   
               /* Adjust the current bucket position based on what was found... */
  -            if ((tmp_dptr != NULL) && (ctx->state == PARSE_TAG)) {
  +            if ((tmp_dptr != NULL) && (ctx->state == PARSE_DIRECTIVE)) {
                   if (ctx->tag_start_bucket != NULL) {
                       dptr = ctx->tag_start_bucket;
                   }
  @@ -2702,7 +2680,9 @@
           }
   
           /* State to check for the ENDING_SEQUENCE. */
  -        if (((ctx->state == PARSE_TAG) || (ctx->state == PARSE_TAIL)) &&
  +        if (((ctx->state == PARSE_DIRECTIVE) ||
  +             (ctx->state == PARSE_TAG)       ||
  +             (ctx->state == PARSE_TAIL))       &&
               (dptr != AP_BRIGADE_SENTINEL(*bb))) {
               tmp_dptr = find_end_sequence(dptr, ctx, *bb);
   
  @@ -2729,9 +2709,10 @@
           /* State to processed the directive... */
           if (ctx->state == PARSED) {
               ap_bucket    *content_head = NULL, *tmp_bkt;
  +            apr_size_t    tmp_i;
               char          tmp_buf[TMP_BUF_SIZE];
  -            char         *directive_str = NULL;
  -            dir_token_id  directive_token;
  +            int (*handle_func)(include_ctx_t *, ap_bucket_brigade **, request_rec *,
  +                           ap_filter_t *, ap_bucket *, ap_bucket **);
   
               /* By now the full tag (all buckets) should either be set aside into
                *  ssi_tag_brigade or contained within the current bb. All tag
  @@ -2783,55 +2764,26 @@
                *  the contents of a single bucket!
                */
   
  -            /* pjr - This is about to change to be a generic function
  -             *       call from a hash table lookup. All functions need
  -             *       to have the same parms...
  +            /* Retrieve the handler function to be called for this directive from the
  +             *  functions registered in the hash table.
  +             * Need to lower case the directive for proper matching. Also need to have
  +             *  it NULL terminated (and include the NULL in the length) for proper
  +             *  hash matching.
                */
  -            directive_str = get_directive(ctx, &directive_token);
  -
  -            switch (directive_token) {
  -            case TOK_IF:
  -                ret = handle_if(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_ELSE:
  -                ret = handle_else(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_ELIF:
  -                ret = handle_elif(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_ENDIF:
  -                ret = handle_endif(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_EXEC:
  -                ret = handle_exec(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_INCLUDE:
  -                ret = handle_include(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_SET:
  -                ret = handle_set(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_ECHO:
  -                ret = handle_echo(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_FSIZE:
  -                ret = handle_fsize(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_CONFIG:
  -                ret = handle_config(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_FLASTMOD:
  -                ret = handle_flastmod(ctx, bb, r, f, dptr, &content_head);
  -                break;
  -            case TOK_PRINTENV:
  -                ret = handle_printenv(ctx, bb, r, f, dptr, &content_head);
  -                break;
  +            for (tmp_i = 0; tmp_i < ctx->directive_length; tmp_i++) {
  +                ctx->combined_tag[tmp_i] = apr_tolower(ctx->combined_tag[tmp_i]);
  +            }
  +            ctx->combined_tag[ctx->directive_length] = '\0';
  +            ctx->curr_tag_pos = &ctx->combined_tag[ctx->directive_length+1];
   
  -            case TOK_UNKNOWN:
  -            default:
  +            handle_func = apr_hash_get(include_hash, ctx->combined_tag, ctx->directive_length+1);
  +            if (handle_func != NULL) {
  +                ret = (*handle_func)(ctx, bb, r, f, dptr, &content_head);
  +            }
  +            else {
                   ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
                                 "unknown directive \"%s\" in parsed doc %s",
  -                              directive_str, r->filename);
  +                              ctx->combined_tag, r->filename);
                   CREATE_ERROR_BUCKET(ctx, tmp_bkt, dptr, content_head);
               }
   
  @@ -2888,6 +2840,7 @@
               ctx->tail_start_index  = 0;
               ctx->curr_tag_pos      = NULL;
               ctx->tag_length        = 0;
  +            ctx->directive_length  = 0;
   
               if (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
                   while (!AP_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
  @@ -3075,6 +3028,33 @@
       return OK;
   }
   
  +void ap_register_include_handler(char *tag, handler func)
  +{
  +    apr_hash_set(include_hash, tag, strlen(tag) + 1, func);
  +}
  +
  +static void include_post_config(apr_pool_t *p, apr_pool_t *plog,
  +                                apr_pool_t *ptemp, server_rec *s)
  +{
  +    include_hash = apr_make_hash(p);
  +
  +    ap_register_include_handler("if", handle_if);
  +    ap_register_include_handler("set", handle_set);
  +    ap_register_include_handler("else", handle_else);
  +    ap_register_include_handler("elif", handle_elif);
  +    ap_register_include_handler("exec", handle_exec);
  +    ap_register_include_handler("echo", handle_echo);
  +    ap_register_include_handler("endif", handle_endif);
  +    ap_register_include_handler("fsize", handle_fsize);
  +    ap_register_include_handler("config", handle_config);
  +    ap_register_include_handler("include", handle_include);
  +    ap_register_include_handler("flastmod", handle_flastmod);
  +    ap_register_include_handler("printenv", handle_printenv);
  +}
  +
  +/*
  + * Module definition and configuration data structs...
  + */
   static const command_rec includes_cmds[] =
   {
       AP_INIT_TAKE1("XBitHack", set_xbithack, NULL, OR_OPTIONS, 
  @@ -3084,6 +3064,7 @@
   
   static void register_hooks(void)
   {
  +    ap_hook_post_config(include_post_config, NULL, NULL, AP_HOOK_REALLY_FIRST);
       ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_CONTENT);
   }
   
  
  
  
  1.4       +8 -5      httpd-2.0/modules/filters/mod_include.h
  
  Index: mod_include.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/filters/mod_include.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- mod_include.h	2000/11/28 03:19:21	1.3
  +++ mod_include.h	2000/12/07 03:32:54	1.4
  @@ -139,7 +139,7 @@
    * ssi_tag_brigade: The temporary brigade used by this filter to set aside
    *                  the buckets containing parts of the ssi tag and headers.
    */
  -typedef enum {PRE_HEAD, PARSE_HEAD, PARSE_TAG, PARSE_TAIL, PARSED} states;
  +typedef enum {PRE_HEAD, PARSE_HEAD, PARSE_DIRECTIVE, PARSE_TAG, PARSE_TAIL, PARSED} states;
   typedef struct include_filter_ctx {
       states       state;
       long         flags;    /* See the FLAG_XXXXX definitions. */
  @@ -157,6 +157,7 @@
   
       char        *combined_tag;
       char        *curr_tag_pos;
  +    apr_size_t   directive_length;
       apr_size_t   tag_length;
   
       apr_size_t   error_length;
  @@ -177,10 +178,6 @@
   #define FLAG_CLEAR_PRINT_COND 0xFFFFFFFC  /* Reset PRINTING and COND_TRUE*/
   #define FLAG_CLEAR_PRINTING   0xFFFFFFFE  /* Reset just PRINTING bit.    */
   
  -typedef enum {TOK_UNKNOWN, TOK_IF, TOK_SET, TOK_ECHO, TOK_ELIF, TOK_ELSE,
  -              TOK_EXEC, TOK_PERL, TOK_ENDIF, TOK_FSIZE, TOK_CONFIG,
  -              TOK_INCLUDE, TOK_FLASTMOD, TOK_PRINTENV} dir_token_id;
  -
   #define CREATE_ERROR_BUCKET(cntx, t_buck, h_ptr, ins_head)        \
   {                                                                 \
       apr_size_t e_wrt;                                             \
  @@ -202,5 +199,11 @@
       ap_pass_brigade(f->next, brgd);                              \
       brgd = tag_plus;                                             \
   }
  +
  +typedef int (*handler)(include_ctx_t *ctx, ap_bucket_brigade **bb, 
  +                       request_rec *r, ap_filter_t *f, ap_bucket *head_ptr, 
  +                       ap_bucket **inserted_head);
  +
  +void ap_register_include_handler(char *tag, handler func);
   
   #endif /* MOD_INCLUDE */