akosut      96/07/28 12:27:58

  Modified:    src       buff.c buff.h http_config.h http_core.c
                        http_protocol.c  http_protocol.h http_request.c
                        httpd.h mod_actions.c  mod_alias.c mod_cgi.c
                        mod_include.c mod_negotiation.c  mod_proxy.c util.c
  Log:
  Make Apache unconditionally compliant with all HTTP/1.1 features and
  requirements, as of draft -06.
  
  Revision  Changes    Path
  1.5       +40 -4     apache/src/buff.c
  
  Index: buff.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/buff.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -C3 -r1.4 -r1.5
  *** buff.c    1996/07/25 19:32:26     1.4
  --- buff.c    1996/07/28 19:27:41     1.5
  ***************
  *** 1,3 ****
  --- 1,4 ----
  + 
    /* ====================================================================
     * Copyright (c) 1996 The Apache Group.  All rights reserved.
     *
  ***************
  *** 173,178 ****
  --- 174,193 ----
    }
    
    /*
  +  * Set a flag on (1) or off (0). Currently, these flags work
  +  * as a function of the bcwrite() function, so we make sure to
  +  * flush before setting them one way or the other; otherwise
  +  * writes could end up with the wrong flag.
  +  */
  + int bsetflag(BUFF *fb, int flag, int value)
  + {
  +     bflush(fb);
  +     if (value) fb->flags |= flag;
  +     else fb->flags &= ~flag;
  +     return value;
  + }
  + 
  + /*
     * Read up to nbyte bytes into buf.
     * If fewer than byte bytes are currently available, then return those.
     * Returns 0 for EOF, -1 for error.
  ***************
  *** 410,415 ****
  --- 425,451 ----
    }
    
    /*
  +  * A hook to write() that deals with chunking. This is really a protocol-
  +  * level issue, but we deal with it here because it's simpler; this is
  +  * an interim solution pending a complete rewrite of all this stuff in
  +  * 2.0, using something like sfio stacked disciplines or BSD's funopen().
  +  */
  + int bcwrite(BUFF *fb, const void *buf, int nbyte) {
  +     int r;
  + 
  +     if (fb->flags & B_CHUNK) {
  +     char chunksize[16];     /* Big enough for practically anything */
  + 
  +     sprintf(chunksize, "%x\015\012", nbyte);
  +     write(fb->fd, chunksize, strlen(chunksize));
  +     }
  +     r = write(fb->fd, buf, nbyte);
  +     if ((r > 0) && (fb->flags & B_CHUNK))
  +     write(fb->fd, "\015\012", 2);
  +     return r;
  + }
  + 
  + /*
     * Write nbyte bytes.
     * Only returns fewer than nbyte if an error ocurred.
     * Returns -1 if no bytes were written before the error ocurred.
  ***************
  *** 425,431 ****
        if (!(fb->flags & B_WR))
        {
    /* unbuffered write */
  !     do i = write(fb->fd, buf, nbyte);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  --- 461,467 ----
        if (!(fb->flags & B_WR))
        {
    /* unbuffered write */
  !     do i = bcwrite(fb, buf, nbyte);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  ***************
  *** 458,464 ****
        }
    
    /* the buffer must be full */
  !     do i = write(fb->fd, fb->outbase, fb->bufsiz);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  --- 494,500 ----
        }
    
    /* the buffer must be full */
  !     do i = bcwrite(fb, fb->outbase, fb->bufsiz);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  ***************
  *** 494,500 ****
     */
        while (nbyte > fb->bufsiz)
        {
  !     do i = write(fb->fd, buf, nbyte);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  --- 530,536 ----
     */
        while (nbyte > fb->bufsiz)
        {
  !     do i = bcwrite(fb, buf, nbyte);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  ***************
  *** 540,546 ****
        {
    /* the buffer must be full */
        j = fb->outcnt;
  !     do i = write(fb->fd, fb->outbase, fb->outcnt);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  --- 576,582 ----
        {
    /* the buffer must be full */
        j = fb->outcnt;
  !     do i = bcwrite(fb, fb->outbase, fb->outcnt);
        while (i == -1 && errno == EINTR);
        if (i > 0) fb->bytes_sent += i;
        if (i == 0)
  
  
  
  1.5       +5 -0      apache/src/buff.h
  
  Index: buff.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/buff.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -C3 -r1.4 -r1.5
  *** buff.h    1996/05/27 21:08:27     1.4
  --- buff.h    1996/07/28 19:27:42     1.5
  ***************
  *** 66,71 ****
  --- 66,73 ----
    /* A write error has occurred */
    #define B_WRERR (32)
    #define B_ERROR (48)
  + /* Use chunked writing */
  + #define B_CHUNK (64)
    
    typedef struct buff_struct BUFF;
    
  ***************
  *** 98,104 ****
  --- 100,109 ----
    extern void bpushfd(BUFF *fb, int fd_in, int fd_out);
    extern int bsetopt(BUFF *fb, int optname, const void *optval);
    extern int bgetopt(BUFF *fb, int optname, void *optval);
  + extern int bsetflag(BUFF *fb, int flag, int value);
    extern int bclose(BUFF *fb);
  + 
  + #define bgetflag(fb, flag)  ((fb)->flags & (flag))
    
    /* Error handling */
    extern void bonerror(BUFF *fb, void (*error)(BUFF *, int, void *),
  
  
  
  1.9       +1 -1      apache/src/http_config.h
  
  Index: http_config.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_config.h,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -C3 -r1.8 -r1.9
  *** http_config.h     1996/07/27 13:08:28     1.8
  --- http_config.h     1996/07/28 19:27:43     1.9
  ***************
  *** 201,207 ****
     * handle it back-compatibly, or at least signal an error).
     */
    
  ! #define MODULE_MAGIC_NUMBER 19960526
    #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, __FILE__, NULL
    
    /* Generic accessors for other modules to get at their own module-specific
  --- 201,207 ----
     * handle it back-compatibly, or at least signal an error).
     */
    
  ! #define MODULE_MAGIC_NUMBER 19960725
    #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, __FILE__, NULL
    
    /* Generic accessors for other modules to get at their own module-specific
  
  
  
  1.25      +32 -11    apache/src/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_core.c,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -C3 -r1.24 -r1.25
  *** http_core.c       1996/07/27 23:00:06     1.24
  --- http_core.c       1996/07/28 19:27:43     1.25
  ***************
  *** 525,530 ****
  --- 525,531 ----
        else if(!strcasecmp(method,"POST")) limited |= (1 << M_POST);
        else if(!strcasecmp(method,"DELETE")) limited |= (1 << M_DELETE);
            else if(!strcasecmp(method,"CONNECT")) limited |= (1 << M_CONNECT);
  +     else if(!strcasecmp(method,"OPTIONS")) limited |= (1 << M_OPTIONS);
        else return "unknown method in <Limit>";
        }
    
  ***************
  *** 1063,1069 ****
        core_server_config *conf = get_module_config (sconf, &core_module);
      
        if (r->proxyreq) return NOT_IMPLEMENTED;
  !     if (r->uri[0] != '/') return BAD_REQUEST;
        
        if (r->server->path &&
        !strncmp(r->uri, r->server->path, r->server->pathlen))
  --- 1064,1070 ----
        core_server_config *conf = get_module_config (sconf, &core_module);
      
        if (r->proxyreq) return NOT_IMPLEMENTED;
  !     if ((r->uri[0] != '/') && strcmp(r->uri, "*")) return BAD_REQUEST;
        
        if (r->server->path &&
        !strncmp(r->uri, r->server->path, r->server->pathlen))
  ***************
  *** 1079,1105 ****
    
    /*
     * Default handler for MIME types without other handlers.  Only GET
  !  * at this point... anyone who wants to write a generic handler for
  !  * PUT or POST is free to do so, but it seems unwise to provide any
  !  * defaults yet...
     */
    
    int default_handler (request_rec *r)
    {
        core_dir_config *d =
          (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
  !     int errstatus;
        FILE *f;
        
  !     if (r->method_number != M_GET) return DECLINED;
    
        if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
        log_reason("File does not exist", r->filename, r);
        return NOT_FOUND;
        }
        
  !     if ((errstatus = set_content_length (r, r->finfo.st_size))
  !     || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
            return errstatus;
        
    #ifdef __EMX__
  --- 1080,1113 ----
    
    /*
     * Default handler for MIME types without other handlers.  Only GET
  !  * and OPTIONS at this point... anyone who wants to write a generic
  !  * handler for PUT or POST is free to do so, but it seems unwise to provide
  !  * any defaults yet... So, for now, we assume that this will always be
  !  * the last handler called and return 405 or 501.
     */
    
    int default_handler (request_rec *r)
    {
        core_dir_config *d =
          (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
  !     int rangestatus, errstatus;
        FILE *f;
        
  !     r->allowed |= (1 << M_GET);
  !     r->allowed |= (1 << M_TRACE);
  !     r->allowed |= (1 << M_OPTIONS);
  ! 
  !     if (r->method_number == M_INVALID) return NOT_IMPLEMENTED;
  !     if (r->method_number == M_OPTIONS) return send_http_options(r);
  !     if (r->method_number != M_GET) return METHOD_NOT_ALLOWED;
    
        if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
        log_reason("File does not exist", r->filename, r);
        return NOT_FOUND;
        }
        
  !     if ((errstatus = set_last_modified (r, r->finfo.st_mtime))
  !     || (errstatus = set_content_length (r, r->finfo.st_size)))
            return errstatus;
        
    #ifdef __EMX__
  ***************
  *** 1119,1128 ****
        }
    
        soft_timeout ("send", r);
  !     
        send_http_header (r);
  !     if (!r->header_only) send_fd (f, r);
  !     fclose (f);
        return OK;
    }
    
  --- 1127,1149 ----
        }
    
        soft_timeout ("send", r);
  ! 
  !     rangestatus = set_byterange(r);
        send_http_header (r);
  !     
  !     if (!r->header_only) {
  !     if (!rangestatus)
  !         send_fd (f, r);
  !     else {
  !         long offset, length;
  !         while (each_byterange(r, &offset, &length)) {
  !             fseek(f, offset, SEEK_SET);
  !             send_fd_length(f, r, length);
  !         }
  !     }
  !     }
  ! 
  !     fclose(f);
        return OK;
    }
    
  
  
  
  1.30      +484 -76   apache/src/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_protocol.c,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -C3 -r1.29 -r1.30
  *** http_protocol.c   1996/07/27 04:35:05     1.29
  --- http_protocol.c   1996/07/28 19:27:44     1.30
  ***************
  *** 1,4 ****
  ! 
    /* ====================================================================
     * Copyright (c) 1995 The Apache Group.  All rights reserved.
     *
  --- 1,4 ----
  !     
    /* ====================================================================
     * Copyright (c) 1995 The Apache Group.  All rights reserved.
     *
  ***************
  *** 50,57 ****
     * project, please see <http://www.apache.org/>.
     *
     */
  ! 
  ! 
    /*
     * http_protocol.c --- routines which directly communicate with the
     * client.
  --- 50,56 ----
     * project, please see <http://www.apache.org/>.
     *
     */
  !   
    /*
     * http_protocol.c --- routines which directly communicate with the
     * client.
  ***************
  *** 146,213 ****
        return 1;
    }
    
    
    int set_content_length (request_rec *r, long clength)
    {
        char ts[MAX_STRING_LEN];
  !     
        sprintf (ts, "%ld", clength);
  !     table_set (r->headers_out, "Content-length", pstrdup (r->pool, ts));
        return 0;
    }
    
    int set_keepalive(request_rec *r)
    {
  !   char *conn = table_get (r->headers_in, "Connection");
  !   char *length = table_get (r->headers_out, "Content-length");
    
  !   if (conn && length && !strncasecmp(conn, "Keep-Alive", 10) &&
  !       r->server->keep_alive_timeout &&
  !       (r->server->keep_alive > r->connection->keepalives)) {
  !     char header[26];
  !     int left = r->server->keep_alive - r->connection->keepalives;
  ! 
  !     r->connection->keepalive = 1;
  !     r->connection->keepalives++;
  !     sprintf(header, "timeout=%d, max=%d", r->server->keep_alive_timeout,
  !         left);
  !     table_set (r->headers_out, "Connection", "Keep-Alive");
  !     table_set (r->headers_out, "Keep-Alive", pstrdup(r->pool, header));
    
  !     return 1;
  !   }
    
  !       return 0;
    }
    
    int set_last_modified(request_rec *r, time_t mtime)
    {
  !     char *ts;
  !     char *if_modified_since = table_get (r->headers_in, 
"If-modified-since");
    
  !     /* Cacheing proxies use the absence of a Last-modified header
  !      * to indicate that a document is dynamic and shouldn't be cached.
  !      * For the moment, we enforce that here, though it would probably
  !      * work just as well to generate an Expires: header in send_http_header.
  !      *
  !      * However, even in that case, if no_cache is set, we would *not*
  !      * want to send USE_LOCAL_COPY, since the client isn't *supposed*
  !      * to have it cached.
         */
  !     
        if (r->no_cache) return OK;
  -     
  -     ts = gm_timestr_822(r->pool, mtime);
  -     table_set (r->headers_out, "Last-modified", ts);
    
        /* Check for conditional GETs --- note that we only want this check
         * to succeed if the GET was successful; ErrorDocuments *always* get 
sent.
         */
        
  !     if (r->status == 200 &&
  !     if_modified_since && later_than(gmtime(&mtime), if_modified_since))
  !       
            return USE_LOCAL_COPY;
        else
            return OK;
    }
  --- 145,380 ----
        return 1;
    }
    
  + static int parse_byterange (char *range, long clength, long *start, long 
*end)
  + {
  +     char *dash = strchr(range, '-');
  + 
  +     if (!dash)
  +     return 0;
  + 
  +     if ((dash == range)) {
  +     /* In the form "-5" */
  +     *start = clength - atol(dash + 1);
  +     *end = clength - 1;
  +     }
  +     else {
  +     *dash = '\0';
  +     dash++;
  +     *start = atol(range);
  +     if (*dash)
  +         *end = atol(dash);
  +     else    /* "5-" */
  +         *end = clength -1;
  +     }
  + 
  +     if (*start > *end)
  +     return 0;
  + 
  +     if (*end >= clength)
  +     *end = clength - 1;
  + 
  +     return 1;
  + }
  + 
  + /* This is a string I made up. Pounded on the keyboard a couple of times.
  +  * It's a good a way as any, I suppose, if you can't parse the document
  +  * beforehand (which we can't).
  +  */
  + 
  + #define BYTERANGE_BOUNDARY "13962mx38v144c9999AQdk39d2Klmx79"
  + 
  + int set_byterange (request_rec *r)
  + {
  +     char *range = table_get (r->headers_in, "Range");
  +     char *if_range = table_get (r->headers_in, "If-Range");
  +     char ts[MAX_STRING_LEN], *match;
  +     long range_start, range_end;
  + 
  +     /* Reasons we won't do ranges... */
  + 
  +     if (!r->clength || r->assbackwards) return 0;
  +     if (!range || strncmp(range, "bytes=", 6)) {
  +     table_set (r->headers_out, "Accept-Ranges", "bytes");
  +     return 0;
  +     }
  + 
  +     /* Check the If-Range header. Golly, this is a long if statement */
  + 
  +     if (if_range
  +     && !((if_range[0] == '"') /* an entity tag */
  +          && (match = table_get(r->headers_out, "Etag"))
  +          && (match[0] == '"') && !strcasecmp(if_range, match))
  +     && !((if_range[0] != '"') /* a date */
  +          && (match = table_get(r->headers_out, "Last-Modified"))
  +          && (!strcasecmp(if_range, match))))
  +     return 0;
  +     
  +     if (!strchr(range, ',')) {
  +     /* A single range */
  +     if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength,
  +                          &range_start, &range_end))
  +         return 0;
  + 
  +     r->byterange = 1;
  + 
  +     sprintf(ts, "bytes %ld-%ld/%ld", range_start, range_end,
  +             r->clength);
  +     table_set(r->headers_out, "Content-Range",
  +               pstrdup(r->pool, ts));
  +     sprintf(ts, "%ld", range_end - range_start + 1);
  +     table_set(r->headers_out, "Content-Length", ts);
  +     }
  +     else {
  +     /* a multiple range */
  +     r->byterange = 2;
  +     table_unset(r->headers_out, "Content-Length");
  +     }
  +     
  +     r->status = PARTIAL_CONTENT;
  +     r->range = range + 6;
  + 
  +     return 1;
  + }
  + 
  + int each_byterange (request_rec *r, long *offset, long *length) {
  +     long range_start, range_end;
  +     char *range;
  + 
  +     if (!*r->range) {
  +     if (r->byterange > 1)
  +         rvputs(r, "\015\012--", BYTERANGE_BOUNDARY, "--\015\012", NULL);
  +     return 0;
  +     }
  + 
  +     range = getword(r->pool, &r->range, ',');
  +     if (!parse_byterange(range, r->clength, &range_start, &range_end))
  +     return each_byterange(r, offset, length);       /* Skip this one */
  + 
  +     if (r->byterange > 1) {
  +     char *ct = r->content_type ? r->content_type : default_type(r);
  +     char ts[MAX_STRING_LEN];
  + 
  +     sprintf(ts, "%ld-%ld/%ld", range_start, range_end, r->clength);
  +     rvputs(r, "\015\012--", BYTERANGE_BOUNDARY, "\015\012Content-type: ",
  +            ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
  +            NULL);
  +     }
  + 
  +     *offset = range_start;
  +     *length = range_end - range_start + 1;
  +     return 1;
  + }
    
    int set_content_length (request_rec *r, long clength)
    {
        char ts[MAX_STRING_LEN];
  ! 
  !     r->clength = clength;
  ! 
        sprintf (ts, "%ld", clength);
  !     table_set (r->headers_out, "Content-Length", pstrdup (r->pool, ts));
  ! 
        return 0;
    }
    
    int set_keepalive(request_rec *r)
    {
  !     char *conn = table_get (r->headers_in, "Connection");
  !     char *length = table_get (r->headers_out, "Content-length");
    
  ! #ifdef FORHTTP11
  !     if ((((r->proto_num >= 1001) && (!find_token(r->pool, conn, "close")))
  !      || (find_token(r->pool, conn, "keep-alive")))
  ! #else
  !     if ((find_token(r->pool, conn, "keep-alive"))
  ! #endif
  !     && (r->header_only || length ||
  !         ((r->proto_num >= 1001) && (r->byterange > 1 || (r->chunked = 1))))
  !     && (r->server->keep_alive_timeout &&
  !         (r->server->keep_alive > r->connection->keepalives))) {
  !     char header[26];
  !     int left = r->server->keep_alive - r->connection->keepalives;
  !     
  !     r->connection->keepalive = 1;
  !     r->connection->keepalives++;
  !     
  ! #ifdef FORHTTP11
  !     if (r->proto_num < 1001) {
  ! #endif
  !         sprintf(header, "timeout=%d, max=%d",
  !                 r->server->keep_alive_timeout, left);
  !         table_set (r->headers_out, "Connection", "Keep-Alive");
  !         table_set (r->headers_out, "Keep-Alive", pstrdup(r->pool, header));
  ! #ifdef FORHTTP11
  !     }
  ! #endif      
    
  !     return 1;
  !     }
  ! 
  !     /* We only really need to send this to HTTP/1.1 clients, but we
  !      * always send it anyway, because a broken proxy may identify itself
  !      * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
  !      * to a HTTP/1.1 client. Better safe than sorry.
  !      */
  !     table_set (r->headers_out, "Connection", "close");
    
  !     return 0;
    }
    
    int set_last_modified(request_rec *r, time_t mtime)
    {
  !     char *ts, etag[MAX_STRING_LEN];
  !     char *if_modified_since = table_get (r->headers_in, 
"If-Modified-Since");
  !     char *if_unmodified = table_get (r->headers_in, "If-Unmodified-Since");
  !     char *if_nonematch = table_get (r->headers_in, "If-None-Match");
  !     char *if_match = table_get (r->headers_in, "If-Match");
  ! 
  !     /* Invalid, future time... just ignore it */
  !     if (mtime > r->request_time) return OK;
    
  !     ts = gm_timestr_822(r->pool, mtime);
  !     table_set (r->headers_out, "Last-Modified", ts);
  ! 
  !     /* Make an ETag header out of various peices of information. We use
  !      * the last-modified date and, if we have a real file, the
  !      * length and inode number - note that this doesn't have to match
  !      * the content-length (i.e. includes), it just has to be unique
  !      * for the file.
         */
  ! 
  !     if (r->finfo.st_mode != 0)
  !         sprintf(etag, "\"%lx-%lx-%lx\"", r->finfo.st_ino, r->finfo.st_size,
  !             mtime);
  !     else
  !         sprintf(etag, "\"%lx\"", mtime);
  !     table_set (r->headers_out, "ETag", etag);
  ! 
  !     /* We now do the no_cache stuff using an Expires: header (we used to
  !      * withhold Last-modified). However, we still want to enforce this by
  !      * not allowing conditional GETs.
  !      */
  ! 
        if (r->no_cache) return OK;
    
        /* Check for conditional GETs --- note that we only want this check
         * to succeed if the GET was successful; ErrorDocuments *always* get 
sent.
         */
        
  !     if ((r->status < 200) || (r->status >= 300))
  !         return OK;
  ! 
  !     if (if_modified_since && later_than(gmtime(&mtime), if_modified_since))
            return USE_LOCAL_COPY;
  +     else if (if_unmodified && !later_than(gmtime(&mtime), if_unmodified))
  +         return PRECONDITION_FAILED;
  +     else if (if_nonematch && ((if_nonematch[0] == '*') ||
  +                           find_token(r->pool, if_nonematch, etag)))
  +         return (r->method_number == M_GET) ?
  +         USE_LOCAL_COPY : PRECONDITION_FAILED;
  +     else if (if_match && !((if_match[0] == '*') ||
  +                        find_token(r->pool, if_match, etag)))
  +         return PRECONDITION_FAILED;
        else
            return OK;
    }
  ***************
  *** 231,245 ****
    void parse_uri (request_rec *r, char *uri)
    {
        const char *s;
  -     /* If we ever want to do byte-ranges a la Netscape & Franks,
  -      * this is the place to parse them; with proper support in
  -      * rprintf and rputc, and the sub-request setup and finalizers
  -      * here, it'll all just work, even for vile cases like
  -      * inclusion of byte-ranges of the output of CGI scripts, with
  -      * the client requesting only a byte-range of *that*!
  -      *
  -      * But for now...
  -      */
    
    #ifdef __EMX__
        /* Variable for OS/2 fix below. */
  --- 398,403 ----
  ***************
  *** 255,262 ****
        r->proxyreq = 1;
        r->uri = uri;
        r->args = NULL;
  !     } else
  !     {
        r->proxyreq = 0;
        r->uri = getword (r->pool, &uri, '?');
    
  --- 413,425 ----
        r->proxyreq = 1;
        r->uri = uri;
        r->args = NULL;
  !     }
  !     else if (r->method && !strcmp(r->method, "TRACE")) {
  !     r->proxyreq = 0;
  !     r->uri = uri;
  !     r->args = NULL;
  !     }
  !     else {
        r->proxyreq = 0;
        r->uri = getword (r->pool, &uri, '?');
    
  ***************
  *** 373,379 ****
    
    void check_hostalias (request_rec *r) {
      char *host = getword(r->pool, &r->hostname, ':'); /* Get rid of port */
  !   int port = (*r->hostname) ? atoi(r->hostname) : 0;
      server_rec *s;
    
      if (port && (port != r->server->port))
  --- 536,542 ----
    
    void check_hostalias (request_rec *r) {
      char *host = getword(r->pool, &r->hostname, ':'); /* Get rid of port */
  !   int port = (*r->hostname) ? atoi(r->hostname) : 80;
      server_rec *s;
    
      if (port && (port != r->server->port))
  ***************
  *** 388,395 ****
      for (s = r->server->next; s; s = s->next) {
        char *names = s->names;
        
  !     if ((!strcasecmp(host, s->server_hostname)) &&
  !     (!port || (port == s->port))) {
          r->server = r->connection->server = s;
          if (r->hostlen && !strncmp(r->uri, "http://";, 7)) {
        r->uri += r->hostlen;
  --- 551,557 ----
      for (s = r->server->next; s; s = s->next) {
        char *names = s->names;
        
  !     if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) {
          r->server = r->connection->server = s;
          if (r->hostlen && !strncmp(r->uri, "http://";, 7)) {
        r->uri += r->hostlen;
  ***************
  *** 431,436 ****
  --- 593,600 ----
    request_rec *read_request (conn_rec *conn)
    {
        request_rec *r = (request_rec *)pcalloc (conn->pool, 
sizeof(request_rec));
  + 
  +     r->request_time = time(NULL);
      
        r->connection = conn;
        r->server = conn->server;
  ***************
  *** 462,468 ****
        
        hard_timeout ("read", r);
        if (!read_request_line (r)) return NULL;
  !     if (!r->assbackwards) get_mime_headers(r);
    
    /* handle Host header here, to get virtual server */
    
  --- 626,632 ----
        
        hard_timeout ("read", r);
        if (!read_request_line (r)) return NULL;
  !     if (!r->assbackwards) get_mime_headers (r);
    
    /* handle Host header here, to get virtual server */
    
  ***************
  *** 488,493 ****
  --- 652,661 ----
            r->method_number = M_DELETE;
        else if(!strcmp(r->method,"CONNECT"))
            r->method_number = M_CONNECT;
  +     else if(!strcmp(r->method,"OPTIONS"))
  +         r->method_number = M_OPTIONS;
  +     else if(!strcmp(r->method,"TRACE"))
  +         r->method_number = M_TRACE;
        else 
            r->method_number = M_INVALID; /* Will eventually croak. */
    
  ***************
  *** 550,556 ****
    {
        char nonce[10];
    
  !     sprintf(nonce, "%lu", time(NULL));
        table_set (r->err_headers_out, "WWW-Authenticate",
                   pstrcat(r->pool, "Digest realm=\"", auth_name(r),
                           "\", nonce=\"", nonce, "\"", NULL));
  --- 718,724 ----
    {
        char nonce[10];
    
  !     sprintf(nonce, "%lu", r->request_time);
        table_set (r->err_headers_out, "WWW-Authenticate",
                   pstrcat(r->pool, "Digest realm=\"", auth_name(r),
                           "\", nonce=\"", nonce, "\"", NULL));
  ***************
  *** 590,596 ****
        return OK;
    }
    
  ! #define RESPONSE_CODE_LIST " 200 302 304 400 401 403 404 500 503 501 502 "
    
    /* New Apache routine to map error responses into array indicies 
     *  e.g.  400 -> 0,  500 -> 1,  502 -> 2 ...                     
  --- 758,764 ----
        return OK;
    }
    
  ! #define RESPONSE_CODE_LIST " 200 206 301 302 304 400 401 403 404 405 411 
412 500 503 501 502 "
    
    /* New Apache routine to map error responses into array indicies 
     *  e.g.  400 -> 0,  500 -> 1,  502 -> 2 ...                     
  ***************
  *** 599,610 ****
  --- 767,783 ----
    
    char *status_lines[] = {
       "200 OK",
  +    "206 Partial Content",
  +    "301 Moved Permanently",
       "302 Found",
       "304 Not Modified",
       "400 Bad Request",
       "401 Unauthorized",
       "403 Forbidden",
       "404 Not found",
  +    "405 Method Not Allowed",
  +    "411 Length Required",
  +    "412 Precondition Failed",
       "500 Server error",
       "503 Out of resources",
       "501 Not Implemented",
  ***************
  *** 613,624 ****
  --- 786,802 ----
    
    char *response_titles[] = {
       "200 OK",                        /* Never actually sent, barring 
die(200,...) */
  +    "206 Partial Content",   /* Never sent as an error (we hope) */
  +    "Document moved",                /* 301 Redirect */
       "Document moved",                /* 302 Redirect */
       "304 Not Modified",              /* Never sent... 304 MUST be header 
only */
       "Bad Request",
       "Authorization Required",
       "Forbidden",
       "File Not found",
  +    "Method Not Allowed",
  +    "Length Required",
  +    "Precondition Failed",
       "Server Error",
       "Out of resources",
       "Method not implemented",
  ***************
  *** 654,660 ****
            r->status_line = status_lines[index_of_response(r->status)];
        
        bvputs(fd, SERVER_PROTOCOL, " ", r->status_line, "\015\012", NULL);
  !     bvputs(fd,"Date: ",gm_timestr_822 (r->pool, time(NULL)), "\015\012", 
NULL);
        bvputs(fd,"Server: ", SERVER_VERSION, "\015\012", NULL);
    }
    
  --- 832,839 ----
            r->status_line = status_lines[index_of_response(r->status)];
        
        bvputs(fd, SERVER_PROTOCOL, " ", r->status_line, "\015\012", NULL);
  !     bvputs(fd,"Date: ",gm_timestr_822 (r->pool, r->request_time),
  !        "\015\012", NULL);
        bvputs(fd,"Server: ", SERVER_VERSION, "\015\012", NULL);
    }
    
  ***************
  *** 683,688 ****
  --- 862,928 ----
    #endif
    }
    
  + char *make_allow(request_rec *r)
  + {
  +     int allowed = r->allowed;
  + 
  +     return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET" : "",
  +                    (allowed & (1 << M_POST)) ? ", POST" : "",
  +                    (allowed & (1 << M_PUT)) ? ", PUT" : "",
  +                    (allowed & (1 << M_DELETE)) ? ", DELETE" : "",
  +                    (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
  +                    (allowed & (1 << M_TRACE)) ? ", TRACE" : "",
  +                    NULL);
  +     
  + }
  + 
  + int send_http_trace (request_rec *r)
  + {
  +     array_header *hdrs_arr = table_elts(r->headers_in);
  +     table_entry *hdrs = (table_entry *)hdrs_arr->elts;
  +     int i;
  + 
  +     /* Get the original request */
  +     while (r->prev) r = r->prev;
  + 
  +     soft_timeout ("send", r);
  + 
  +     r->content_type = "message/http";
  +     send_http_header(r);
  +     
  +     /* Now we recreate the request, and echo it back */
  + 
  +     rvputs(r, r->method, " ", r->uri, " ", r->protocol, "\015\012", NULL);
  + 
  +     for (i = 0; i < hdrs_arr->nelts; ++i) {
  +       if (!hdrs[i].key) continue;
  +       rvputs(r, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
  +     }
  + 
  +     kill_timeout(r);
  +     return OK;
  + }
  + 
  + int send_http_options(request_rec *r)
  + {
  +     BUFF *fd = r->connection->client;
  +     const long int zero=0L;
  + 
  +     if (r->assbackwards) return DECLINED;
  + 
  +     soft_timeout ("send", r);
  + 
  +     basic_http_header(r);
  +     bputs("Connection: close\015\012", fd);
  +     bvputs(fd, "Allow: ", make_allow(r), "\015\012", NULL);
  +     bputs("\015\012", fd);
  + 
  +     bsetopt(fd, BO_BYTECT, &zero);
  +     kill_timeout (r);
  + 
  +     return OK;
  + }
  + 
    void send_http_header(request_rec *r)
    {
        conn_rec *c = r->connection;
  ***************
  *** 705,727 ****
        basic_http_header (r);
    
        set_keepalive (r);
  !     
  !     if (r->content_type)
  !         bvputs(fd, "Content-type: ", 
                 nuke_mime_parms (r->pool, r->content_type), "\015\012", NULL);
  !     else if(default_type)
  !         bvputs(fd, "Content-type: ", default_type, "\015\012", NULL);
        
        if (r->content_encoding)
  !         bvputs(fd,"Content-encoding: ", r->content_encoding, "\015\012", 
NULL);
        
        if (r->content_language)
  !         bvputs(fd,"Content-language: ", r->content_language, "\015\012", 
NULL);
  !     
        hdrs_arr = table_elts(r->headers_out);
        hdrs = (table_entry *)hdrs_arr->elts;
        for (i = 0; i < hdrs_arr->nelts; ++i) {
            if (!hdrs[i].key) continue;
        bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
        }
    
  --- 945,989 ----
        basic_http_header (r);
    
        set_keepalive (r);
  ! 
  !     if (r->chunked)
  !     bputs("Transfer-Encoding: chunked\015\012", fd);
  ! 
  !     if (r->byterange > 1)
  !         bvputs(fd, "Content-Type: multipart/byteranges; boundary=",
  !            BYTERANGE_BOUNDARY, "\015\012", NULL);
  !     else if (r->content_type)
  !         bvputs(fd, "Content-Type: ", 
                 nuke_mime_parms (r->pool, r->content_type), "\015\012", NULL);
  !     else if (default_type)
  !         bvputs(fd, "Content-Type: ", default_type, "\015\012", NULL);
        
        if (r->content_encoding)
  !         bvputs(fd,"Content-Encoding: ", r->content_encoding, "\015\012", 
NULL);
        
        if (r->content_language)
  !         bvputs(fd,"Content-Language: ", r->content_language, "\015\012", 
NULL);
  ! 
  !     /* If it's a TRACE, or if they sent us Via:, send one back */
  !     if ((r->method_number == M_TRACE) || table_get(r->headers_in, "Via"))
  !         bvputs(fd, "Via: ",
  !     SERVER_PROTOCOL + (!strncmp(SERVER_PROTOCOL, "HTTP/", 5) ? 5 : 0), " ",
  !     construct_server(r->pool, r->server->server_hostname, r->server->port),
  !            " (", SERVER_VERSION, ")\015\012", NULL);
  !     
  !     /* We now worry about this here */
  ! 
  !     if (r->no_cache && (r->proto_num >= 1001))
  !         bputs ("Cache-Control: private\015\012", fd);
  !     else if (r->no_cache)
  !         bvputs(fd,"Expires: ", gm_timestr_822(r->pool, r->request_time),
  !            "\015\012", NULL);
  ! 
        hdrs_arr = table_elts(r->headers_out);
        hdrs = (table_entry *)hdrs_arr->elts;
        for (i = 0; i < hdrs_arr->nelts; ++i) {
            if (!hdrs[i].key) continue;
  +     if (r->no_cache && !strcasecmp(hdrs[i].key, "Expires")) continue;
        bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
        }
    
  ***************
  *** 729,761 ****
        hdrs = (table_entry *)hdrs_arr->elts;
        for (i = 0; i < hdrs_arr->nelts; ++i) {
            if (!hdrs[i].key) continue;
        bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
        }
    
        bputs("\015\012",fd);
    
        if (c->keepalive)
  !     bflush(r->connection->client);  /* For bugs in Netscape, perhaps */
    
        bsetopt(fd, BO_BYTECT, &zero);
        r->sent_bodyct = 1;             /* Whatever follows is real body 
stuff... */
    }
    
    long read_client_block (request_rec *r, char *buffer, int bufsiz)
    {
  !     return bread(r->connection->client, buffer, bufsiz);
    }
    
  ! long send_fd(FILE *f, request_rec *r)
    {
        char buf[IOBUFSIZE];
        long total_bytes_sent;
  !     register int n,o,w;
        conn_rec *c = r->connection;
        
        total_bytes_sent = 0;
        while (!r->connection->aborted) {
  !         while ((n= fread(buf, sizeof(char), IOBUFSIZE, f)) < 1
               && ferror(f) && errno == EINTR)
            continue;
        
  --- 991,1134 ----
        hdrs = (table_entry *)hdrs_arr->elts;
        for (i = 0; i < hdrs_arr->nelts; ++i) {
            if (!hdrs[i].key) continue;
  +     if (r->no_cache && !strcasecmp(hdrs[i].key, "Expires")) continue;
        bvputs(fd, hdrs[i].key, ": ", hdrs[i].val, "\015\012", NULL);
        }
    
        bputs("\015\012",fd);
    
        if (c->keepalive)
  !     bflush(fd);  /* This is to work around a Netscape bug */
    
        bsetopt(fd, BO_BYTECT, &zero);
        r->sent_bodyct = 1;             /* Whatever follows is real body 
stuff... */
  + 
  +     /* Set buffer flags for the body */
  +     if (r->chunked) bsetflag(fd, B_CHUNK, 1);
  + }
  + 
  + void finalize_request_protocol (request_rec *r) {
  +     BUFF *fd = r->connection->client;
  + 
  +     /* Turn off chunked encoding */
  + 
  +     if (r->chunked) {
  +         bsetflag(fd, B_CHUNK, 0);
  +     bputs("0\015\012", fd);
  +     /* If we had footer "headers", we'd send them now */
  +     bputs("\015\012", fd);
  +     }
  + 
  + }
  + 
  + int setup_client_block (request_rec *r)
  + {
  +     char *tenc = table_get (r->headers_in, "Transfer-Encoding");
  +     char *lenp = table_get (r->headers_in, "Content-length");
  + 
  +     if ((r->method_number != M_POST) && (r->method_number != M_PUT))
  +     return OK;
  + 
  +     if (tenc) {
  +     if (strcasecmp(tenc, "chunked")) {
  +         log_printf(r->server, "Unknown Transfer-Encoding %s", tenc);
  +         return BAD_REQUEST;
  +     }
  +     r->read_chunked = 1;
  +     }
  +     else {
  +     if (!lenp) {
  +         log_reason("POST or PUT without Content-length:", r->filename, r);
  +         return LENGTH_REQUIRED;
  +     }
  +     r->remaining = atol(lenp);
  +     }
  + 
  +     return OK;
  + }
  + 
  + int should_client_block (request_rec *r) {
  +     return (r->method_number == M_POST || r->method_number == M_PUT);
  + }
  + 
  + static int rd_chunk_size (BUFF *b) {
  +     int chunksize = 0;
  +     int c;
  + 
  +     while ((c = bgetc (b)) != EOF && isxdigit (c)) {
  +         int xvalue;
  + 
  +         if (c >= '0' && c <= '9') xvalue = c - '0';
  +         else if (c >= 'A' && c <= 'F') xvalue = c - 'A' + 0xa;
  +         else if (c >= 'a' && c <= 'f') xvalue = c - 'a' + 0xa;
  + 
  +         chunksize = (chunksize << 4) | xvalue;
  +     }
  + 
  +     /* Skip to end of line, bypassing chunk options, if present */
  + 
  +     while (c != '\n' && c != EOF)
  +         c = bgetc (b);
  + 
  +     return (c == EOF) ? -1 : chunksize;
    }
    
    long read_client_block (request_rec *r, char *buffer, int bufsiz)
    {
  !     long c, len_read, len_to_read = r->remaining;
  ! 
  !     if (!r->read_chunked) { /* Content-length read */
  !     if (len_to_read >= bufsiz)
  !         len_to_read = bufsiz - 1;
  !     len_read = bread(r->connection->client, buffer, len_to_read);
  !     r->remaining -= len_read;
  !     return len_read;
  !     }
  ! 
  !     /* Handle chunked reading */
  !     if (len_to_read == 0) {
  !     len_to_read = rd_chunk_size(r->connection->client);
  !     if (len_to_read == 0) {
  !         /* Skip over any "footers" */
  !         do c = bgets(buffer, bufsiz, r->connection->client);
  !         while ((c > 0) && (*buffer != '\015') && (*buffer != '\012'));
  !         return 0;
  !     }
  !     }
  !     if (len_to_read >= bufsiz) {
  !     r->remaining = len_to_read - bufsiz - 1;
  !     len_to_read = bufsiz - 1;
  !     }
  !     else
  !     r->remaining = 0;
  !     
  !     len_read = bread(r->connection->client, buffer, len_to_read);
  !     if (r->remaining == 0) {
  !     do c = bgetc (r->connection->client);
  !     while (c != '\n' && c != EOF);
  !     }
  ! 
  !     return len_read;
    }
    
  ! long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
  ! 
  ! long send_fd_length(FILE *f, request_rec *r, long length)
    {
        char buf[IOBUFSIZE];
        long total_bytes_sent;
  !     register int n, w, o, len;
        conn_rec *c = r->connection;
        
  +     if (length == 0) return 0;
  + 
        total_bytes_sent = 0;
        while (!r->connection->aborted) {
  !     if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
  !         len = length - total_bytes_sent;
  !     else len = IOBUFSIZE;
  ! 
  !         while ((n= fread(buf, sizeof(char), len, f)) < 1
               && ferror(f) && errno == EINTR)
            continue;
        
  ***************
  *** 771,780 ****
                break;
            reset_timeout(r); /* reset timeout after successfule write */
                n-=w;
  !             o+=w;
            }
        }
  !     bflush(c->client);
        
        SET_BYTES_SENT(r);
        return total_bytes_sent;
  --- 1144,1154 ----
                break;
            reset_timeout(r); /* reset timeout after successfule write */
                n-=w;
  !         o+=w;
            }
        }
  ! 
  !     if (length > 0) bflush(c->client);
        
        SET_BYTES_SENT(r);
        return total_bytes_sent;
  ***************
  *** 860,873 ****
         */
        
        if (status == USE_LOCAL_COPY) {
  !         if (set_keepalive(r))
  !             bputs("Connection: Keep-Alive\015\012", c->client);
            bputs("\015\012", c->client);
            return;
        }
        
  !     if (status == REDIRECT)
            bvputs(c->client, "Location: ", location, "\015\012", NULL);
        
        for (i = 0; i < err_hdrs_arr->nelts; ++i) {
            if (!err_hdrs[i].key) continue;
  --- 1234,1266 ----
         */
        
        if (status == USE_LOCAL_COPY) {
  !         char *etag = table_get(r->headers_out, "ETag");
  !         char *cloc = table_get(r->headers_out, "Content-Location");
  !         if (etag) bvputs(c->client, "ETag: ", etag, "\015\012", NULL);
  !         if (cloc) bvputs(c->client, "Content-Location: ", cloc,
  !                          "\015\012", NULL);
  !         if (set_keepalive(r)) {
  ! #ifdef FORHTTP11
  !             if (r->proto_num < 1001)
  ! #endif
  !                 bputs("Connection: Keep-Alive\015\012", c->client);
  !         }
  !         else bputs("Connection: close", c->client);
            bputs("\015\012", c->client);
            return;
        }
  + 
  +     /* We don't want persistent connections here, for several reasons.
  +      * Most importantly, if there's been an error, we don't want
  +      * it screwing up the next request.
  +      */
  +     bputs("Connection: close\015\012", c->client);
        
  !     if ((status == REDIRECT) || (status == MOVED))
            bvputs(c->client, "Location: ", location, "\015\012", NULL);
  + 
  +     if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
  +         bvputs(c->client, "Allow: ", make_allow(r), "\015\012", NULL);
        
        for (i = 0; i < err_hdrs_arr->nelts; ++i) {
            if (!err_hdrs[i].key) continue;
  ***************
  *** 911,916 ****
  --- 1304,1310 ----
        
            switch (r->status) {
        case REDIRECT:
  +     case MOVED:
            bvputs(fd, "The document has moved <A HREF=\"",
                    escape_html(r->pool, location), "\">here</A>.<P>\n", NULL);
            break;
  ***************
  *** 932,939 ****
                   NULL);
            break;
        case NOT_FOUND:
  !          bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri),
                    " was not found on this server.<P>\n", NULL);
            break;
        case SERVER_ERROR:
            bputs("The server encountered an internal error or\n", fd);
  --- 1326,1347 ----
                   NULL);
            break;
        case NOT_FOUND:
  !         bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri),
                    " was not found on this server.<P>\n", NULL);
  +         break;
  +     case METHOD_NOT_ALLOWED:
  +         bvputs(fd, "The requested method ", r->method, " is not allowed "
  +                "for the URL ", escape_html(r->pool, r->uri),
  +                ".<P>\n", NULL);
  +         break;
  +     case LENGTH_REQUIRED:
  +         bvputs(fd, "A request of the requested method ", r->method,
  +                " requires a valid Content-length.<P>\n", NULL);
  +         break;
  +     case PRECONDITION_FAILED:
  +         bvputs(fd, "The requested precondition for serving the URL ",
  +                escape_html(r->pool, r->uri), " evaluated to false.<P>\n",
  +                NULL);
            break;
        case SERVER_ERROR:
            bputs("The server encountered an internal error or\n", fd);
  
  
  
  1.7       +17 -0     apache/src/http_protocol.h
  
  Index: http_protocol.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_protocol.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -C3 -r1.6 -r1.7
  *** http_protocol.h   1996/05/27 21:08:28     1.6
  --- http_protocol.h   1996/07/28 19:27:45     1.7
  ***************
  *** 64,69 ****
  --- 64,78 ----
    /* Send header for http response */
    
    void send_http_header (request_rec *l);     
  + 
  + /* Send the response to special method requests */
  + 
  + int send_http_trace (request_rec *r);
  + int send_http_options (request_rec *r);
  + 
  + /* Finish up stuff after a request */
  + 
  + void finalize_request_protocol (request_rec *r);
         
    /* Send error back to client... last arg indicates error status in case
     * we get an error in the process of trying to deal with an ErrorDocument
  ***************
  *** 99,104 ****
  --- 108,114 ----
     */
    
    long send_fd(FILE *f, request_rec *r);
  + long send_fd_length(FILE *f, request_rec *r, long length);
         
    /* Hmmm... could macrofy these for now, and maybe forever, though the
     * definitions of the macros would get a whole lot hairier.
  ***************
  *** 121,127 ****
  --- 131,144 ----
    
    /* Reading a block of data from the client connection (e.g., POST arg) */
         
  + int setup_client_block (request_rec *r);
  + int should_client_block (request_rec *r);
    long read_client_block (request_rec *r, char *buffer, int bufsiz);
  + 
  + /* Sending a byterange */
  + 
  + int set_byterange (request_rec *r);
  + int each_byterange (request_rec *r, long *offset, long *length);
         
    /* Finally, this charming little number is here to encapsulate the
     * degree to which nph- scripts completely escape from any discipline
  
  
  
  1.13      +17 -2     apache/src/http_request.c
  
  Index: http_request.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_request.c,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -C3 -r1.12 -r1.13
  *** http_request.c    1996/07/25 19:32:29     1.12
  --- http_request.c    1996/07/28 19:27:45     1.13
  ***************
  *** 782,788 ****
        return;
        }
    
  !     if (!r->hostname && (r->proto_num >= 1001)) {
            /* Client sent us a HTTP/1.1 or later request without telling
         * us the hostname, either with a full URL or a Host: header.
         * We therefore need to (as per the 1.1 spec) send an error
  --- 782,789 ----
        return;
        }
    
  !     if ((!r->hostname && (r->proto_num >= 1001)) ||
  !     ((r->proto_num == 1001) && !table_get(r->headers_in, "Host"))) {
            /* Client sent us a HTTP/1.1 or later request without telling
         * us the hostname, either with a full URL or a Host: header.
         * We therefore need to (as per the 1.1 spec) send an error
  ***************
  *** 852,859 ****
        return;
        }
    
  !     if ((access_status = invoke_handler (r)) != 0)
            die (access_status, r);
    }
    
    void process_request (request_rec *r)
  --- 853,869 ----
        return;
        }
    
  !     /* We don't want TRACE to run through the normal handler set,
  !      * we handle it specially.
  !      */
  !     if (r->method_number == M_TRACE) send_http_trace (r);
  !     else if ((access_status = invoke_handler (r)) != 0) {
            die (access_status, r);
  +     return;
  +     }
  + 
  +    /* Take care of little things that need to happen when we're done */
  +    finalize_request_protocol (r);
    }
    
    void process_request (request_rec *r)
  ***************
  *** 913,923 ****
  --- 923,938 ----
    
        new->method = r->method;
        new->method_number = r->method_number;
  +     new->allowed = r->allowed;
        
        new->status = r->status;
        new->assbackwards = r->assbackwards;
        new->header_only = r->header_only;
        new->protocol = r->protocol;
  +     new->proto_num = r->proto_num;
  +     new->hostname = r->hostname;
  +     new->hostlen = r->hostlen;
  +     new->request_time = r->request_time;
        new->main = r->main;
    
        new->headers_in = r->headers_in;
  
  
  
  1.40      +26 -6     apache/src/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/httpd.h,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -C3 -r1.39 -r1.40
  *** httpd.h   1996/07/25 19:49:02     1.39
  --- httpd.h   1996/07/28 19:27:46     1.40
  ***************
  *** 226,232 ****
    #define DEFAULT_MAX_REQUESTS_PER_CHILD 0
    
    /* If you have altered Apache and wish to change the SERVER_VERSION define
  !  * below, please keep to the HTTP/1.0 specification.  This states that
     * the identification string should consist of product tokens with an 
optional
     * slash and version designator.  Sub-products which form a significant 
part 
     * of the application can be listed, separated by whitespace.  The tokens
  --- 226,232 ----
    #define DEFAULT_MAX_REQUESTS_PER_CHILD 0
    
    /* If you have altered Apache and wish to change the SERVER_VERSION define
  !  * below, please keep to the HTTP specification.  This states that
     * the identification string should consist of product tokens with an 
optional
     * slash and version designator.  Sub-products which form a significant 
part 
     * of the application can be listed, separated by whitespace.  The tokens
  ***************
  *** 235,241 ****
     * "Product tokens should be short and to the point -- use of them for 
     * advertizing or other non-essential information is explicitly forbidden."
     *
  !  * Example: "Apache/1.1b3 MrWidget/0.1-alpha" 
     */
    
    #define SERVER_VERSION "Apache/1.2-dev" /* SEE COMMENTS ABOVE */
  --- 235,241 ----
     * "Product tokens should be short and to the point -- use of them for 
     * advertizing or other non-essential information is explicitly forbidden."
     *
  !  * Example: "Apache/1.1.0 MrWidget/0.1-alpha" 
     */
    
    #define SERVER_VERSION "Apache/1.2-dev" /* SEE COMMENTS ABOVE */
  ***************
  *** 249,273 ****
    /* ------------------------------ error types 
------------------------------ */
    
    #define DOCUMENT_FOLLOWS 200
    #define REDIRECT 302
    #define USE_LOCAL_COPY 304
    #define BAD_REQUEST 400
    #define AUTH_REQUIRED 401
    #define FORBIDDEN 403
    #define NOT_FOUND 404
    #define SERVER_ERROR 500
    #define NOT_IMPLEMENTED 501
    #define BAD_GATEWAY 502
    #define HTTP_SERVICE_UNAVAILABLE 503
  ! #define RESPONSE_CODES 10
    
  ! #define METHODS 6
    #define M_GET 0
    #define M_PUT 1
    #define M_POST 2
    #define M_DELETE 3
    #define M_CONNECT 4
  ! #define M_INVALID 5
    
    #define CGI_MAGIC_TYPE "application/x-httpd-cgi"
    #define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
  --- 249,280 ----
    /* ------------------------------ error types 
------------------------------ */
    
    #define DOCUMENT_FOLLOWS 200
  + #define PARTIAL_CONTENT 206
  + #define MOVED 301
    #define REDIRECT 302
    #define USE_LOCAL_COPY 304
    #define BAD_REQUEST 400
    #define AUTH_REQUIRED 401
    #define FORBIDDEN 403
    #define NOT_FOUND 404
  + #define METHOD_NOT_ALLOWED 405
  + #define LENGTH_REQUIRED 411
  + #define PRECONDITION_FAILED 412
    #define SERVER_ERROR 500
    #define NOT_IMPLEMENTED 501
    #define BAD_GATEWAY 502
    #define HTTP_SERVICE_UNAVAILABLE 503
  ! #define RESPONSE_CODES 15
    
  ! #define METHODS 8
    #define M_GET 0
    #define M_PUT 1
    #define M_POST 2
    #define M_DELETE 3
    #define M_CONNECT 4
  ! #define M_OPTIONS 5
  ! #define M_TRACE 6
  ! #define M_INVALID 7
    
    #define CGI_MAGIC_TYPE "application/x-httpd-cgi"
    #define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
  ***************
  *** 342,347 ****
  --- 349,356 ----
      char *hostname;           /* Host, as set by full URI or Host: */
      int hostlen;                      /* Length of http://host:port in full 
URI */
    
  +   time_t request_time;              /* When the request started */
  + 
      char *status_line;                /* Status line, if set by script */
      int status;                       /* In any case */
      
  ***************
  *** 351,360 ****
      
      char *method;                     /* GET, HEAD, POST, etc. */
      int method_number;                /* M_GET, M_POST, etc. */
    
      int sent_bodyct;          /* byte count in stream is for body */
      long bytes_sent;          /* body byte count, for easy access */
  !   
      /* MIME header environments, in and out.  Also, an array containing
       * environment variables to be passed to subprocesses, so people can
       * write modules to add to that environment.
  --- 360,378 ----
      
      char *method;                     /* GET, HEAD, POST, etc. */
      int method_number;                /* M_GET, M_POST, etc. */
  +   int allowed;                      /* Allowed methods - for 405, OPTIONS, 
etc */
    
      int sent_bodyct;          /* byte count in stream is for body */
      long bytes_sent;          /* body byte count, for easy access */
  ! 
  !   int chunked;                      /* sending chunked transfer-coding */
  !   int byterange;            /* number of byte ranges */
  !   char *range;                      /* The Range: header */
  !   long clength;                     /* The "real" content length */
  ! 
  !   long int remaining;               /* bytes left to read */
  !   int read_chunked;         /* reading chunked transfer-coding */
  ! 
      /* MIME header environments, in and out.  Also, an array containing
       * environment variables to be passed to subprocesses, so people can
       * write modules to add to that environment.
  ***************
  *** 521,526 ****
  --- 539,545 ----
    char *getword_conf (pool *p, char **line);      
    
    char *get_token (pool *p, char **accept_line, int accept_white);
  + int find_token (pool *p, char *line, char *tok);
         
    int is_url(char *u);
    extern int unescape_url(char *url);
  ***************
  *** 530,535 ****
  --- 549,555 ----
    char *os_escape_path(pool *p,const char *path,int partial);
    char *escape_uri (pool *p, char *s);
    extern char *escape_html(pool *p, const char *s);
  + char *construct_server(pool *p, char *hostname, int port);
    char *construct_url (pool *p, char *path, server_rec *s);     
    char *escape_shell_cmd (pool *p, char *s);
         
  
  
  
  1.5       +6 -0      apache/src/mod_actions.c
  
  Index: mod_actions.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_actions.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -C3 -r1.4 -r1.5
  *** mod_actions.c     1996/06/16 02:25:06     1.4
  --- mod_actions.c     1996/07/28 19:27:46     1.5
  ***************
  *** 156,161 ****
  --- 156,167 ----
        char *t, *action = r->handler ? r->handler : r->content_type;
        char *script = NULL;
    
  +     /* Set allowed stuff */
  +     if (conf->get) r->allowed |= (1 << M_GET);
  +     if (conf->post) r->allowed |= (1 << M_POST);
  +     if (conf->put) r->allowed |= (1 << M_PUT);
  +     if (conf->delete) r->allowed |= (1 << M_DELETE);
  + 
        /* First, check for the method-handling scripts */
        if ((r->method_number == M_GET) && r->args && conf->get)
            script = conf->get;
  
  
  
  1.6       +1 -1      apache/src/mod_alias.c
  
  Index: mod_alias.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_alias.c,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -C3 -r1.5 -r1.6
  *** mod_alias.c       1996/07/08 18:58:58     1.5
  --- mod_alias.c       1996/07/28 19:27:47     1.6
  ***************
  *** 234,240 ****
    #else    
        if (r->uri[0] != '/' && r->uri[0] != '\0') 
    #endif    
  !         return BAD_REQUEST;
    
        if ((ret = try_alias_list (r, serverconf->redirects, 1)) != NULL) {
            table_set (r->headers_out, "Location", ret);
  --- 234,240 ----
    #else    
        if (r->uri[0] != '/' && r->uri[0] != '\0') 
    #endif    
  !         return DECLINED;
    
        if ((ret = try_alias_list (r, serverconf->redirects, 1)) != NULL) {
            table_set (r->headers_out, "Location", ret);
  
  
  
  1.12      +16 -37    apache/src/mod_cgi.c
  
  Index: mod_cgi.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_cgi.c,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -C3 -r1.11 -r1.12
  *** mod_cgi.c 1996/07/21 20:03:42     1.11
  --- mod_cgi.c 1996/07/28 19:27:48     1.12
  ***************
  *** 165,179 ****
    
    int cgi_handler (request_rec *r)
    {
  !     int nph;
        char *argv0;
        FILE *script_out, *script_in;
        char argsbuffer[HUGE_STRING_LEN];
        int is_included = !strcmp (r->protocol, "INCLUDED");
  -     char *lenp = table_get (r->headers_in, "Content-length");
    
        struct cgi_child_stuff cld;
    
        if((argv0 = strrchr(r->filename,'/')) != NULL)
            argv0++;
        else argv0 = r->filename;
  --- 165,185 ----
    
    int cgi_handler (request_rec *r)
    {
  !     int retval, nph;
        char *argv0;
        FILE *script_out, *script_in;
        char argsbuffer[HUGE_STRING_LEN];
        int is_included = !strcmp (r->protocol, "INCLUDED");
    
        struct cgi_child_stuff cld;
    
  +     if (r->method_number == M_OPTIONS) {
  +         /* 99 out of 100 CGI scripts, this is all they support */
  +         r->allowed |= (1 << M_GET);
  +         r->allowed |= (1 << M_POST);
  +     return DECLINED;
  +     }
  + 
        if((argv0 = strrchr(r->filename,'/')) != NULL)
            argv0++;
        else argv0 = r->filename;
  ***************
  *** 201,221 ****
            log_reason("file permissions deny server execution", r->filename, 
r);
            return FORBIDDEN;
        }
  !     if ((r->method_number == M_POST || r->method_number == M_PUT)
  !     && !lenp) {
  !         log_reason("POST or PUT without Content-length:", r->filename, r);
  !     return BAD_REQUEST;
  !     }
    
        add_common_vars (r);
        cld.argv0 = argv0; cld.r = r; cld.nph = nph;
        
    #ifdef __EMX__
  !     if (r->method_number == M_POST || r->method_number == M_PUT) {
  !         int len_to_read = atoi (lenp);
  !     
  !         if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
  !         read_client_block (r, argsbuffer, len_to_read);
    
            if (!spawn_child_os2 (r->connection->pool, cgi_child, (void *)&cld,
                      nph ? just_wait : kill_after_timeout, 
  --- 207,222 ----
            log_reason("file permissions deny server execution", r->filename, 
r);
            return FORBIDDEN;
        }
  !     if ((retval = setup_client_block(r)))
  !     return retval;
    
        add_common_vars (r);
        cld.argv0 = argv0; cld.r = r; cld.nph = nph;
        
    #ifdef __EMX__
  !     if (should_client_block (r)) {
  ! 
  !         read_client_block (r, argsbuffer, HUGE_STRING_LEN);
    
            if (!spawn_child_os2 (r->connection->pool, cgi_child, (void *)&cld,
                      nph ? just_wait : kill_after_timeout, 
  ***************
  *** 251,289 ****
         */
        
    #ifndef __EMX__
  !     if (r->method_number == M_POST || r->method_number == M_PUT) {
            void (*handler)();
  !     int remaining = atoi (lenp);
        
            hard_timeout ("copy script args", r);
            handler = signal (SIGPIPE, SIG_IGN);
        
  !     while ((remaining > 0))
  !     {
  !         int len_read, len_to_read = remaining;
  ! 
  !         if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
  !         
  !         len_read = read_client_block (r, argsbuffer, len_to_read);
  !         if (len_read == 0)
  !             break;
            if (fwrite (argsbuffer, 1, len_read, script_out) == 0)
                break;
  -         remaining -= len_read;
  -     }
    
  -     /* If script stopped reading early, soak up remaining stuff from
  -      * client...
  -      */
  -     
  -     while (remaining > 0) {
  -         int len_read, len_to_read = remaining;
  -         if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
  -         
  -         len_read = read_client_block (r, argsbuffer, len_to_read);
  -         if (len_read == 0) break;
  -     }
  -     
        fflush (script_out);
        signal (SIGPIPE, handler);
        
  --- 252,268 ----
         */
        
    #ifndef __EMX__
  !      if (should_client_block(r)) {
            void (*handler)();
  !     int len_read;
        
            hard_timeout ("copy script args", r);
            handler = signal (SIGPIPE, SIG_IGN);
        
  !     while ((len_read = read_client_block (r, argsbuffer, HUGE_STRING_LEN)))
            if (fwrite (argsbuffer, 1, len_read, script_out) == 0)
                break;
    
        fflush (script_out);
        signal (SIGPIPE, handler);
        
  
  
  
  1.12      +2 -2      apache/src/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_include.c,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -C3 -r1.11 -r1.12
  *** mod_include.c     1996/07/27 04:43:22     1.11
  --- mod_include.c     1996/07/28 19:27:48     1.12
  ***************
  *** 87,93 ****
        struct passwd *pw;
        table *e = r->subprocess_env;
        char *t;
  !     time_t date = time(NULL);
    
        table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
        table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
  --- 87,93 ----
        struct passwd *pw;
        table *e = r->subprocess_env;
        char *t;
  !     time_t date = r->request_time;
    
        table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
        table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
  ***************
  *** 584,590 ****
            if(!strcmp(tag,"errmsg"))
                strcpy(error,tag_val);
            else if(!strcmp(tag,"timefmt")) {
  !         time_t date = time(NULL);
                strcpy(tf,tag_val);
                table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
                table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
  --- 584,590 ----
            if(!strcmp(tag,"errmsg"))
                strcpy(error,tag_val);
            else if(!strcmp(tag,"timefmt")) {
  !         time_t date = r->request_time;
                strcpy(tf,tag_val);
                table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
                table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
  
  
  
  1.10      +38 -3     apache/src/mod_negotiation.c
  
  Index: mod_negotiation.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_negotiation.c,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -C3 -r1.9 -r1.10
  *** mod_negotiation.c 1996/07/08 18:59:02     1.9
  --- mod_negotiation.c 1996/07/28 19:27:49     1.10
  ***************
  *** 347,353 ****
    negotiation_state *parse_accept_headers (request_rec *r)
    {
        negotiation_state *new =
  !         (negotiation_state *)palloc (r->pool, sizeof (negotiation_state));
        table *hdrs = r->headers_in;
    
        new->pool = r->pool;
  --- 347,353 ----
    negotiation_state *parse_accept_headers (request_rec *r)
    {
        negotiation_state *new =
  !         (negotiation_state *)pcalloc (r->pool, sizeof (negotiation_state));
        table *hdrs = r->headers_in;
    
        new->pool = r->pool;
  ***************
  *** 1016,1021 ****
  --- 1016,1046 ----
        return best;
    }
    
  + char *set_vary (pool *p, negotiation_state *neg)
  + {
  +     var_rec *var_recs = (var_rec*)neg->avail_vars->elts;
  +     int i, accept_encoding = 0;
  +     int accept_language = 0;
  +     char *enc, *lang;
  + 
  +     /* Go through each variant and check for an encoding
  +      * or language (we always set "Accept", so no need to check).
  +      */
  + 
  +     for (i = 0; i < neg->avail_vars->nelts; ++i) {
  +         enc = var_recs[i].content_encoding;
  +     lang = var_recs[i].content_language;
  + 
  +         if (!accept_encoding && !(!enc || !strcmp(enc, "")))
  +         accept_encoding = 1;
  +     if (!accept_language && !(!lang || !strcmp(lang, "")))
  +         accept_language = 1;
  +     }
  + 
  +     return pstrcat(p, "Accept", accept_encoding ? ", Accept-Encoding" : "",
  +                accept_language ? ", Accept-Language" : "", NULL);
  + }
  + 
    /****************************************************************
     *
     * Executive...
  ***************
  *** 1039,1045 ****
          return NOT_FOUND;
        }
    
  !     if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
        udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri));
        udir = escape_uri(r->pool, udir);
        internal_redirect (make_full_path (r->pool, udir, best->file_name), r);
  --- 1064,1077 ----
          return NOT_FOUND;
        }
    
  !     /* Make sure caching works - Vary should handle HTTP/1.1, but for
  !      * HTTP/1.0, we can't allow caching at all. NB that we merge the
  !      * header in case some other module negotiates on something else.
  !      */
  !     if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001))
  !         r->no_cache = 1;
  !     table_merge(r->err_headers_out, "Vary", set_vary(r->pool, neg));
  ! 
        udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri));
        udir = escape_uri(r->pool, udir);
        internal_redirect (make_full_path (r->pool, udir, best->file_name), r);
  ***************
  *** 1087,1093 ****
        
        /* Otherwise, use it. */
        
  !     if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
        r->filename = sub_req->filename;
        r->handler = sub_req->handler;
        r->content_type = sub_req->content_type;
  --- 1119,1128 ----
        
        /* Otherwise, use it. */
        
  !     if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001))
  !         r->no_cache = 1;
  !     table_merge(r->err_headers_out, "Vary", set_vary(r->pool, neg));
  ! 
        r->filename = sub_req->filename;
        r->handler = sub_req->handler;
        r->content_type = sub_req->content_type;
  
  
  
  1.34      +6 -18     apache/src/mod_proxy.c
  
  Index: mod_proxy.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_proxy.c,v
  retrieving revision 1.33
  retrieving revision 1.34
  diff -C3 -r1.33 -r1.34
  *** mod_proxy.c       1996/07/25 19:49:04     1.33
  --- mod_proxy.c       1996/07/28 19:27:49     1.34
  ***************
  *** 2117,2123 ****
    static int
    proxy_handler(request_rec *r)
    {
  !     char *url, *scheme, *lenp, *p;
        void *sconf = r->server->module_config;
        proxy_server_conf *conf =
            (proxy_server_conf *)get_module_config(sconf, &proxy_module);
  --- 2117,2123 ----
    static int
    proxy_handler(request_rec *r)
    {
  !     char *url, *scheme, *p;
        void *sconf = r->server->module_config;
        proxy_server_conf *conf =
            (proxy_server_conf *)get_module_config(sconf, &proxy_module);
  ***************
  *** 2128,2137 ****
    
        if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
    
  !     lenp = table_get (r->headers_in, "Content-length");
  !     if ((r->method_number == M_POST || r->method_number == M_PUT)
  !     && lenp == NULL)
  !     return BAD_REQUEST;
    
        url = r->filename + 6;
        p = strchr(url, ':');
  --- 2128,2135 ----
    
        if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
    
  !     if ((rc = setup_client_block(r)))
  !     return rc;
    
        url = r->filename + 6;
        p = strchr(url, ':');
  ***************
  *** 2849,2868 ****
        bputs("\015\012", f);
    /* send the request data, if any. N.B. should we trap SIGPIPE ? */
    
  !     if (r->method_number == M_POST || r->method_number == M_PUT)
        {
  !     len = atoi(table_get (r->headers_in, "Content-length"));
  ! 
  !     while (len > 0)
  !     {
  !         i = len;
  !         if (i > HUGE_STRING_LEN) i = HUGE_STRING_LEN;
  !         
  !         i = read_client_block(r, buffer, i);
  !         bwrite(f, buffer, i);
  ! 
  !         len -= i;
  !     }
        }
        bflush(f);
        kill_timeout(r);
  --- 2847,2856 ----
        bputs("\015\012", f);
    /* send the request data, if any. N.B. should we trap SIGPIPE ? */
    
  !     if (should_client_block(r))
        {
  !     while ((i = read_client_block (r, buffer, HUGE_STRING_LEN)))
  !             bwrite(f, buffer, i);
        }
        bflush(f);
        kill_timeout(r);
  
  
  
  1.14      +60 -7     apache/src/util.c
  
  Index: util.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/util.c,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -C3 -r1.13 -r1.14
  *** util.c    1996/07/09 21:40:14     1.13
  --- util.c    1996/07/28 19:27:50     1.14
  ***************
  *** 528,533 ****
  --- 528,581 ----
        return token;
    }
    
  + static char* tspecials = " \t()<>@,;:\\/[]?={}";
  + 
  + /* Next HTTP token from a header line.  Warning --- destructive!
  +  * Use only with a copy!
  +  */
  + 
  + static char *next_token (char **toks) {
  +     char *cp = *toks;
  +     char *ret;
  + 
  +     while (*cp && (iscntrl (*cp) || strchr (tspecials, *cp))) {
  +         if (*cp == '"')
  +       while (*cp && (*cp != '"')) ++cp;
  +     else
  +       ++cp;
  +     }
  + 
  +     if (!*cp) ret = NULL;
  +     else {
  +         ret = cp;
  + 
  +         while (*cp && !iscntrl(*cp) && !strchr (tspecials, *cp))
  +             ++cp;
  + 
  +         if (*cp) {
  +             *toks = cp + 1;
  +             *cp = '\0';
  +     }
  +         else *toks = cp;
  +     }
  + 
  +     return ret;
  + }
  + 
  + int find_token (pool *p, char *line, char *tok) {
  +     char *ltok;
  + 
  +     if (!line) return 0;
  + 
  +     line = pstrdup (p, line);
  +     while ((ltok = next_token (&line)))
  +         if (!strcasecmp (ltok, tok))
  +             return 1;
  + 
  +     return 0;
  + }
  + 
  + 
    char *escape_shell_cmd(pool *p, char *s) {
        register int x,y,l;
        char *cmd;
  ***************
  *** 617,632 ****
        else return OK;
    }
    
  ! char *construct_url(pool *p, char *uri, server_rec *s) {
        char portnum[10];               /* Long enough.  Really! */
      
  !     if (s->port == 80) {
  !         return pstrcat (p, "http://";, s->server_hostname, uri, NULL);
  !     } else {
  !         sprintf (portnum, "%d", s->port);
  !     return pstrcat (p, "http://";, s->server_hostname, ":", portnum, uri,
  !                     NULL);
        }
    }
    
    #define c2x(what,where) sprintf(where,"%%%02x",what)
  --- 665,685 ----
        else return OK;
    }
    
  ! char *construct_server(pool *p, char *hostname, int port) {
        char portnum[10];               /* Long enough.  Really! */
      
  !     if (port == 80)
  !     return hostname;
  !     else {
  !         sprintf (portnum, "%d", port);
  !     return pstrcat (p, hostname, ":", portnum, NULL);
        }
  + }
  + 
  + char *construct_url(pool *p, char *uri, server_rec *s) {
  +     return pstrcat (p, "http://";,
  +                 construct_server(p, s->server_hostname, s->port),
  +                 uri, NULL);
    }
    
    #define c2x(what,where) sprintf(where,"%%%02x",what)
  
  
  

Reply via email to