Author: stefan2
Date: Tue Jul 29 17:34:46 2014
New Revision: 1614429

URL: http://svn.apache.org/r1614429
Log:
On the authzperf branch:  Add support for full-segment '*'.

This adds a new sub-structure to node_t that will grow as we
add support for more patterns in later commits.  We also
implement the "*" prefix to path rules indicating that there
may be non-literal characters (wildcards) in the path.

* BRANCH-README
  (TODO, DONE): First wildcard feature done.

* subversion/libsvn_repos/authz.c
  (node_pattern_t,
   node_t): Extend the prefix tree nodes to allows for different
            kinds, i.e. different to match, of sub-nodes.
  (has_wildcards,
   ensure_node,
   ensure_pattern_sub_nodes): New utilities that handle the
                              detection and addition of pattern
                              sub-nodes.
  (insert_path): Add opt-in wildcard support.
  (process_path_rule): Handle the wildcard enabling "*" prefix
                       and check whether there are actually
                       wildcards in the current path rule.
  (finalize_tree,
   lookup): Handle the ANY sub-node just like any other sub-node.
  (authz_validate_section): Valid paths may now have a "*" prefix.

Modified:
    subversion/branches/authzperf/BRANCH-README
    subversion/branches/authzperf/subversion/libsvn_repos/authz.c

Modified: subversion/branches/authzperf/BRANCH-README
URL: 
http://svn.apache.org/viewvc/subversion/branches/authzperf/BRANCH-README?rev=1614429&r1=1614428&r2=1614429&view=diff
==============================================================================
--- subversion/branches/authzperf/BRANCH-README (original)
+++ subversion/branches/authzperf/BRANCH-README Tue Jul 29 17:34:46 2014
@@ -9,7 +9,6 @@ TODO:
 
 * implement an authz-specific constructor for the config parser
 * implement precedence rules
-* add support for full-segment wildcards ("/*/")
 * add support for variable length full-segment wildcards ("/**/")
 * add support for prefix segment patterns ("/foo*/")
 * add support for suffix segment patterns ("/*foo/")
@@ -24,3 +23,4 @@ DONE:
 * implement recursive tree checks
 * implement evaluation shortcuts
 * parametrize in-memory representation constructor in the config parser
+* add support for full-segment wildcards ("/*/")

Modified: subversion/branches/authzperf/subversion/libsvn_repos/authz.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_repos/authz.c?rev=1614429&r1=1614428&r2=1614429&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_repos/authz.c Tue Jul 29 
17:34:46 2014
@@ -287,6 +287,16 @@ typedef struct access_t
  * It will automatically be inferior to (less than) any other sequence ID. */
 #define NO_SEQUENCE_NUMBER (-1)
 
+/* Substructure of node_t.  It contains all sub-node that use patterns
+ * in the next segment level. We keep it separate to save a bit of memory
+ * and to be able to check for pattern presence in a single operation.
+ */
+typedef struct node_pattern_t
+{
+  /* If not NULL, this represents the "*" follow-segment. */
+  struct node_t *any;
+} node_pattern_t;
+
 /* The pattern tree.  All relevant path rules are being folded into this
  * prefix tree, with a single, whole segment stored at each node.  The whole
  * tree applies to a single user only.
@@ -314,6 +324,9 @@ typedef struct node_t
    * sub-segments that have rules on themselves or their respective subtrees.
    * NULL, if there are no rules for sub-paths relevant to the user. */
   apr_hash_t *sub_nodes;
+
+  /* If not NULL, this contains the pattern-based segment sub-nodes. */
+  node_pattern_t *pattern_sub_nodes;
 } node_t;
 
 /* Callback baton to be used with process_rule(). */
@@ -388,6 +401,15 @@ has_matching_rule(svn_repos_authz_access
   return baton.found;
 }
 
+/* Return TRUE, iff PATH has been marked as supporting wildcards and is
+ * actually using wildcards.
+ */
+static svn_boolean_t
+has_wildcards(const char *path)
+{
+  return path[0] == '*' && strchr(path + 1, '*');
+}
+
 /* Constructor utility: Create a new tree node for SEGMENT.
  */
 static node_t *
@@ -403,14 +425,44 @@ create_node(const char *segment,
   return result;
 }
 
