fielding    99/02/11 08:24:12

  Modified:    src/main util.c
               src/test test_parser.c
  Added:       src/test test_find.c
  Log:
  Replace the simple implementation of ap_find_list_item() with a
  much more efficient but complex implementation.
  
  Revision  Changes    Path
  1.152     +87 -10    apache-1.3/src/main/util.c
  
  Index: util.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/util.c,v
  retrieving revision 1.151
  retrieving revision 1.152
  diff -u -r1.151 -r1.152
  --- util.c    1999/02/10 13:36:50     1.151
  +++ util.c    1999/02/11 16:24:09     1.152
  @@ -1132,24 +1132,101 @@
    * an HTTP field value list.  Returns 1 if found, 0 if not found.
    * This would be much more efficient if we stored header fields as
    * an array of list items as they are received instead of a plain string.
  - * We could make it more efficient by duplicating the loop/switch above
  - * within this function, replacing the assignments with compares.
    */
   API_EXPORT(int) ap_find_list_item(pool *p, const char *line, const char *tok)
   {
  -    const char *nxt;
  -    char *item;
  +    const unsigned char *pos;
  +    const unsigned char *ptr = (const unsigned char *)line;
  +    int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
   
       if (!line || !tok)
           return 0;
   
  -    nxt = line;
  +    do {  /* loop for each item in line's list */
   
  -    while ((item = ap_get_list_item(p, &nxt)) != NULL) {
  -        if (strcmp(item, tok) == 0)
  -            return 1;
  -    }
  -    return 0;
  +        /* Find first non-comma, non-whitespace byte */
  +
  +        while (*ptr == ',' || ap_isspace(*ptr))
  +            ++ptr;
  +
  +        if (*ptr)
  +            good = 1;  /* until proven otherwise for this item */
  +        else
  +            break;     /* no items left and nothing good found */
  +
  +        /* We skip extra whitespace and any whitespace around a '=', '/',
  +         * or ';' and lowercase normal characters not within a comment,
  +         * quoted-string or quoted-pair.
  +         */
  +        for (pos = (const unsigned char *)tok;
  +             *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
  +             ++ptr) {
  +
  +            if (in_qpair) {
  +                in_qpair = 0;
  +                if (good)
  +                    good = (*pos++ == *ptr);
  +            }
  +            else {
  +                switch (*ptr) {
  +                    case '\\': in_qpair = 1;
  +                               if (addspace == 1)
  +                                   good = good && (*pos++ == ' ');
  +                               good = good && (*pos++ == *ptr);
  +                               addspace = 0;
  +                               break;
  +                    case '"' : if (!in_com)
  +                                   in_qstr = !in_qstr;
  +                               if (addspace == 1)
  +                                   good = good && (*pos++ == ' ');
  +                               good = good && (*pos++ == *ptr);
  +                               addspace = 0;
  +                               break;
  +                    case '(' : if (!in_qstr)
  +                                   ++in_com;
  +                               if (addspace == 1)
  +                                   good = good && (*pos++ == ' ');
  +                               good = good && (*pos++ == *ptr);
  +                               addspace = 0;
  +                               break;
  +                    case ')' : if (in_com)
  +                                   --in_com;
  +                               good = good && (*pos++ == *ptr);
  +                               addspace = 0;
  +                               break;
  +                    case ' ' :
  +                    case '\t': if (addspace || !good)
  +                                   break;
  +                               if (in_com || in_qstr)
  +                                   good = (*pos++ == *ptr);
  +                               else
  +                                   addspace = 1;
  +                               break;
  +                    case '=' :
  +                    case '/' :
  +                    case ';' : if (!(in_com || in_qstr))
  +                                   addspace = -1;
  +                               good = good && (*pos++ == *ptr);
  +                               break;
  +                    default  : if (!good)
  +                                   break;
  +                               if (addspace == 1)
  +                                   good = (*pos++ == ' ');
  +                               if (in_com || in_qstr)
  +                                   good = good && (*pos++ == *ptr);
  +                               else
  +                                   good = good && (*pos++ == 
ap_tolower(*ptr));
  +                               addspace = 0;
  +                               break;
  +                }
  +            }
  +        }
  +        if (good && *pos)
  +            good = 0;          /* not good if only a prefix was matched */
  +
  +    } while (*ptr && !good);
  +
  +    return good;
   }
   
   
  
  
  
  1.3       +1 -1      apache-1.3/src/test/test_parser.c
  
  Index: test_parser.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/test/test_parser.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- test_parser.c     1999/02/10 13:36:51     1.2
  +++ test_parser.c     1999/02/11 16:24:11     1.3
  @@ -1,4 +1,4 @@
  -/* This program tests the ap_get_list_item routine in ../main/util_date.c.
  +/* This program tests the ap_get_list_item routine in ../main/util.c.
    *
    * The defines in this sample compile line are specific to Roy's system.
    * They should match whatever was used to compile Apache first.
  
  
  
  1.1                  apache-1.3/src/test/test_find.c
  
  Index: test_find.c
  ===================================================================
  /* This program tests the ap_find_list_item routine in ../main/util.c.
   *
   * The defines in this sample compile line are specific to Roy's system.
   * They should match whatever was used to compile Apache first.
   *
       gcc -g -O2 -I../os/unix -I../include -o test_find \
              -DSOLARIS2=250 -Wall -DALLOC_DEBUG -DPOOL_DEBUG \
              ../main/alloc.o ../main/buff.o ../main/util.o \
              ../ap/libap.a -lsocket -lnsl test_find.c
   * 
   * Roy Fielding, 1999
   */
  #include <stdio.h>
  #include <stdlib.h>
  #include "httpd.h"
  #include "alloc.h"
  
  /*
   * Dummy a bunch of stuff just to get a compile
   */
  uid_t ap_user_id;
  gid_t ap_group_id;
  void *ap_dummy_mutex = &ap_dummy_mutex;
  char *ap_server_argv0;
  
  API_EXPORT(void) ap_block_alarms(void)
  {
      ;
  }
  
  API_EXPORT(void) ap_unblock_alarms(void)
  {
      ;
  }
  
  API_EXPORT(void) ap_log_error(const char *file, int line, int level,
                                const request_rec *r, const char *fmt, ...)
  {
      ;
  }
  
  int main (void)
  {
      ap_pool *p;
      char line[512];
      char tok[512];
  
      p = ap_init_alloc();
  
      printf("Enter field value to find items within:\n");
      if (!gets(line))
          exit(0);
  
      printf("Enter search item:\n");
      while (gets(tok)) {
          printf("  [%s] == %s\n", tok, ap_find_list_item(p, line, tok)
                                    ? "Yes" : "No");
          printf("Enter search item:\n");
      }
      
      exit(0);
  }
  
  
  

Reply via email to