Daniel Shahaf wrote:
> Jon Foster wrote on Mon, Sep 20, 2010 at 11:01:02 +0100:
> > 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".
I looked and couldn't find any. The DAV spec doesn't list it as
one of the common errors that get sent in that place. (Obviously,
it would be very bad if mod_dav started sending that error code
for some other error).
> 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?
Sure. See attached.
> > - b->description->data);
> > + *b->description->data);
> ^^^
> Unintentional change? (triggers compiler warning)
Oops, yes. Fixed in attached.
This updated patch is against the atomic-revprop branch.
[[[
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.
* subversion/libsvn_ra_serf/ra_serf.h:
(svn_ra_serf__server_error_t): New member
contains_precondition_error.
* subversion/libsvn_ra_serf/util.c:
(parse_dav_status): New method.
(svn_ra_serf__handle_discard_body): Initialise new member.
(start_207): Parse DAV:status XML element.
(end_207): Parse DAV:status XML element. Use SVN_ERR_BAD_OLD_VALUE
error code if applicable.
(svn_ra_serf__handle_multistatus_only): Initialise new member.
Patch by: Jon Foster <jon.fos...@cabot.co.uk>
]]]
Kind regards,
Jon
**********************************************************************
This email and its attachments may be confidential and are intended solely for
the use of the individual to whom it is addressed. Any views or opinions
expressed are solely those of the author and do not necessarily represent those
of Cabot Communications Ltd.
If you are not the intended recipient of this email and its attachments, you
must take no action based upon them, nor must you copy or show them to anyone.
Cabot Communications Limited
Verona House, Filwood Road, Bristol BS16 3RY, UK
+44 (0) 1179584232
Co. Registered in England number 02817269
Please contact the sender if you believe you have received this email in error.
**********************************************************************
______________________________________________________________________
This email has been scanned by the MessageLabs Email Security System.
For more information please visit http://www.messagelabs.com/email
______________________________________________________________________
Index: subversion/mod_dav_svn/util.c
===================================================================
--- subversion/mod_dav_svn/util.c (revision 999102)
+++ subversion/mod_dav_svn/util.c (working copy)
@@ -107,6 +107,9 @@ dav_svn__convert_err(svn_error_t *serr,
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 999102)
+++ subversion/libsvn_ra_neon/util.c (working copy)
@@ -167,6 +167,7 @@ typedef struct
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,6 +232,9 @@ end_207_element(void *baton, int state,
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);
@@ -260,6 +264,10 @@ end_207_element(void *baton, int state,
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
Index: subversion/libsvn_ra_serf/util.c
===================================================================
--- subversion/libsvn_ra_serf/util.c (revision 999102)
+++ subversion/libsvn_ra_serf/util.c (working copy)
@@ -836,6 +836,7 @@ svn_ra_serf__handle_discard_body(serf_request_t *r
{
server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL);
server_err->has_xml_response = TRUE;
+ server_err->contains_precondition_error = FALSE;
server_err->cdata = svn_stringbuf_create("", pool);
server_err->collect_cdata = FALSE;
server_err->parser.pool = server_err->error->pool;
@@ -945,6 +946,31 @@ svn_ra_serf__handle_status_only(serf_request_t *re
return svn_error_return(err);
}
+/* Given a string like "HTTP/1.1 500 (status)", parse out the numeric status
+ code. Ignores leading whitespace. This function will overwrite and then
+ clear the passed buf. */
+static svn_error_t *
+parse_dav_status(svn_stringbuf_t *buf, int *status_code_out)
+{
+ svn_error_t * err;
+ const char * token;
+ char * tok_status = 0;
+
+ svn_stringbuf_strip_whitespace(buf);
+ token = apr_strtok(buf->data, " \t\r\n", &tok_status);
+ if (token)
+ token = apr_strtok(NULL, " \t\r\n", &tok_status);
+ if (!token)
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ "Malformed DAV:status CDATA");
+ err = svn_cstring_atoi(status_code_out, token);
+ if (err)
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, err,
+ "Malformed DAV:status CDATA");
+ svn_stringbuf_setempty(buf);
+ return SVN_NO_ERROR;
+}
+
/*
* Expat callback invoked on a start element tag for a 207 response.
*/
@@ -968,6 +994,14 @@ start_207(svn_ra_serf__xml_parser_t *parser,
svn_stringbuf_setempty(ctx->cdata);
ctx->collect_cdata = TRUE;
}
+ else if (ctx->in_error &&
+ strcmp(name.namespace, "DAV:") == 0 &&
+ strcmp(name.name, "status") == 0)
+ {
+ /* Start collecting cdata. */
+ svn_stringbuf_setempty(ctx->cdata);
+ ctx->collect_cdata = TRUE;
+ }
return SVN_NO_ERROR;
}
@@ -993,9 +1027,24 @@ end_207(svn_ra_serf__xml_parser_t *parser,
ctx->collect_cdata = FALSE;
ctx->error->message = apr_pstrmemdup(ctx->error->pool, ctx->cdata->data,
ctx->cdata->len);
- ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
+ if (ctx->contains_precondition_error)
+ ctx->error->apr_err = SVN_ERR_BAD_OLD_VALUE;
+ else
+ ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
}
+ else if (ctx->in_error &&
+ strcmp(name.namespace, "DAV:") == 0 &&
+ strcmp(name.name, "status") == 0)
+ {
+ int status_code;
+ ctx->collect_cdata = FALSE;
+
+ SVN_ERR(parse_dav_status(ctx->cdata, &status_code));
+ if (status_code == 412)
+ ctx->contains_precondition_error = TRUE;
+ }
+
return SVN_NO_ERROR;
}
@@ -1044,6 +1093,7 @@ svn_ra_serf__handle_multistatus_only(serf_request_
{
server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL);
server_err->has_xml_response = TRUE;
+ server_err->contains_precondition_error = FALSE;
server_err->cdata = svn_stringbuf_create("", pool);
server_err->collect_cdata = FALSE;
server_err->parser.pool = server_err->error->pool;
Index: subversion/libsvn_ra_serf/ra_serf.h
===================================================================
--- subversion/libsvn_ra_serf/ra_serf.h (revision 999102)
+++ subversion/libsvn_ra_serf/ra_serf.h (working copy)
@@ -673,6 +673,9 @@ typedef struct svn_ra_serf__server_error_t {
/* Have we seen an error tag? */
svn_boolean_t in_error;
+ /* Have we seen a HTTP "412 Precondition Failed" error? */
+ svn_boolean_t contains_precondition_error;
+
/* Should we be collecting the XML cdata? */
svn_boolean_t collect_cdata;