http://subversion.tigris.org/issues/show_bug.cgi?id=3085

The issue is that when a pre-revprop-change hook fails mod_dav_svn
runs the hook a second time but with a different property change.
This means that the message returned to the user doesn't contain the
correct hook error output.

The reason for this is that mod_dav has a rollback mechanism.  When a
reprop is changed mod_dav first calls mod_dav_svn to setup for
rollback, then it calls mod_dav_svn a second time to make the change,
and if the change fails it calls mod_dav_svn a third time to rollback
the change.

If I patch mod_dav_svn to make the rollback into a no-op then I get
the expected behaviour, the hook runs once and the change succeeds or
fails.  It also fixes the problem that when a post-revprop-change
hook fails it reverts the successful change.

There is however one problem: the message returned to the client no
longer contains the hook output.  This is because when mod_dav_svn
returns an the hook error to mod_dav then mod_dav creates it's own
generic PROPPATCH failed error and returns that to the user.  Before I
made rollback a no-op the rollback could return an error that was
generated after mod_dav's generic PROPPATCH error and that gets
returned to thwe client.

I can be sneaky and work around this.  When the hook fails mod_dav_svn
can cache the error, and then when rollback gets invoked the cached
error can be returned even though rollback is otherwise a no-op.

What do people think?  I suppose the proper solution is to change
mod_dav to return Subversion's error but then users would need to
coordinate upgrades to both mod_dav_svn and mod_dav.

Proof of principle patch:

Index: subversion/mod_dav_svn/deadprops.c
===================================================================
--- subversion/mod_dav_svn/deadprops.c  (revision 947740)
+++ subversion/mod_dav_svn/deadprops.c  (working copy)
@@ -218,6 +218,8 @@
                                                db->authz_read_func,
                                                db->authz_read_baton,
                                                resource->pool);
+          if (serr)
+            resource->info->revprop_error = svn_error_dup(serr);
 
           /* Tell the logging subsystem about the revprop change. */
           dav_svn__operational_log(resource->info,
@@ -681,12 +683,20 @@
 static dav_error *
 db_apply_rollback(dav_db *db, dav_deadprop_rollback *rollback)
 {
+#if 0
   if (rollback->value.data == NULL)
     {
       return db_remove(db, &rollback->name);
     }
 
   return save_value(db, &rollback->name, &rollback->value);
+#endif
+  db->props = NULL;
+  if (db->resource->info->revprop_error)
+    return dav_svn__convert_err(db->resource->info->revprop_error,
+                                HTTP_INTERNAL_SERVER_ERROR, NULL,
+                                db->resource->pool);
+  return NULL;
 }
 
 
Index: subversion/mod_dav_svn/dav_svn.h
===================================================================
--- subversion/mod_dav_svn/dav_svn.h    (revision 947740)
+++ subversion/mod_dav_svn/dav_svn.h    (working copy)
@@ -271,6 +271,8 @@
      interface (ie: /path/to/item?p=PEGREV]? */
   svn_boolean_t pegged;
 
+  svn_error_t *revprop_error;
+
   /* Pool to allocate temporary data from */
   apr_pool_t *pool;
 };
 
-- 
Philip

Reply via email to