Jon Foster wrote on Mon, Sep 20, 2010 at 11:01:02 +0100:
> Hi,
> 
> For atomic-revprop, the client needs to know if the error was
> SVN_ERR_BAD_OLD_VALUE or not.  For ra_local and ra_svn this is
> already done; this patch does it for DAV (with Neon).
> 
> 
> With mod_dav, we only have 2 ways to affect the 207 multistatus
> response from a failed PROPPATCH:
> 
> - We can set the text that appears in <D:responsedescription>,
>   including injecting arbitrary XML.
> - We can set the <D:status> value to a (numeric) HTTP error code.

There is also dav_svn__error_response_tag().

> 
> The approach that's been discussed on-list and on IRC was to
> inject the error as XML inside <D:responsedescription>.  I did
> actually implement that, only to discover that Neon completely
> rejects the XML in that case[1].  While we would obviously fix
> this in the 1.7 client code, it could break compatibility between
> the 1.7 server and 1.6 and older clients.  The only way to handle

In other words, changing that table means changing the protocol, which
isn't backwards-compatible.  Good call.

> this would be to introduce a new client capability, so the server
> could fall back to the old code for 1.6 clients.  This means we'd
> have two code paths for error-handling... this gets very complex.
> 
> 
> However, there is a simpler way!  The <D:status> element contains
> the HTTP error code, usually "500 Internal Server Error".  So we
> could pick a special HTTP status code to mean SVN_ERR_BAD_OLD_VALUE.
> I think of old_value_p as a precondition for the operation, a bit
> like "If-Modified-Since:", so I'd suggest "412 Precondition Failed".
> Note that generic DAV clients won't ever see this message, because
> they won't be sending old_value_p.
> 

Fair enough.  Are there currently any circumstances where
HTTP_PRECONDITION_FAILED would be raised?  (e.g., by mod_dav)

As far as I can tell (by greping httpd sources), the answer is "No".

> This patch only does mod_dav_svn and Neon.  I don't want to waste
> time doing both HTTP libraries if this patch is rejected.  (Also,
> Serf is slightly harder because it doesn't parse <D:status> yet).
> 
> The patch is against the atomic-revprop branch, and requires
> Patch 1 to be applied first.  (It does apply to trunk, too).
> 
> [[[
> Signal SVN_ERR_BAD_OLD_VALUE over DAV using a HTTP 412 status
> code inside a 207 multi-status response.
> 
> * subversion/mod_dav_svn/util.c:
>   (dav_svn__convert_err): Map SVN_ERR_BAD_OLD_VALUE to 412.
> 
> * subversion/libsvn_ra_neon/util.c:
>    (multistatus_baton_t): New member contains_precondition_error.
>    (end_207_element): Check for HTTP 412 status code and create
>                       a SVN_ERR_BAD_OLD_VALUE error if found.
> 
> Patch by: Jon Foster <jon.fos...@cabot.co.uk>
> ]]]
> 

Tested it and it works fine:

[[[
CMD: atomic-ra-revprop-change 
http://localhost:8081/svn-test-work/repositories/prop_tests-34 0 flower "( 11 
old_value_p 0  5 value 6 violet )" neon
CMD: 
/home/daniel/src/svn/atomic-revprop/subversion/tests/cmdline/atomic-ra-revprop-change
 http://localhost:8081/svn-test-work/repositories/prop_tests-34 0 flower ( 11 
old_value_p 0  5 value 6 violet ) neon exited with 1
<TIME = 0.305840>
subversion/tests/cmdline/atomic-ra-revprop-change.c:156: (apr_err=175002)
subversion/libsvn_ra_neon/fetch.c:1210: (apr_err=175002)
atomic-ra-revprop-change: DAV request failed; it's possible that the 
repository's pre-revprop-change hook either failed or is non-existent
subversion/libsvn_ra_neon/props.c:1231: (apr_err=175008)
atomic-ra-revprop-change: At least one property change failed; repository is 
unchanged
subversion/libsvn_ra_neon/util.c:1550: (apr_err=125014)
subversion/libsvn_ra_neon/util.c:236: (apr_err=125014)
atomic-ra-revprop-change: Error setting property 'flower': 
revprop 'flower' has unexpected value in filesystem
]]]

where 125014 is SVN_ERR_BAD_OLD_VALUE. :-)

I'll commit this once I have an ra_serf version too.  Would you like to
write the ra_serf part of the patch, too?

Thanks!

Daniel

> Kind regards,
> 
> Jon
> 
> 
> [1] More precisely, libsvn_ra_neon/util.c:wrapper_startelm_cb()
>     raises a SVN_ERR_XML_MALFORMED "XML data was not well-formed"
>     error if <D:responsedescription> contains any XML tags.  See
>     the ELEM_responsedescription row in multistatus_nesting_table[]
>     in the same file - it explicitly states that if there's any
>     XML tags inside <D:responsedescription> then the XML is invalid.
> 

> Index: subversion/mod_dav_svn/util.c
> ===================================================================
> --- subversion/mod_dav_svn/util.c     (revision 998620)
> +++ subversion/mod_dav_svn/util.c     (working copy)
> @@ -107,6 +107,9 @@
>        case SVN_ERR_FS_PATH_ALREADY_LOCKED:
>          status = HTTP_LOCKED;
>          break;
> +      case SVN_ERR_BAD_OLD_VALUE:
> +        status = HTTP_PRECONDITION_FAILED;
> +        break;
>          /* add other mappings here */
>        }
>  
> Index: subversion/libsvn_ra_neon/util.c
> ===================================================================
> --- subversion/libsvn_ra_neon/util.c  (revision 998620)
> +++ subversion/libsvn_ra_neon/util.c  (working copy)
> @@ -167,6 +167,7 @@
>    svn_ra_neon__request_t *req;
>    svn_stringbuf_t *description;
>    svn_boolean_t contains_error;
> +  svn_boolean_t contains_precondition_error;
>  } multistatus_baton_t;
>  
>  /* Implements svn_ra_neon__startelm_cb_t. */
> @@ -231,9 +232,12 @@
>              return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
>                                      _("The request response contained at 
> least "
>                                        "one error"));
> +          else if (b->contains_precondition_error) 
> +            return svn_error_create(SVN_ERR_BAD_OLD_VALUE, NULL,
> +                                    b->description->data);
>            else
>              return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
> -                                    b->description->data);
> +                                    *b->description->data);
                                      ^^^
Unintentional change?  (triggers compiler warning)

>          }
>        break;
>  
> @@ -260,6 +264,10 @@
>              else
>                b->propstat_has_error = (status.klass != 2);
>  
> +            /* Handle "412 Precondition Failed" specially */
> +            if (status.code == 412)
> +              b->contains_precondition_error = TRUE;
> +
>              free(status.reason_phrase);
>            }
>          else

Reply via email to