+/* Constructor utility: Auto-create a node in *NODE, make it apply to
+ * SEGMENT and return it.
+ */
+static node_t *
+ensure_node(node_t **node,
+            const char *segment,
+            apr_pool_t *result_pool)
+{
+  if (!*node)
+    *node = create_node(segment, result_pool);
+
+  return *node;
+}
+
+/* Constructor utility: Auto-create the PATTERN_SUB_NODES sub-structure in
+ * *NODE and return it.
+ */
+static node_pattern_t *
+ensure_pattern_sub_nodes(node_t *node,
+                         apr_pool_t *result_pool)
+{
+  if (node->pattern_sub_nodes == NULL)
+    node->pattern_sub_nodes = apr_pcalloc(result_pool,
+                                          sizeof(*node->pattern_sub_nodes));
+
+  return node->pattern_sub_nodes;
+}
+
 /* Constructor utility:  Below NODE, recursively insert sub-nodes for the
  * path given as *SEGMENTS.  The end of the path is indicated by a NULL
- * SEGMENT.  If matching nodes already exist, use those instead of creating
- * new ones.  Set the leave node's access rights spec to ACCESS.
+ * SEGMENT.  If ALLOW_WILDCARDS is FALSE, treat all characters literally.
+ * If matching nodes already exist, use those instead of creating new ones.
+ * Set the leave node's access rights spec to ACCESS.
  */
 static void
 insert_path(node_t *node,
             const char **segments,
+            svn_boolean_t allow_wildcards,
             access_t *access,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
@@ -430,21 +482,38 @@ insert_path(node_t *node,
       return;
     }
 
-  /* There will be sub-nodes.  Ensure the container is there as well. */
-  if (!node->sub_nodes)
-    node->sub_nodes = svn_hash__make(result_pool);
-
-  /* Auto-insert a sub-node for the current segment. */
-  sub_node = svn_hash_gets(node->sub_nodes, segment);
-  if (!sub_node)
-    {
-      sub_node = create_node(segment, result_pool);
-      apr_hash_set(node->sub_nodes, sub_node->segment.data,
-                   sub_node->segment.len, sub_node);
+  /* Any wildcards? */
+  if (allow_wildcards && strchr(segment, '*'))
+    {
+      ensure_pattern_sub_nodes(node, result_pool);
+
+      /* A full wildcard segment? */
+      if (strcmp(segment, "*") == 0)
+        sub_node = ensure_node(&node->pattern_sub_nodes->any, segment,
+                               result_pool);
+
+      /* More cases to be added here later.
+       * There will be no error condition to be checked for. */
+    }
+  else
+    {
+      /* There will be sub-nodes.  Ensure the container is there as well. */
+      if (!node->sub_nodes)
+        node->sub_nodes = svn_hash__make(result_pool);
+
+      /* Auto-insert a sub-node for the current segment. */
+      sub_node = svn_hash_gets(node->sub_nodes, segment);
+      if (!sub_node)
+        {
+          sub_node = create_node(segment, result_pool);
+          apr_hash_set(node->sub_nodes, sub_node->segment.data,
+                       sub_node->segment.len, sub_node);
+        }
     }
 
   /* Continue at the sub-node with the next segment. */
-  insert_path(sub_node, segments + 1, access, result_pool, scratch_pool);
+  insert_path(sub_node, segments + 1, allow_wildcards, access,
+              result_pool, scratch_pool);
 }
 
 /* Callback baton to be used with  process_path_rule().
@@ -487,6 +556,7 @@ process_path_rule(const char *name,
   access_t *access;
   svn_repos_authz_access_t rights;
   apr_array_header_t *segments;
+  svn_boolean_t wildcards;
 
   /* Is this section is relevant to the selected repository? */
   colon_pos = strchr(name, ':');
@@ -497,6 +567,9 @@ process_path_rule(const char *name,
 
   /* Ignore sections that are not path rules */
   path = colon_pos ? colon_pos + 1 : name;
+  wildcards = has_wildcards(path);
+  if (path[0] == '*')
+    ++path;
   if (path[0] != '/')
     return TRUE;
 
@@ -515,8 +588,8 @@ process_path_rule(const char *name,
   access->rights = rights;
 
   /* Insert the path rule into the filtered tree. */
-  insert_path(baton->root, (void *)segments->elts, access, baton->pool,
-              scratch_pool);
+  insert_path(baton->root, (void *)segments->elts, wildcards, access,
+              baton->pool, scratch_pool);
 
   return TRUE;
 }
@@ -550,6 +623,14 @@ finalize_tree(node_t *parent,
                       scratch_pool);
     }
 
+  /* Do the same thing for all other sub-nodes as well. */
+  if (node->pattern_sub_nodes)
+    {
+      if (node->pattern_sub_nodes->any)
+        finalize_tree(node, access, node->pattern_sub_nodes->any,
+                      scratch_pool);
+    }
+
   /* Add our min / max info to the parent's info.
    * Idempotent for parent == node (happens at root). */
   parent->max_rights |= node->max_rights;
@@ -825,6 +906,12 @@ lookup(lookup_state_t *state,
           if (node->sub_nodes)
             add_next_node(state, apr_hash_get(node->sub_nodes, segment->data,
                                               segment->len));
+
+          /* Process alternative, wildcard-based sub-nodes. */
+          if (node->pattern_sub_nodes)
+            {
+              add_next_node(state, node->pattern_sub_nodes->any);
+            }
         }
 
       /* The list of nodes for SEGMENT is now complete.
@@ -1119,6 +1206,9 @@ static svn_boolean_t authz_validate_sect
         fspath++;
       else
         fspath = name;
+      if (fspath[0] == '*')
+        ++fspath;
+
       if (! svn_fspath__is_canonical(fspath))
         {
           b->err = svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,


Reply via email to