httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alexei Kosut <ako...@organic.com>
Subject per-dir config patch
Date Wed, 24 Jul 1996 23:06:52 GMT
Here's a patch that implements some of the functionality I've been talking
about the last few days. It does four things:

1) Contains the patch I submitted earlier to make <Location> work only on
directory segments.

2) Adds a pregcomp() function to alloc.c (also adds #include
"regex/regex.h" to conf.h).

3) Adds a <Files> directive. This works akin to how I'm given to
understand the Netscape Server directive of the same name works. It works
very much like <Directory>, except it applies to all files, not just
directories. So you can do <Files /some/path/to/a/file.html>. You can also
put <Files> into an .htaccess file. It supports relative pathnames, so you
can put <Files file.gif> in /www/.htaccess and it will apply to
/www/file.gif.

4) Allows <Directory>, <Location> and <Files> to use regular expressions
instead of simple prefix matching or wildcard matching. The syntax is:

<Directory ~ regex>
<Location ~ regex>
<Files ~ regex>

For example, if I wanted to restrict all JPEG and GIF files on my server,
I might use

<Files ~ \\.(gif|jpeg)$>

(the \\ is needed because Apache's config file parsing routines get to the
backslash first, so we need to backslash-escape the backslash to pass it
to the regex parser).

I think this implements useful functionality, and functionality people
have been asking for. Do I hear two +1 votes?

Heres the complete patch:

Index: alloc.c
===================================================================
RCS file: /export/home/cvs/apache/src/alloc.c,v
retrieving revision 1.7
diff -c -r1.7 alloc.c
*** alloc.c	1996/07/21 14:49:01	1.7
--- alloc.c	1996/07/24 22:49:38
***************
*** 803,808 ****
--- 803,829 ----
    return res;
  }
  
+ /*
+  * Here's a pool-based interface to POSIX regex's regcomp().
+  * Note that we return regex_t instead of being passed one.
+  * The reason is that if you use an already-used regex_t structure,
+  * the memory that you've already allocated gets forgotten, and
+  * regfree() doesn't clear it. So we don't allow it.
+  */
+ 
+ static void regex_cleanup (void *preg) { regfree ((regex_t *)preg); }
+ 
+ regex_t *pregcomp(pool *p, const char *pattern, int cflags) {
+     regex_t *preg = palloc(p, sizeof(regex_t));
+ 
+     if (regcomp(preg, pattern, cflags))
+ 	return NULL;
+ 
+     register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup);
+ 
+     return preg;
+ }
+ 
  /*****************************************************************
   *
   * More grotty system stuff... subprocesses.  Frump.  These don't use
Index: alloc.h
===================================================================
RCS file: /export/home/cvs/apache/src/alloc.h,v
retrieving revision 1.6
diff -c -r1.6 alloc.h
*** alloc.h	1996/07/21 14:49:01	1.6
--- alloc.h	1996/07/24 22:49:38
***************
*** 207,212 ****
--- 207,214 ----
  void note_cleanups_for_fd (pool *, int);
  void kill_cleanups_for_fd (pool *p, int fd);
  
+ regex_t *pregcomp(pool *p, const char *pattern, int cflags);
+ 
  /* routines to note closes... file descriptors are constrained enough
   * on some systems that we want to support this.
   */
Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache/src/buff.c,v
retrieving revision 1.3
diff -c -r1.3 buff.c
*** buff.c	1996/05/08 15:28:19	1.3
--- buff.c	1996/07/24 22:49:38
***************
*** 56,61 ****
--- 56,62 ----
  #include <string.h>
  #include <unistd.h>
  
+ #include "conf.h"
  #include "alloc.h"
  #include "buff.h"
  
Index: conf.h
===================================================================
RCS file: /export/home/cvs/apache/src/conf.h,v
retrieving revision 1.23
diff -c -r1.23 conf.h
*** conf.h	1996/07/18 18:44:44	1.23
--- conf.h	1996/07/24 22:49:38
***************
*** 388,393 ****
--- 388,394 ----
  #ifndef QNX
  #include <memory.h>
  #endif
