fielding 99/07/30 20:30:19
Modified: src CHANGES
src/main http_protocol.c
Log:
Replace the Vary fixup code with a single-pass, single-copy
implementation that only adds the cost of a single ap_make_array
when there is no Vary field.
Revision Changes Path
1.1406 +1 -1 apache-1.3/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.1405
retrieving revision 1.1406
diff -u -r1.1405 -r1.1406
--- CHANGES 1999/07/31 00:37:22 1.1405
+++ CHANGES 1999/07/31 03:30:16 1.1406
@@ -10,7 +10,7 @@
*) Fix SIGSEGV on some systems because the Vary fix below included
a call to table_do with a variable argument list that was not
- NULL terminated. [Roy Fielding]
+ NULL terminated. Replaced with better implementation. [Roy Fielding]
Changes with Apache 1.3.7 [not released]
1.275 +56 -85 apache-1.3/src/main/http_protocol.c
Index: http_protocol.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_protocol.c,v
retrieving revision 1.274
retrieving revision 1.275
diff -u -r1.274 -r1.275
--- http_protocol.c 1999/07/31 00:37:25 1.274
+++ http_protocol.c 1999/07/31 03:30:18 1.275
@@ -1446,27 +1446,55 @@
&& strstr(ua, "MSIE 3")));
}
-/*
- * qsort comparison routine for fixup_vary().
+/* This routine is called by ap_table_do and merges all instances of
+ * the passed field values into a single array that will be further
+ * processed by some later routine. Originally intended to help split
+ * and recombine multiple Vary fields, though it is generic to any field
+ * consisting of comma/space-separated tokens.
*/
-static int compare_vary(const void *va, const void *vb)
+static int uniq_field_values(void *d, const char *key, const char *val)
{
- return strcasecmp(*(const char **)va, *(const char **)vb);
-}
+ array_header *values;
+ char *start;
+ char *e;
+ char **strpp;
+ int i;
-/*
- * ap_table_get() only picks up the first occurrence of a key,
- * which means that if there's a Vary in r->headers_out and another
- * in r->err_headers_out, one might get ignored. This routine
- * is called by ap_table_do and merges all instances of Vary into
- * a temporary list in r->notes.
- */
-static int merge_vary_fields(void *d, const char *key, const char *val)
-{
- request_rec *r;
+ values = (array_header *)d;
+
+ e = ap_pstrdup(values->pool, val);
- r = (request_rec *)d;
- ap_table_merge(r->notes, "Vary-list", val);
+ do {
+ /* Find a non-empty fieldname */
+
+ while (*e == ',' || ap_isspace(*e)) {
+ ++e;
+ }
+ if (*e == '\0') {
+ break;
+ }
+ start = e;
+ while (*e != '\0' && *e != ',' && !ap_isspace(*e)) {
+ ++e;
+ }
+ if (*e != '\0') {
+ *e++ = '\0';
+ }
+
+ /* Now add it to values if it isn't already represented.
+ * Could be replaced by a ap_array_strcasecmp() if we had one.
+ */
+ for (i = 0, strpp = (char **) values->elts; i < values->nelts;
+ ++i, ++strpp) {
+ if (*strpp && strcasecmp(*strpp, start) == 0) {
+ break;
+ }
+ }
+ if (i == values->nelts) { /* if not found */
+ *(char **)ap_push_array(values) = start;
+ }
+ } while (*e != '\0');
+
return 1;
}
@@ -1477,80 +1505,23 @@
*/
static void fixup_vary(request_rec *r)
{
- const char *vary;
- array_header *arr;
- char *start;
- char *e;
- char **ecur;
- char **eend;
- char **ekeep;
+ array_header *varies;
- /* Don't do any unnecessary manipulations..
- */
- if (ap_table_get(r->headers_out, "Vary") == NULL) {
- return;
- }
- ap_table_do((int (*)(void *, const char *, const char
*))merge_vary_fields,
- (void *) r, r->headers_out, "Vary", NULL);
- vary = ap_table_get(r->notes, "Vary-list");
-
- /* XXX: we could make things a lot better, by having r->vary,
- * which is an array of char * -- which modules append to as they
- * find things which the request varies on. This is probably
- * better than a table, because a table would require O(n^2)
- * string comparisons... another option would be to use a table
- * but indicate that folks should use ap_table_add...
- * at any rate, if we had such an array, we would just set
- * arr = r->vary here (or arr = ap_table_elts(r->vary)).
- */
- arr = ap_make_array(r->pool, 5, sizeof(char *));
+ varies = ap_make_array(r->pool, 5, sizeof(char *));
- /* XXX: this part could become a new routine which takes a string
- * and breaks it up, appending to an array, spliting on /[,\s]+/.
+ /* Extract all Vary fields from the headers_out, separate each into
+ * its comma-separated fieldname values, and then add them to varies
+ * if not already present in the array.
*/
- e = ap_pstrdup(r->pool, vary);
- start = e;
- while (*e) {
- while (ap_isspace(*e)) {
- ++e;
- }
- start = e;
- e = strchr(e, ',');
- if (!e) {
- break;
- }
- *e = '\0';
- *(char **)ap_push_array(arr) = start;
- ++e;
- }
- if (*start) {
- *(char **)ap_push_array(arr) = start;
- }
+ ap_table_do((int (*)(void *, const char *, const char
*))uniq_field_values,
+ (void *) varies, r->headers_out, "Vary", NULL);
- /* XXX: this part could become a new routine which modifies an
- * array of char * in place, eliminating duplicate entries
- */
- if (arr->nelts > 1) {
- qsort(arr->elts, arr->nelts, sizeof(char *), compare_vary);
+ /* If we found any, replace old Vary fields with unique-ified value */
- /* now pluck out the non-duplicates */
- ekeep = (char **)arr->elts;
- ecur = ekeep + 1;
- eend = ekeep + arr->nelts - 1;
- while (ecur <= eend) {
- if (strcasecmp(*ecur, *ekeep)) {
- *++ekeep = *ecur;
- }
- ++ecur;
- }
- arr->nelts = ekeep - (char **)arr->elts + 1;
+ if (varies->nelts > 0) {
+ ap_table_setn(r->headers_out, "Vary",
+ ap_array_pstrcat(r->pool, varies, ','));
}
-
- /* and finally we're done, we can just merge the array adding ,
- * between entries
- */
- ap_table_setn(r->headers_out, "Vary",
- ap_array_pstrcat(r->pool, arr, ','));
}
API_EXPORT(void) ap_send_http_header(request_rec *r)