summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_ra_serf
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_serf')
-rw-r--r--subversion/libsvn_ra_serf/commit.c25
-rw-r--r--subversion/libsvn_ra_serf/ra_serf.h12
-rw-r--r--subversion/libsvn_ra_serf/replay.c37
-rw-r--r--subversion/libsvn_ra_serf/serf.c29
-rw-r--r--subversion/libsvn_ra_serf/util.c261
5 files changed, 244 insertions, 120 deletions
diff --git a/subversion/libsvn_ra_serf/commit.c b/subversion/libsvn_ra_serf/commit.c
index 56a2bce..9682a65 100644
--- a/subversion/libsvn_ra_serf/commit.c
+++ b/subversion/libsvn_ra_serf/commit.c
@@ -397,10 +397,18 @@ checkout_dir(dir_context_t *dir,
{
if (p_dir->added)
{
+ /* Calculate the working_url by skipping the shared ancestor bewteen
+ * the parent->relpath and dir->relpath. This is safe since an
+ * add is guaranteed to have a parent that is checked out. */
+ dir_context_t *parent = p_dir->parent_dir;
+ const char *relpath = svn_relpath_skip_ancestor(parent->relpath,
+ dir->relpath);
+
/* Implicitly checkout this dir now. */
+ SVN_ERR_ASSERT(parent->working_url);
dir->working_url = svn_path_url_add_component2(
- dir->parent_dir->working_url,
- dir->name, dir->pool);
+ parent->working_url,
+ relpath, dir->pool);
return SVN_NO_ERROR;
}
p_dir = p_dir->parent_dir;
@@ -1924,7 +1932,18 @@ add_file(const char *path,
if (handler->sline.code != 404)
{
- return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
+ if (handler->sline.code != 200)
+ {
+ svn_error_t *err;
+
+ err = svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location);
+
+ SVN_ERR(err);
+ }
+
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
_("File '%s' already exists"), path);
}
}
diff --git a/subversion/libsvn_ra_serf/ra_serf.h b/subversion/libsvn_ra_serf/ra_serf.h
index f6310b3..335a9e3 100644
--- a/subversion/libsvn_ra_serf/ra_serf.h
+++ b/subversion/libsvn_ra_serf/ra_serf.h
@@ -57,13 +57,6 @@ extern "C" {
/** Use this to silence compiler warnings about unused parameters. */
#define UNUSED_CTX(x) ((void)(x))
-/** Our User-Agent string. */
-#define USER_AGENT "SVN/" SVN_VER_NUMBER " (" SVN_BUILD_TARGET ")" \
- " serf/" \
- APR_STRINGIFY(SERF_MAJOR_VERSION) "." \
- APR_STRINGIFY(SERF_MINOR_VERSION) "." \
- APR_STRINGIFY(SERF_PATCH_VERSION)
-
/** Wait duration (in microseconds) used in calls to serf_context_run() */
#define SVN_RA_SERF__CONTEXT_RUN_DURATION 500000
@@ -658,11 +651,6 @@ struct svn_ra_serf__xml_parser_t {
See libsvn_ra_serf/util.c */
struct svn_ra_serf__pending_t *pending;
-
- /* Response restart support */
- const void *headers_baton; /* Last pointer to headers */
- apr_off_t skip_size; /* Number of bytes to skip */
- apr_off_t read_size; /* Number of bytes read from response */
};
diff --git a/subversion/libsvn_ra_serf/replay.c b/subversion/libsvn_ra_serf/replay.c
index 2d385f3..66e2f58 100644
--- a/subversion/libsvn_ra_serf/replay.c
+++ b/subversion/libsvn_ra_serf/replay.c
@@ -90,8 +90,6 @@ typedef struct prop_info_t {
typedef struct replay_context_t {
apr_pool_t *src_rev_pool;
apr_pool_t *dst_rev_pool;
- /*file_pool is cleared after completion of each file. */
- apr_pool_t *file_pool;
/* Are we done fetching this file? */
svn_boolean_t done;
@@ -147,10 +145,11 @@ push_state(svn_ra_serf__xml_parser_t *parser,
state == OPEN_FILE || state == ADD_FILE)
{
replay_info_t *info;
+ apr_pool_t *pool = svn_pool_create(replay_ctx->dst_rev_pool);
- info = apr_palloc(replay_ctx->dst_rev_pool, sizeof(*info));
+ info = apr_palloc(pool, sizeof(*info));
- info->pool = replay_ctx->dst_rev_pool;
+ info->pool = pool;
info->parent = parser->state->private;
info->baton = NULL;
info->stream = NULL;
@@ -160,12 +159,13 @@ push_state(svn_ra_serf__xml_parser_t *parser,
else if (state == CHANGE_PROP)
{
prop_info_t *info;
+ apr_pool_t *pool = svn_pool_create(replay_ctx->dst_rev_pool);
- info = apr_pcalloc(replay_ctx->dst_rev_pool, sizeof(*info));
+ info = apr_pcalloc(pool, sizeof(*info));
- info->pool = replay_ctx->dst_rev_pool;
+ info->pool = pool;
info->parent = parser->state->private;
- info->prop_value = svn_stringbuf_create_empty(info->pool);
+ info->prop_value = svn_stringbuf_create_empty(pool);
parser->state->private = info;
}
@@ -194,7 +194,6 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
/* Create a pool for the commit editor. */
ctx->dst_rev_pool = svn_pool_create(ctx->src_rev_pool);
- ctx->file_pool = svn_pool_create(ctx->dst_rev_pool);
SVN_ERR(svn_ra_serf__select_revprops(&ctx->props,
ctx->revprop_target,
@@ -334,6 +333,8 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
SVN_ERR(ctx->editor->close_directory(info->baton, scratch_pool));
svn_ra_serf__xml_pop_state(parser);
+
+ svn_pool_destroy(info->pool);
}
else if ((state == OPEN_DIR || state == ADD_DIR) &&
strcmp(name.name, "open-file") == 0)
@@ -341,7 +342,6 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
const char *file_name, *rev;
replay_info_t *info;
- svn_pool_clear(ctx->file_pool);
file_name = svn_xml_get_attr_value("name", attrs);
if (!file_name)
{
@@ -359,7 +359,7 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
SVN_ERR(ctx->editor->open_file(file_name, info->parent->baton,
SVN_STR_TO_REV(rev),
- ctx->file_pool, &info->baton));
+ info->pool, &info->baton));
}
else if ((state == OPEN_DIR || state == ADD_DIR) &&
strcmp(name.name, "add-file") == 0)
@@ -368,7 +368,6 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
svn_revnum_t rev;
replay_info_t *info;
- svn_pool_clear(ctx->file_pool);
file_name = svn_xml_get_attr_value("name", attrs);
if (!file_name)
{
@@ -387,7 +386,7 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
SVN_ERR(ctx->editor->add_file(file_name, info->parent->baton,
copyfrom, rev,
- ctx->file_pool, &info->baton));
+ info->pool, &info->baton));
}
else if ((state == OPEN_FILE || state == ADD_FILE) &&
strcmp(name.name, "apply-textdelta") == 0)
@@ -407,7 +406,7 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
}
SVN_ERR(ctx->editor->apply_textdelta(info->baton, checksum,
- ctx->file_pool,
+ info->pool,
&textdelta,
&textdelta_baton));
@@ -426,6 +425,8 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
SVN_ERR(ctx->editor->close_file(info->baton, checksum, scratch_pool));
svn_ra_serf__xml_pop_state(parser);
+
+ svn_pool_destroy(info->pool);
}
else if (((state == OPEN_FILE || state == ADD_FILE) &&
strcmp(name.name, "change-file-prop") == 0) ||
@@ -451,14 +452,13 @@ start_replay(svn_ra_serf__xml_parser_t *parser,
else
info->del_prop = FALSE;
+ info->name = apr_pstrdup(info->pool, prop_name);
if (state == OPEN_FILE || state == ADD_FILE)
{
- info->name = apr_pstrdup(ctx->file_pool, prop_name);
info->change = ctx->editor->change_file_prop;
}
else
{
- info->name = apr_pstrdup(ctx->dst_rev_pool, prop_name);
info->change = ctx->editor->change_dir_prop;
}
@@ -538,15 +538,14 @@ end_replay(svn_ra_serf__xml_parser_t *parser,
info->prop_value = NULL; /* morph killed the stringbuf. */
#endif
- if (strcmp(name.name, "change-file-prop") == 0)
- prop_val = svn_base64_decode_string(morph, ctx->file_pool);
- else
- prop_val = svn_base64_decode_string(morph, ctx->dst_rev_pool);
+ prop_val = svn_base64_decode_string(morph, info->pool);
}
SVN_ERR(info->change(info->parent->baton, info->name, prop_val,
info->parent->pool));
svn_ra_serf__xml_pop_state(parser);
+
+ svn_pool_destroy(info->pool);
}
return SVN_NO_ERROR;
diff --git a/subversion/libsvn_ra_serf/serf.c b/subversion/libsvn_ra_serf/serf.c
index b0b6346..66f9962 100644
--- a/subversion/libsvn_ra_serf/serf.c
+++ b/subversion/libsvn_ra_serf/serf.c
@@ -61,11 +61,18 @@ ra_serf_version(void)
#define RA_SERF_DESCRIPTION \
N_("Module for accessing a repository via WebDAV protocol using serf.")
+#define RA_SERF_DESCRIPTION_VER \
+ N_("Module for accessing a repository via WebDAV protocol using serf.\n" \
+ " - using serf %d.%d.%d")
+
/* Implements svn_ra__vtable_t.get_description(). */
static const char *
-ra_serf_get_description(void)
+ra_serf_get_description(apr_pool_t *pool)
{
- return _(RA_SERF_DESCRIPTION);
+ int major, minor, patch;
+
+ serf_lib_version(&major, &minor, &patch);
+ return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER), major, minor, patch);
}
/* Implements svn_ra__vtable_t.get_schemes(). */
@@ -413,6 +420,18 @@ svn_ra_serf__progress(void *progress_baton, apr_off_t read, apr_off_t written)
}
}
+/** Our User-Agent string. */
+static const char *
+get_user_agent_string(apr_pool_t *pool)
+{
+ int major, minor, patch;
+ serf_lib_version(&major, &minor, &patch);
+
+ return apr_psprintf(pool, "SVN/%s (%s) serf/%d.%d.%d",
+ SVN_VER_NUMBER, SVN_BUILD_TARGET,
+ major, minor, patch);
+}
+
/* Implements svn_ra__vtable_t.open_session(). */
static svn_error_t *
svn_ra_serf__open(svn_ra_session_t *session,
@@ -495,10 +514,10 @@ svn_ra_serf__open(svn_ra_session_t *session,
SVN_ERR(callbacks->get_client_string(callback_baton, &client_string, pool));
if (client_string)
- serf_sess->useragent = apr_pstrcat(pool, USER_AGENT, " ",
+ serf_sess->useragent = apr_pstrcat(pool, get_user_agent_string(pool), " ",
client_string, (char *)NULL);
else
- serf_sess->useragent = USER_AGENT;
+ serf_sess->useragent = get_user_agent_string(pool);
/* go ahead and tell serf about the connection. */
status =
@@ -1260,7 +1279,7 @@ svn_ra_serf__init(const svn_version_t *loader_version,
int serf_minor;
int serf_patch;
- SVN_ERR(svn_ver_check_list(ra_serf_version(), checklist));
+ SVN_ERR(svn_ver_check_list2(ra_serf_version(), checklist, svn_ver_equal));
/* Simplified version check to make sure we can safely use the
VTABLE parameter. The RA loader does a more exhaustive check. */
diff --git a/subversion/libsvn_ra_serf/util.c b/subversion/libsvn_ra_serf/util.c
index ce1e31a..55efca4 100644
--- a/subversion/libsvn_ra_serf/util.c
+++ b/subversion/libsvn_ra_serf/util.c
@@ -191,13 +191,65 @@ construct_realm(svn_ra_serf__session_t *session,
static char *
convert_organisation_to_str(apr_hash_t *org, apr_pool_t *pool)
{
- return apr_psprintf(pool, "%s, %s, %s, %s, %s (%s)",
- (char*)svn_hash_gets(org, "OU"),
- (char*)svn_hash_gets(org, "O"),
- (char*)svn_hash_gets(org, "L"),
- (char*)svn_hash_gets(org, "ST"),
- (char*)svn_hash_gets(org, "C"),
- (char*)svn_hash_gets(org, "E"));
+ const char *org_unit = svn_hash_gets(org, "OU");
+ const char *org_name = svn_hash_gets(org, "O");
+ const char *locality = svn_hash_gets(org, "L");
+ const char *state = svn_hash_gets(org, "ST");
+ const char *country = svn_hash_gets(org, "C");
+ const char *email = svn_hash_gets(org, "E");
+ svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool);
+
+ if (org_unit)
+ {
+ svn_stringbuf_appendcstr(buf, org_unit);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (org_name)
+ {
+ svn_stringbuf_appendcstr(buf, org_name);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (locality)
+ {
+ svn_stringbuf_appendcstr(buf, locality);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (state)
+ {
+ svn_stringbuf_appendcstr(buf, state);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (country)
+ {
+ svn_stringbuf_appendcstr(buf, country);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ /* Chop ', ' if any. */
+ svn_stringbuf_chop(buf, 2);
+
+ if (email)
+ {
+ svn_stringbuf_appendcstr(buf, "(");
+ svn_stringbuf_appendcstr(buf, email);
+ svn_stringbuf_appendcstr(buf, ")");
+ }
+
+ return buf->data;
+}
+
+static void append_reason(svn_stringbuf_t *errmsg, const char *reason, int *reasons)
+{
+ if (*reasons < 1)
+ svn_stringbuf_appendcstr(errmsg, _(": "));
+ else
+ svn_stringbuf_appendcstr(errmsg, _(", "));
+ svn_stringbuf_appendcstr(errmsg, reason);
+ (*reasons)++;
}
/* This function is called on receiving a ssl certificate of a server when
@@ -258,11 +310,12 @@ ssl_server_cert(void *baton, int failures,
for (i = 0; i < san->nelts; i++) {
char *s = APR_ARRAY_IDX(san, i, char*);
if (apr_fnmatch(s, conn->session->session_url.hostname,
- APR_FNM_PERIOD) == APR_SUCCESS) {
+ APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
+ {
found_matching_hostname = 1;
cert_info.hostname = s;
break;
- }
+ }
}
}
@@ -270,7 +323,7 @@ ssl_server_cert(void *baton, int failures,
if (!found_matching_hostname && cert_info.hostname)
{
if (apr_fnmatch(cert_info.hostname, conn->session->session_url.hostname,
- APR_FNM_PERIOD) == APR_FNM_NOMATCH)
+ APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
{
svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
}
@@ -301,7 +354,35 @@ ssl_server_cert(void *baton, int failures,
SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
if (!server_creds)
- return svn_error_create(SVN_ERR_RA_SERF_SSL_CERT_UNTRUSTED, NULL, NULL);
+ {
+ svn_stringbuf_t *errmsg;
+ int reasons = 0;
+
+ errmsg = svn_stringbuf_create(
+ _("Server SSL certificate verification failed"),
+ scratch_pool);
+
+
+ if (svn_failures & SVN_AUTH_SSL_NOTYETVALID)
+ append_reason(errmsg, _("certificate is not yet valid"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_EXPIRED)
+ append_reason(errmsg, _("certificate has expired"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_CNMISMATCH)
+ append_reason(errmsg,
+ _("certificate issued for a different hostname"),
+ &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_UNKNOWNCA)
+ append_reason(errmsg, _("issuer is not trusted"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_OTHER)
+ append_reason(errmsg, _("and other reason(s)"), &reasons);
+
+ return svn_error_create(SVN_ERR_RA_SERF_SSL_CERT_UNTRUSTED, NULL,
+ errmsg->data);
+ }
return SVN_NO_ERROR;
}
@@ -746,8 +827,6 @@ svn_ra_serf__context_run_wait(svn_boolean_t *done,
the connection timed out. */
if (APR_STATUS_IS_TIMEUP(status))
{
- svn_error_clear(err);
- err = SVN_NO_ERROR;
status = 0;
if (sess->timeout)
@@ -758,8 +837,11 @@ svn_ra_serf__context_run_wait(svn_boolean_t *done,
}
else
{
- return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
- _("Connection timed out"));
+ return
+ svn_error_compose_create(
+ err,
+ svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+ _("Connection timed out")));
}
}
}
@@ -805,6 +887,23 @@ svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler,
/* Wait until the response logic marks its DONE status. */
err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
scratch_pool);
+
+ /* A callback invocation has been canceled. In this simple case of
+ context_run_one, we can keep the ra-session operational by resetting
+ the connection.
+
+ If we don't do this, the next context run will notice that the connection
+ is still in the error state and will just return SVN_ERR_CEASE_INVOCATION
+ (=the last error for the connection) again */
+ if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+ {
+ apr_status_t status = serf_connection_reset(handler->conn->conn);
+
+ if (status)
+ err = svn_error_compose_create(err,
+ svn_ra_serf__wrap_err(status, NULL));
+ }
+
if (handler->server_error)
{
err = svn_error_compose_create(err, handler->server_error->error);
@@ -1388,19 +1487,22 @@ inject_to_parser(svn_ra_serf__xml_parser_t *ctx,
int xml_status;
xml_status = XML_Parse(ctx->xmlp, data, (int) len, 0);
- if (xml_status == XML_STATUS_ERROR && !ctx->ignore_errors)
+
+ if (! ctx->ignore_errors)
{
- if (sl == NULL)
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("XML parsing failed"));
+ SVN_ERR(ctx->error);
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("XML parsing failed: (%d %s)"),
- sl->code, sl->reason);
- }
+ if (xml_status != XML_STATUS_OK)
+ {
+ if (sl == NULL)
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed"));
- if (ctx->error && !ctx->ignore_errors)
- return svn_error_trace(ctx->error);
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed: (%d %s)"),
+ sl->code, sl->reason);
+ }
+ }
return SVN_NO_ERROR;
}
@@ -1481,14 +1583,26 @@ svn_ra_serf__process_pending(svn_ra_serf__xml_parser_t *parser,
if (pending_empty &&
parser->pending->network_eof)
{
+ int xml_status;
SVN_ERR_ASSERT(parser->xmlp != NULL);
- /* Tell the parser that no more content will be parsed. Ignore the
- return status. We just don't care. */
- (void) XML_Parse(parser->xmlp, NULL, 0, 1);
+ /* Tell the parser that no more content will be parsed. */
+ xml_status = XML_Parse(parser->xmlp, NULL, 0, 1);
apr_pool_cleanup_run(parser->pool, &parser->xmlp, xml_parser_cleanup);
parser->xmlp = NULL;
+
+ if (! parser->ignore_errors)
+ {
+ SVN_ERR(parser->error);
+
+ if (xml_status != XML_STATUS_OK)
+ {
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed"));
+ }
+ }
+
add_done_item(parser);
}
@@ -1588,22 +1702,6 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
return svn_error_trace(err);
}
- if (ctx->headers_baton == NULL)
- ctx->headers_baton = serf_bucket_response_get_headers(response);
- else if (ctx->headers_baton != serf_bucket_response_get_headers(response))
- {
- /* We got a new response to an existing parser...
- This tells us the connection has restarted and we should continue
- where we stopped last time.
- */
-
- /* Is this a second attempt?? */
- if (!ctx->skip_size)
- ctx->skip_size = ctx->read_size;
-
- ctx->read_size = 0; /* New request, nothing read */
- }
-
if (!ctx->xmlp)
{
ctx->xmlp = XML_ParserCreate(NULL);
@@ -1623,41 +1721,11 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
apr_size_t len;
status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
-
if (SERF_BUCKET_READ_ERROR(status))
{
return svn_ra_serf__wrap_err(status, NULL);
}
- ctx->read_size += len;
-
- if (ctx->skip_size)
- {
- /* Handle restarted requests correctly: Skip what we already read */
- apr_size_t skip;
-
- if (ctx->skip_size >= ctx->read_size)
- {
- /* Eek. What did the file shrink or something? */
- if (APR_STATUS_IS_EOF(status))
- {
- SVN_ERR_MALFUNCTION();
- }
-
- /* Skip on to the next iteration of this loop. */
- if (APR_STATUS_IS_EAGAIN(status))
- {
- return svn_ra_serf__wrap_err(status, NULL);
- }
- continue;
- }
-
- skip = (apr_size_t)(len - (ctx->read_size - ctx->skip_size));
- data += skip;
- len -= skip;
- ctx->skip_size = 0;
- }
-
/* Note: once the callbacks invoked by inject_to_parser() sets the
PAUSED flag, then it will not be cleared. write_to_pending() will
only save the content. Logic outside of serf_context_run() will
@@ -1703,12 +1771,25 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
in the PENDING structures, then we're completely done. */
if (!HAS_PENDING_DATA(ctx->pending))
{
+ int xml_status;
SVN_ERR_ASSERT(ctx->xmlp != NULL);
- /* Ignore the return status. We just don't care. */
- (void) XML_Parse(ctx->xmlp, NULL, 0, 1);
+ xml_status = XML_Parse(ctx->xmlp, NULL, 0, 1);
apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
+
+ if (! ctx->ignore_errors)
+ {
+ SVN_ERR(ctx->error);
+
+ if (xml_status != XML_STATUS_OK)
+ {
+ return svn_error_create(
+ SVN_ERR_XML_MALFORMED, NULL,
+ _("The XML response contains invalid XML"));
+ }
+ }
+
add_done_item(ctx);
}
@@ -1828,12 +1909,26 @@ handle_response(serf_request_t *request,
{
/* Uh-oh. Our connection died. */
if (handler->response_error)
- SVN_ERR(handler->response_error(request, response, 0,
- handler->response_error_baton));
+ {
+ /* Give a handler chance to prevent request requeue. */
+ SVN_ERR(handler->response_error(request, response, 0,
+ handler->response_error_baton));
- /* Requeue another request for this handler.
- ### how do we know if the handler can deal with this?! */
- svn_ra_serf__request_create(handler);
+ svn_ra_serf__request_create(handler);
+ }
+ /* Response error callback is not configured. Requeue another request
+ for this handler only if we didn't started to process body.
+ Return error otherwise. */
+ else if (!handler->reading_body)
+ {
+ svn_ra_serf__request_create(handler);
+ }
+ else
+ {
+ return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("%s request on '%s' failed"),
+ handler->method, handler->path);
+ }
return SVN_NO_ERROR;
}
@@ -2417,6 +2512,10 @@ svn_ra_serf__error_on_status(serf_status_line sline,
"server or an intermediate proxy does not accept "
"chunked encoding. Try setting 'http-chunked-requests' "
"to 'auto' or 'no' in your client configuration."));
+ case 501:
+ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("The requested feature is not supported by "
+ "'%s'"), path);
}
if (sline.code >= 300)
OpenPOWER on IntegriCloud