+ #include "regex/regex.h"
  
  #ifdef HAVE_RESOURCE
  #include <sys/resource.h>
Index: http_bprintf.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_bprintf.c,v
retrieving revision 1.4
diff -c -r1.4 http_bprintf.c
*** http_bprintf.c	1996/07/16 19:57:25	1.4
--- http_bprintf.c	1996/07/24 22:49:38
***************
*** 13,27 ****
   * 18 May 1996 Initial revision [Ben Laurie]
   */
  
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #ifndef QNX
- #include <memory.h>
- #endif
  #include <assert.h>
  #include <math.h>
  #include "alloc.h"
  #include "buff.h"
  
--- 13,21 ----
   * 18 May 1996 Initial revision [Ben Laurie]
   */
  
  #include <assert.h>
  #include <math.h>
+ #include "conf.h"
  #include "alloc.h"
  #include "buff.h"
  
Index: http_core.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.c,v
retrieving revision 1.18
diff -c -r1.18 http_core.c
*** http_core.c	1996/06/12 18:14:31	1.18
--- http_core.c	1996/07/24 22:49:38
***************
*** 93,98 ****
--- 93,101 ----
  
      conf->hostname_lookups = 2;/* binary, but will use 2 as an "unset = on" */
      conf->do_rfc1413 = DEFAULT_RFC1413 | 2;  /* set bit 1 to indicate default */
+ 
+     conf->sec = make_array (a, 2, sizeof(void *));
+ 
      return (void *)conf;
  }
  
***************
*** 107,112 ****
--- 110,116 ----
      memcpy ((char *)conf, (const char *)base, sizeof(core_dir_config));
      
      conf->d = new->d;
+     conf->r = new->r;
      
      if (new->opts != OPT_UNSET) conf->opts = new->opts;
      if (new->override != OR_UNSET) conf->override = new->override;
***************
*** 124,129 ****
--- 128,135 ----
      if ((new->do_rfc1413 & 2) == 0) conf->do_rfc1413 = new->do_rfc1413;
      if ((new->content_md5 & 2) == 0) conf->content_md5 = new->content_md5;
  
+     conf->sec = append_arrays (a, base->sec, new->sec);
+ 
      return (void*)conf;
  }
  
***************
*** 179,184 ****
--- 185,197 ----
      *new_space = url_config;
  }
  
+ void add_file_conf (core_dir_config *conf, void *url_config)
+ {
+     void **new_space = (void **) push_array (conf->sec);
+     
+     *new_space = url_config;
+ }
+ 
  /*****************************************************************
   *
   * There are some elements of the core config structures in which
***************
*** 518,536 ****
      char *errmsg, *endp = strrchr (arg, '>');
      int old_overrides = cmd->override;
      char *old_path = cmd->path;
      void *new_dir_conf = create_per_dir_config (cmd->pool);
  
      if (endp) *endp = '\0';
  
      if (cmd->path) return "<Directory> sections don't nest";
      if (cmd->limited != -1) return "Can't have <Directory> within <Limit>";
!     
      cmd->path = getword_conf (cmd->pool, &arg);
      cmd->override = OR_ALL|ACCESS_CONF;
  
      errmsg = srm_command_loop (cmd, new_dir_conf);
      add_per_dir_conf (cmd->server, new_dir_conf);
!     
      cmd->path = old_path;
      cmd->override = old_overrides;
  
--- 531,559 ----
      char *errmsg, *endp = strrchr (arg, '>');
      int old_overrides = cmd->override;
      char *old_path = cmd->path;
+     core_dir_config *conf;
      void *new_dir_conf = create_per_dir_config (cmd->pool);
+     regex_t *r = NULL;
  
      if (endp) *endp = '\0';
  
      if (cmd->path) return "<Directory> sections don't nest";
      if (cmd->limited != -1) return "Can't have <Directory> within <Limit>";
! 
      cmd->path = getword_conf (cmd->pool, &arg);
      cmd->override = OR_ALL|ACCESS_CONF;
  
+     if (!strcmp(cmd->path, "~")) {
+ 	cmd->path = getword_conf (cmd->pool, &arg);
+ 	r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+     }
+ 
      errmsg = srm_command_loop (cmd, new_dir_conf);
      add_per_dir_conf (cmd->server, new_dir_conf);
! 
!     conf = (core_dir_config *)get_module_config(new_dir_conf, &core_module);
!     conf->r = r;
!  
      cmd->path = old_path;
      cmd->override = old_overrides;
  
***************
*** 550,555 ****
--- 573,579 ----
      int old_overrides = cmd->override;
      char *old_path = cmd->path;
      core_dir_config *conf;
+     regex_t *r = NULL;
  
      void *new_url_conf = create_per_dir_config (cmd->pool);
  
***************
*** 561,571 ****
--- 585,601 ----
      cmd->path = getword_conf (cmd->pool, &arg);
      cmd->override = OR_ALL|ACCESS_CONF;
  
+     if (!strcmp(cmd->path, "~")) {
+ 	cmd->path = getword_conf (cmd->pool, &arg);
+ 	r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+     }
+ 
      errmsg = srm_command_loop (cmd, new_url_conf);
      if (errmsg != end_url_magic) return errmsg;
  
      conf = (core_dir_config *)get_module_config(new_url_conf, &core_module);
      conf->d = pstrdup(cmd->pool, cmd->path);	/* No mangling, please */
