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