You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by fi...@hyperreal.org on 1999/02/08 16:12:22 UTC
cvs commit: apache-1.3/src/test test_parser.c
fielding 99/02/08 07:12:22
Modified: src ApacheCore.def CHANGES
src/include ap_mmn.h httpd.h
src/main util.c
src/modules/standard mod_negotiation.c
src/support httpd.exp
Added: src/test test_parser.c
Log:
Added ap_find_list_item() and ap_get_list_item() to util.c for parsing
an HTTP header field value to extract the next list item, taking into
account the possible presence of nested comments, quoted-pairs,
and quoted-strings. ap_get_list_item() also removes insignificant
whitespace and lowercases non-quoted tokens.
Work around a bug in Lynx regarding its sending "Negotiate: trans"
even though it doesn't understand TCN.
PR: 2065
Revision Changes Path
1.10 +2 -0 apache-1.3/src/ApacheCore.def
Index: ApacheCore.def
===================================================================
RCS file: /home/cvs/apache-1.3/src/ApacheCore.def,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- ApacheCore.def 1999/02/03 16:22:27 1.9
+++ ApacheCore.def 1999/02/08 15:12:15 1.10
@@ -327,4 +327,6 @@
ap_find_opaque_token @320
ap_MD5Encode @321
ap_validate_password @322
+ ap_find_list_item @323
+ ap_get_list_item @324
1.1239 +9 -0 apache-1.3/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.1238
retrieving revision 1.1239
diff -u -r1.1238 -r1.1239
--- CHANGES 1999/02/07 20:53:44 1.1238
+++ CHANGES 1999/02/08 15:12:16 1.1239
@@ -1,5 +1,14 @@
Changes with Apache 1.3.5
+ *) Work around a bug in Lynx regarding its sending "Negotiate: trans"
+ even though it doesn't understand TCN. [Koen Holtman, Roy Fielding]
+
+ *) Added ap_find_list_item() and ap_get_list_item() to util.c for parsing
+ an HTTP header field value to extract the next list item, taking into
+ account the possible presence of nested comments, quoted-pairs,
+ and quoted-strings. ap_get_list_item() also removes insignificant
+ whitespace and lowercases non-quoted tokens. [Roy Fielding] PR#2065
+
*) proxy: The various calls to ap_proxyerror() can return HTTP/1.1 status
code different from 500. This allows the proxy to, e.g., return
"403 Forbidden" for ProxyBlock'ed URL's. [Martin Kraemer]
1.26 +4 -3 apache-1.3/src/include/ap_mmn.h
Index: ap_mmn.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/ap_mmn.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- ap_mmn.h 1999/02/03 16:22:31 1.25
+++ ap_mmn.h 1999/02/08 15:12:18 1.26
@@ -203,13 +203,14 @@
* scan_script_header -> ap_scan_script_header_err
* - reordered entries in request_rec that were waiting
* for a non-binary-compatible release.
- * 19990108-1 - add ap_find_opaque_token() for things like ETags
+ * 19990108.1 - add ap_find_opaque_token() for things like ETags
* (1.3.5-dev) which can contain opaque quoted strings, and
* ap_MD5Encode() for MD5 password handling.
- * 19990108-2 - add ap_validate_password() and change ap_MD5Encode()
+ * 19990108.2 - add ap_validate_password() and change ap_MD5Encode()
* (1.3.5-dev) to use a stronger algorithm (which is incompatible
* with the one introduced [but not released] with
* 19990108-1).
+ * 19990108.3 - add ap_find_list_item() and ap_get_list_item()
*/
#define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
@@ -217,7 +218,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 19990108
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 3 /* 0...n */
#define MODULE_MAGIC_NUMBER MODULE_MAGIC_NUMBER_MAJOR /* backward compat */
/* Useful for testing for features. */
1.267 +2 -0 apache-1.3/src/include/httpd.h
Index: httpd.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/httpd.h,v
retrieving revision 1.266
retrieving revision 1.267
diff -u -r1.266 -r1.267
--- httpd.h 1999/02/05 09:14:56 1.266
+++ httpd.h 1999/02/08 15:12:18 1.267
@@ -932,6 +932,8 @@
API_EXPORT(char *) ap_getword_conf(pool *p, const char **line);
API_EXPORT(char *) ap_getword_conf_nc(pool *p, char **line);
+API_EXPORT(const char *) ap_find_list_item(const char **field, int *len);
+API_EXPORT(char *) ap_get_list_item(pool *p, const char **field);
API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_white);
API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok);
API_EXPORT(int) ap_find_opaque_token(pool *p, const char *line,
1.148 +152 -0 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.147
retrieving revision 1.148
diff -u -r1.147 -r1.148
--- util.c 1999/01/27 12:16:02 1.147
+++ util.c 1999/02/08 15:12:19 1.148
@@ -978,6 +978,158 @@
}
}
+/* Find an HTTP header field list item, as separated by a comma.
+ * The return value is a pointer to the beginning of the non-empty list item
+ * within the original string (or NULL if there is none) and the address
+ * of field is shifted to the next non-comma, non-whitespace character.
+ * len is the length of the item excluding any beginning whitespace.
+ */
+API_EXPORT(const char *) ap_find_list_item(const char **field, int *len)
+{
+ const char *ptr = *field;
+ const char *token;
+ int in_qpair, in_qstr, in_com;
+
+ /* Find first non-comma, non-whitespace byte */
+
+ while (*ptr == ',' || ap_isspace(*ptr))
+ ++ptr;
+
+ token = ptr;
+
+ /* Find the end of this item, skipping over dead bits */
+
+ for (in_qpair = in_qstr = in_com = 0;
+ *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
+ ++ptr) {
+
+ if (in_qpair) {
+ in_qpair = 0;
+ }
+ else {
+ switch (*ptr) {
+ case '\\': in_qpair = 1; /* quoted-pair */
+ break;
+ case '"' : if (!in_com) /* quoted string delim */
+ in_qstr = !in_qstr;
+ break;
+ case '(' : if (!in_qstr) /* comment (may nest) */
+ ++in_com;
+ break;
+ case ')' : if (in_com) /* end comment */
+ --in_com;
+ break;
+ default : break;
+ }
+ }
+ }
+
+ if ((*len = (ptr - token)) == 0) {
+ *field = ptr;
+ return NULL;
+ }
+
+ /* Advance field pointer to the next non-comma, non-white byte */
+
+ while (*ptr == ',' || ap_isspace(*ptr))
+ ++ptr;
+
+ *field = ptr;
+ return token;
+}
+
+/* Retrieve an HTTP header field list item, as separated by a comma,
+ * while stripping insignificant whitespace/comments and lowercasing anything
+ * not in a quoted string. The return value is a new string containing
+ * the converted list item (empty if it was all comments or NULL if none)
+ * and the address of field is shifted to the next non-comma, non-whitespace.
+ */
+API_EXPORT(char *) ap_get_list_item(pool *p, const char **field)
+{
+ const char *tok_start, *ptr;
+ char *token, *pos;
+ int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
+
+ /* Find the beginning and maximum length of the list item so that
+ * we can allocate a buffer for the new string and reset the field.
+ */
+ if ((tok_start = ap_find_list_item(field, &tok_len)) == NULL) {
+ return NULL;
+ }
+ token = ap_palloc(p, tok_len + 1);
+
+ /* Scan the token again, but this time copy only the good bytes.
+ * We skip extra whitespace and any whitespace around a '=' or ';',
+ * strip comments, and lowercase normal characters not within a
+ * quoted-string or quoted-pair. The result may be an empty string.
+ */
+ for (ptr = tok_start, pos = token;
+ *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
+ ++ptr) {
+
+ if (in_qpair) {
+ in_qpair = 0;
+ if (!in_com)
+ *pos++ = *ptr;
+ }
+ else {
+ switch (*ptr) {
+ case '\\': in_qpair = 1;
+ if (in_com)
+ break;
+ if (addspace == 1)
+ *pos++ = ' ';
+ *pos++ = *ptr;
+ addspace = 0;
+ break;
+ case '"' : if (in_com)
+ break;
+ in_qstr = !in_qstr;
+ if (addspace == 1)
+ *pos++ = ' ';
+ *pos++ = *ptr;
+ addspace = 0;
+ break;
+ case '(' : if (in_qstr)
+ *pos++ = *ptr;
+ else
+ ++in_com;
+ break;
+ case ')' : if (in_com)
+ --in_com;
+ else
+ *pos++ = *ptr;
+ break;
+ case ' ' :
+ case '\t': if (in_com || addspace)
+ break;
+ if (in_qstr)
+ *pos++ = *ptr;
+ else
+ addspace = 1;
+ break;
+ case '=' :
+ case ';' : if (in_com)
+ break;
+ if (!in_qstr)
+ addspace = -1;
+ *pos++ = *ptr;
+ break;
+ default : if (in_com)
+ break;
+ if (addspace == 1)
+ *pos++ = ' ';
+ *pos++ = in_qstr ? *ptr : ap_tolower(*ptr);
+ addspace = 0;
+ break;
+ }
+ }
+ }
+ *pos = '\0';
+
+ return token;
+}
+
/* Retrieve a token, spacing over it and returning a pointer to
* the first non-white byte afterwards. Note that these tokens
* are delimited by semis and commas; and can also be delimited
1.97 +64 -64 apache-1.3/src/modules/standard/mod_negotiation.c
Index: mod_negotiation.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_negotiation.c,v
retrieving revision 1.96
retrieving revision 1.97
diff -u -r1.96 -r1.97
--- mod_negotiation.c 1999/02/06 14:36:27 1.96
+++ mod_negotiation.c 1999/02/08 15:12:20 1.97
@@ -511,78 +511,78 @@
static void parse_negotiate_header(request_rec *r, negotiation_state *neg)
{
const char *negotiate = ap_table_get(r->headers_in, "Negotiate");
+ char *tok;
- if (negotiate) {
- /* Negotiate: header tells us UA does transparent negotiation */
-
- /* sending Alternates on non-transparent resources is allowed,
- * and may even be useful, but we don't for now, also
- * because it could clash with an Alternates header set by
- * a sub- or super- request on a transparent resource.
+ /* First, default to no TCN, no Alternates, and the original Apache
+ * negotiation algorithm with fiddles for broken browser configs.
+ *
+ * To save network bandwidth, we do not configure to send an
+ * Alternates header to the user agent by default. User
+ * agents that want an Alternates header for agent-driven
+ * negotiation will have to request it by sending an
+ * appropriate Negotiate header.
+ */
+ neg->ua_supports_trans = 0;
+ neg->send_alternates = 0;
+ neg->may_choose = 1;
+ neg->use_rvsa = 0;
+ neg->dont_fiddle_headers = 0;
+
+ if (!negotiate)
+ return;
+
+ if (strcmp(negotiate, "trans") == 0) {
+ /* Lynx 2.7 and 2.8 send 'negotiate: trans' even though they
+ * do not support transparent content negotiation, so for Lynx we
+ * ignore the negotiate header when its contents are exactly "trans".
+ * If future versions of Lynx ever need to say 'negotiate: trans',
+ * they can send the equivalent 'negotiate: trans, trans' instead
+ * to avoid triggering the workaround below.
*/
+ const char *ua = ap_table_get(r->headers_in, "User-Agent");
+
+ if (ua && (strncmp(ua, "Lynx", 4) == 0))
+ return;
+ }
- while (*negotiate) {
- char *tok = ap_get_token(neg->pool, &negotiate, 1);
- char *cp;
+ neg->may_choose = 0; /* An empty Negotiate would require 300 response */
- for (cp = tok; (*cp && !ap_isspace(*cp) && *cp != '='); ++cp) {
- *cp = ap_tolower(*cp);
+ while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) {
+
+ if (strcmp(tok, "trans") == 0 ||
+ strcmp(tok, "vlist") == 0 ||
+ strcmp(tok, "guess-small") == 0 ||
+ ap_isdigit(tok[0]) ||
+ strcmp(tok, "*") == 0) {
+
+ /* The user agent supports transparent negotiation */
+ neg->ua_supports_trans = 1;
+
+ /* Send-alternates could be configurable, but note
+ * that it must be 1 if we have 'vlist' in the
+ * negotiate header.
+ */
+ neg->send_alternates = 1;
+
+ if (strcmp(tok, "1.0") == 0) {
+ /* we may use the RVSA/1.0 algorithm, configure for it */
+ neg->may_choose = 1;
+ neg->use_rvsa = 1;
+ neg->dont_fiddle_headers = 1;
}
- *cp = 0;
-
- if (strcmp(tok, "trans") == 0 ||
- strcmp(tok, "vlist") == 0 ||
- strcmp(tok, "guess-small") == 0 ||
- ap_isdigit(tok[0]) ||
- strcmp(tok, "*") == 0) {
-
- /* The user agent supports transparent negotiation */
- neg->ua_supports_trans = 1;
-
- /* Send-alternates could be configurable, but note
- * that it must be 1 if we have 'vlist' in the
- * negotiate header.
+ else if (tok[0] == '*') {
+ /* we may use any variant selection algorithm, configure
+ * to use the Apache algorithm
*/
- neg->send_alternates = 1;
-
- if (strcmp(tok, "1.0") == 0) {
- /* we may use the RVSA/1.0 algorithm, configure for it */
- neg->may_choose = 1;
- neg->use_rvsa = 1;
- neg->dont_fiddle_headers = 1;
- }
- else if (strcmp(tok, "*") == 0) {
- /* we may use any variant selection algorithm, configure
- * to use the Apache algorithm
- */
- neg->may_choose = 1;
-
- /* We disable header fiddles on the assumption that a
- * client sending Negotiate knows how to send correct
- * headers which don't need fiddling.
- */
- neg->dont_fiddle_headers = 1;
- }
+ neg->may_choose = 1;
+
+ /* We disable header fiddles on the assumption that a
+ * client sending Negotiate knows how to send correct
+ * headers which don't need fiddling.
+ */
+ neg->dont_fiddle_headers = 1;
}
-
- if (*negotiate)
- negotiate++; /* skip over , */
}
- }
-
- if (!neg->ua_supports_trans) {
- /* User agent does not support transparent negotiation,
- * configure to do server-driven negotiation with the Apache
- * algorithm.
- */
- neg->may_choose = 1;
-
- /* To save network bandwidth, we do not configure to send an
- * Alternates header to the user agent in this case. User
- * agents which want an Alternates header for agent-driven
- * negotiation will have to request it by sending an
- * appropriate Negotiate header.
- */
}
#ifdef NEG_DEBUG
1.14 +2 -0 apache-1.3/src/support/httpd.exp
Index: httpd.exp
===================================================================
RCS file: /home/cvs/apache-1.3/src/support/httpd.exp,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- httpd.exp 1999/02/03 16:22:34 1.13
+++ httpd.exp 1999/02/08 15:12:21 1.14
@@ -106,6 +106,7 @@
ap_find_command_in_modules
ap_find_last_token
ap_find_linked_module
+ap_find_list_item
ap_find_module_name
ap_find_opaque_token
ap_find_path_info
@@ -117,6 +118,7 @@
ap_get_basic_auth_pw
ap_get_client_block
ap_get_gmtoff
+ap_get_list_item
ap_get_local_host
ap_get_remote_host
ap_get_remote_logname
1.1 apache-1.3/src/test/test_parser.c
Index: test_parser.c
===================================================================
/* This program tests the ap_get_list_item routine in ../main/util_date.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_parser \
-DSOLARIS2=250 -Wall -DALLOC_DEBUG -DPOOL_DEBUG \
../main/alloc.o ../main/buff.o ../main/util.o \
../main/http_log.o ../ap/libap.a \
-lsocket -lnsl test_parser.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;
const char *field;
char *newstr;
char instr[512];
p = ap_init_alloc();
while (gets(instr)) {
printf(" [%s] ==\n", instr);
field = instr;
while ((newstr = ap_get_list_item(p, &field)) != NULL)
printf(" <%s> ..\n", newstr);
}
exit(0);
}