+     conf->r = r;
  
      add_per_url_conf (cmd->server, new_url_conf);
      
***************
*** 575,580 ****
--- 605,654 ----
      return NULL;
  }
  
+ static char *end_file_magic = "</Files> outside of any <Files> section";
+ 
+ char *end_filesection (cmd_parms *cmd, void *dummy) {
+     return end_file_magic;
+ }
+ 
+ char *filesection (cmd_parms *cmd, core_dir_config *c, char *arg)
+ {
+     char *errmsg, *endp = strrchr (arg, '>');
+     char *old_path = cmd->path;
+     core_dir_config *conf;
+     regex_t *r = NULL;
+ 
+     void *new_file_conf = create_per_dir_config (cmd->pool);
+ 
+     if (endp) *endp = '\0';
+ 
+     if (cmd->limited != -1) return "Can't have <Files> within <Limit>";
+ 
+     cmd->path = getword_conf (cmd->pool, &arg);
+ 
+     if (!strcmp(cmd->path, "~")) {
+ 	cmd->path = getword_conf (cmd->pool, &arg);
+ 	if (old_path && cmd->path[0] != '/' && cmd->path[0] != '^')
+ 	    cmd->path = pstrcat(cmd->pool, "^", old_path, cmd->path, NULL);
+ 	r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+     }
+     else if (old_path && cmd->path[0] != '/')
+ 	cmd->path = pstrcat(cmd->pool, old_path, cmd->path, NULL);
+ 
+     errmsg = srm_command_loop (cmd, new_file_conf);
+     if (errmsg != end_file_magic) return errmsg;
+ 
+     conf = (core_dir_config *)get_module_config(new_file_conf, &core_module);
+     conf->d = pstrdup(cmd->pool, cmd->path);
+     conf->r = r;
+ 
+     add_file_conf (c, new_file_conf);
+     
+     cmd->path = old_path;
+ 
+     return NULL;
+ }
+ 
  /* httpd.conf commands... beginning with the <VirtualHost> business */
  
  char *end_virthost_magic = "</Virtualhost> out of place";
