Index: subversion/mod_dav_svn/util.c =================================================================== --- subversion/mod_dav_svn/util.c (revision 999170) +++ 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_FS_PROP_BASEVALUE_MISMATCH: + status = HTTP_PRECONDITION_FAILED; + break; /* add other mappings here */ } Index: subversion/libsvn_ra_neon/util.c =================================================================== --- subversion/libsvn_ra_neon/util.c (revision 999170) +++ 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_FS_PROP_BASEVALUE_MISMATCH, 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 999170) +++ 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,34 @@ svn_ra_serf__handle_status_only(serf_request_t *re return svn_error_return(err); } +/* Given a string like "HTTP/1.1 500 (status)" in BUF, parse out the numeric + status code into *STATUS_CODE_OUT. Ignores leading whitespace. */ +static svn_error_t * +parse_dav_status(int *status_code_out, svn_stringbuf_t *buf, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + const char *token; + char *tok_status; + svn_stringbuf_t *temp_buf = svn_stringbuf_dup(buf, scratch_pool); + + svn_stringbuf_strip_whitespace(temp_buf); + token = apr_strtok(temp_buf->data, " \t\r\n", &tok_status); + if (token) + token = apr_strtok(NULL, " \t\r\n", &tok_status); + if (!token) + return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, + "Malformed DAV:status CDATA '%s'", + buf->data); + err = svn_cstring_atoi(status_code_out, token); + if (err) + return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, err, + "Malformed DAV:status CDATA '%s'", + buf->data); + + return SVN_NO_ERROR; +} + /* * Expat callback invoked on a start element tag for a 207 response. */ @@ -968,6 +997,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 +1030,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_FS_PROP_BASEVALUE_MISMATCH; + 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(&status_code, ctx->cdata, parser->pool)); + if (status_code == 412) + ctx->contains_precondition_error = TRUE; + } + return SVN_NO_ERROR; } @@ -1044,6 +1096,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 999170) +++ 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;