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); }