***************
*** 779,784 ****
--- 853,860 ----
  { "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
  { "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS, NULL },
  { "</Location>", end_urlsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+ { "<Files", filesection, NULL, OR_ALL, RAW_ARGS, NULL },
+ { "</Files>", end_filesection, NULL, OR_ALL, NO_ARGS, NULL },
  { "<Limit", limit, NULL, OR_ALL, RAW_ARGS, NULL },
  { "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL },
  { "AuthType", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_type),
Index: http_core.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.h,v
retrieving revision 1.6
diff -c -r1.6 http_core.h
*** http_core.h	1996/04/06 23:38:25	1.6
--- http_core.h	1996/07/24 22:49:38
***************
*** 152,157 ****
--- 152,161 ----
      int hostname_lookups;
      int do_rfc1413;   /* See if client is advertising a username? */
  
+     /* Access control */
+     array_header *sec;
+     regex_t *r;
+ 
  } core_dir_config;
  
  /* Per-server core configuration */
***************
*** 165,171 ****
      char *document_root;
    
      /* Access control */
!   
      char *access_name;
      array_header *sec;
      array_header *sec_url;
--- 169,175 ----
      char *document_root;
    
      /* Access control */
! 
      char *access_name;
      array_header *sec;
      array_header *sec_url;
Index: http_request.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_request.c,v
retrieving revision 1.11
diff -c -r1.11 http_request.c
*** http_request.c	1996/07/01 18:10:29	1.11
--- http_request.c	1996/07/24 22:49:38
***************
*** 242,248 ****
  	    entry_dir = entry_core->d;
  
  	    this_conf = NULL;
! 	    if (is_matchexp(entry_dir)) {
  		if (!strcmp_match(test_filename, entry_dir))
  		    this_conf = entry_config;
  	    }
--- 242,252 ----
  	    entry_dir = entry_core->d;
  
  	    this_conf = NULL;
! 	    if (entry_core->r) {
! 		if (!regexec(entry_core->r, test_filename, 0, NULL, 0))
! 		    this_conf = entry_config;
! 	    }
! 	    else if (is_matchexp(entry_dir)) {
  		if (!strcmp_match(test_filename, entry_dir))
  		    this_conf = entry_config;
  	    }
***************
*** 301,311 ****
  	      (core_dir_config *)get_module_config(entry_config, &core_module);
  	    entry_dir = entry_core->d;
  	
! 	    if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
! 		/* Don't try this wildcard again --- if it ends in '*'
! 		 * it'll match again, and subdirectories won't be able to
! 		 * override it...
! 		 */
  		sec[j] = NULL;	
  	        this_conf = entry_config;
  	    }
--- 305,323 ----
  	      (core_dir_config *)get_module_config(entry_config, &core_module);
  	    entry_dir = entry_core->d;
  	
! 	    if (entry_core->r) {
! 		if (!regexec(entry_core->r, this_dir, 0, NULL,
! 			     (j == num_sec) ? 0 : REG_NOTEOL)) {
! 		    /* Don't try this wildcard again --- if it ends in '*'
! 		     * it'll match again, and subdirectories won't be able to
! 		     * override it...
! 		     */
! 		    sec[j] = NULL;
! 		    this_conf = entry_config;
! 		}
! 	    }
! 	    else if (is_matchexp(entry_dir) &&
! 		     !strcmp_match(this_dir, entry_dir)) {
  		sec[j] = NULL;	
  	        this_conf = entry_config;
  	    }
***************
*** 359,365 ****
      void *per_dir_defaults = r->per_dir_config;
      
      core_dir_config **url = (core_dir_config **)url_array->elts;
!     int num_url = url_array->nelts;
      char *test_location = pstrdup (r->pool, r->uri);
  
      /* Go through the location entries, and check for matches. */
--- 371,377 ----
      void *per_dir_defaults = r->per_dir_config;
      
      core_dir_config **url = (core_dir_config **)url_array->elts;
!     int len, num_url = url_array->nelts;
      char *test_location = pstrdup (r->pool, r->uri);
  
      /* Go through the location entries, and check for matches. */
***************
*** 383,394 ****
  		get_module_config(entry_config, &core_module);
  	    entry_url = entry_core->d;
  
  	    this_conf = NULL;
! 	    if (is_matchexp(entry_url)) {
  		if (!strcmp_match(test_location, entry_url))
  		    this_conf = entry_config;
  	    }
! 	    else if (!strncmp (test_location, entry_url, strlen(entry_url)))
  	        this_conf = entry_config;
  
  	    if (this_conf)
--- 395,474 ----
  		get_module_config(entry_config, &core_module);
  	    entry_url = entry_core->d;
  
+ 	    len = strlen(entry_url);
+ 
  	    this_conf = NULL;
! 
! 	    if (entry_core->r) {
! 		if (!regexec(entry_core->r, test_location, 0, NULL, 0))
! 		    this_conf = entry_config;
! 	    }
! 	    else if (is_matchexp(entry_url)) {
  		if (!strcmp_match(test_location, entry_url))
  		    this_conf = entry_config;
  	    }
! 	    else if (!strncmp (test_location, entry_url, len) &&
! 		     (entry_url[len - 1] == '/' ||
! 		      test_location[len] == '/' || test_location[len] == '\0'))
! 	        this_conf = entry_config;
! 
! 	    if (this_conf)
! 	        per_dir_defaults = merge_per_dir_configs (r->pool,
! 					    per_dir_defaults, this_conf);
! 	}
! 
! 	r->per_dir_config = per_dir_defaults;
!     }
! 
!     return OK;
! }
! 
! int file_walk (request_rec *r)
! {
!     core_dir_config *conf = get_module_config(r->per_dir_config, &core_module);
!     array_header *file_array = copy_array (r->pool, conf->sec);
!     void *per_dir_defaults = r->per_dir_config;
!     
!     core_dir_config **file = (core_dir_config **)file_array->elts;
!     int len, num_files = file_array->nelts;
!     char *test_file = pstrdup (r->pool, r->filename);
! 
!     /* Go through the file entries, and check for matches. */
! 
!     if (num_files) {
!         void *this_conf, *entry_config;
! 	core_dir_config *entry_core;
! 	char *entry_file;
! 	int j;
! 
! /* 
!  * we apply the directive sections in some order; should really try them
!  * with the most general first.
!  */
! 	for (j = 0; j < num_files; ++j) {
! 
! 	    entry_config = file[j];
! 	    if (!entry_config) continue;
! 	    
! 	    entry_core =(core_dir_config *)
! 		get_module_config(entry_config, &core_module);
! 	    entry_file = entry_core->d;
! 
! 	    len = strlen(entry_file);
! 
! 	    this_conf = NULL;
! 
! 	    if (entry_core->r) {
! 		if (!regexec(entry_core->r, test_file, 0, NULL, 0))
! 		    this_conf = entry_config;
! 	    }
! 	    else if (is_matchexp(entry_file)) {
! 		if (!strcmp_match(test_file, entry_file))
! 		    this_conf = entry_config;
! 	    }
! 	    else if (!strncmp (test_file, entry_file, len) &&
! 		     (entry_file[len - 1] == '/' ||
! 		      test_file[len] == '/' || test_file[len] == '\0'))
  	        this_conf = entry_config;
  
  	    if (this_conf)
***************
*** 513,518 ****
--- 593,599 ----
       */
      
      if ((res = directory_walk (rnew))
+ 	|| (res = file_walk (rnew))
  	|| (!some_auth_required (rnew) ? 0 :
  	     ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
  	|| (res = check_access (rnew))
***************
*** 555,560 ****
--- 636,642 ----
  		      make_full_path (rnew->pool, fdir, new_file));
  	
      if ((res = directory_walk (rnew))
+ 	|| (res = file_walk (rnew))
  	|| (res = check_access (rnew))
  	|| (!some_auth_required (rnew) ? 0 :
  	     ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
***************
*** 732,742 ****
          die (access_status, r);
  	return;
      }	
!     
      if ((access_status = location_walk (r))) {
          die (access_status, r);
  	return;
      }	
      
      if ((access_status = check_access (r)) != 0) {
          decl_die (access_status, "check access", r);
--- 814,829 ----
          die (access_status, r);
  	return;
      }	
! 
      if ((access_status = location_walk (r))) {
          die (access_status, r);
  	return;
      }	
+     
+     if ((access_status = file_walk (r))) {
+ 	die (access_status, r);
+ 	return;
+     }
      
      if ((access_status = check_access (r)) != 0) {
          decl_die (access_status, "check access", r);


-- Alexei Kosut <akosut@organic.com>            The Apache HTTP Server 
   http://www.nueva.pvt.k12.ca.us/~akosut/      http://www.apache.org/


Mime
View raw message