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