summaryrefslogtreecommitdiff
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/getlocks.c19
-rw-r--r--subversion/libsvn_ra_serf/inherited_props.c237
-rw-r--r--subversion/libsvn_ra_serf/locks.c45
-rw-r--r--subversion/libsvn_ra_serf/log.c2
-rw-r--r--subversion/libsvn_ra_serf/update.c19
5 files changed, 137 insertions, 185 deletions
diff --git a/subversion/libsvn_ra_serf/getlocks.c b/subversion/libsvn_ra_serf/getlocks.c
index 04e5561799361..df201a7506f55 100644
--- a/subversion/libsvn_ra_serf/getlocks.c
+++ b/subversion/libsvn_ra_serf/getlocks.c
@@ -116,6 +116,7 @@ getlocks_closed(svn_ra_serf__xml_estate_t *xes,
if (leaving_state == LOCK)
{
const char *path = svn_hash_gets(attrs, "path");
+ const char *token = svn_hash_gets(attrs, "token");
svn_boolean_t save_lock = FALSE;
/* Filter out unwanted paths. Since Subversion only allows
@@ -128,6 +129,12 @@ getlocks_closed(svn_ra_serf__xml_estate_t *xes,
c) we've asked for depth=files or depth=immediates, and this
lock is on an immediate child of our query path.
*/
+ if (! token)
+ {
+ /* A lock without a token is not a lock; just an answer that there
+ is no lock on the node. */
+ save_lock = FALSE;
+ }
if (strcmp(lock_ctx->path, path) == 0
|| lock_ctx->requested_depth == svn_depth_infinity)
{
@@ -154,7 +161,7 @@ getlocks_closed(svn_ra_serf__xml_estate_t *xes,
them may have not been sent, so the value will be NULL. */
lock.path = path;
- lock.token = svn_hash_gets(attrs, "token");
+ lock.token = token;
lock.owner = svn_hash_gets(attrs, "owner");
lock.comment = svn_hash_gets(attrs, "comment");
@@ -234,6 +241,7 @@ svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
const char *req_url, *rel_path;
+ svn_error_t *err;
req_url = svn_path_url_add_component2(session->session_url.path, path, pool);
SVN_ERR(svn_ra_serf__get_relative_path(&rel_path, req_url, session,
@@ -260,7 +268,14 @@ svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
handler->body_delegate = create_getlocks_body;
handler->body_delegate_baton = lock_ctx;
- SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
+ err = svn_ra_serf__context_run_one(handler, pool);
+
+ /* Wrap the server generated error for an unsupported report with the
+ documented error for this ra function. */
+ if (svn_error_find_cause(err, SVN_ERR_UNSUPPORTED_FEATURE))
+ err = svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err, NULL);
+
+ SVN_ERR(err);
/* We get a 404 when a path doesn't exist in HEAD, but it might
have existed earlier (E.g. 'svn ls http://s/svn/trunk/file@1' */
diff --git a/subversion/libsvn_ra_serf/inherited_props.c b/subversion/libsvn_ra_serf/inherited_props.c
index 54eae0b5be7cd..f1172e7b6815c 100644
--- a/subversion/libsvn_ra_serf/inherited_props.c
+++ b/subversion/libsvn_ra_serf/inherited_props.c
@@ -41,7 +41,7 @@
/* The current state of our XML parsing. */
typedef enum iprops_state_e {
- NONE = 0,
+ INITIAL = 0,
IPROPS_REPORT,
IPROPS_ITEM,
IPROPS_PATH,
@@ -61,18 +61,12 @@ typedef struct iprops_context_t {
/* The repository's root URL. */
const char *repos_root_url;
- /* Current CDATA values*/
- svn_stringbuf_t *curr_path;
+ /* Current property name */
svn_stringbuf_t *curr_propname;
- svn_stringbuf_t *curr_propval;
- const char *curr_prop_val_encoding;
/* Current element in IPROPS. */
svn_prop_inherited_item_t *curr_iprop;
- /* Serf context completion flag for svn_ra_serf__context_run_wait() */
- svn_boolean_t done;
-
/* Path we are finding inherited properties for. This is relative to
the RA session passed to svn_ra_serf__get_inherited_props. */
const char *path;
@@ -80,162 +74,121 @@ typedef struct iprops_context_t {
svn_revnum_t revision;
} iprops_context_t;
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t iprops_table[] = {
+ { INITIAL, S_, SVN_DAV__INHERITED_PROPS_REPORT, IPROPS_REPORT,
+ FALSE, { NULL }, FALSE },
+
+ { IPROPS_REPORT, S_, SVN_DAV__IPROP_ITEM, IPROPS_ITEM,
+ FALSE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PATH, IPROPS_PATH,
+ TRUE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPNAME, IPROPS_PROPNAME,
+ TRUE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPVAL, IPROPS_PROPVAL,
+ TRUE, { "?V:encoding", NULL }, TRUE },
+
+ { 0 }
+};
+
+/* Conforms to svn_ra_serf__xml_opened_t */
static svn_error_t *
-start_element(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
+iprops_opened(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int entered_state,
+ const svn_ra_serf__dav_props_t *tag,
apr_pool_t *scratch_pool)
{
- iprops_context_t *iprops_ctx = parser->user_data;
- iprops_state_e state;
+ iprops_context_t *iprops_ctx = baton;
- state = parser->state->current_state;
- if (state == NONE
- && strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
+ if (entered_state == IPROPS_ITEM)
{
- svn_ra_serf__xml_push_state(parser, IPROPS_REPORT);
- }
- else if (state == IPROPS_REPORT &&
- strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
- {
- svn_stringbuf_setempty(iprops_ctx->curr_path);
svn_stringbuf_setempty(iprops_ctx->curr_propname);
- svn_stringbuf_setempty(iprops_ctx->curr_propval);
- iprops_ctx->curr_prop_val_encoding = NULL;
- iprops_ctx->curr_iprop = NULL;
- svn_ra_serf__xml_push_state(parser, IPROPS_ITEM);
- }
- else if (state == IPROPS_ITEM &&
- strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
- {
- const char *prop_val_encoding = svn_xml_get_attr_value("encoding",
- attrs);
- iprops_ctx->curr_prop_val_encoding = apr_pstrdup(iprops_ctx->pool,
- prop_val_encoding);
- svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
- }
- else if (state == IPROPS_ITEM &&
- strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
- {
- svn_ra_serf__xml_push_state(parser, IPROPS_PATH);
- }
- else if (state == IPROPS_ITEM &&
- strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
- {
- svn_ra_serf__xml_push_state(parser, IPROPS_PROPNAME);
- }
- else if (state == IPROPS_ITEM &&
- strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
- {
- svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
- }
+ iprops_ctx->curr_iprop = apr_pcalloc(iprops_ctx->pool,
+ sizeof(*iprops_ctx->curr_iprop));
+
+ iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
+ }
return SVN_NO_ERROR;
}
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_element(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+iprops_closed(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int leaving_state,
+ const svn_string_t *cdata,
+ apr_hash_t *attrs,
+ apr_pool_t *scratch_pool)
{
- iprops_context_t *iprops_ctx = parser->user_data;
- iprops_state_e state;
-
- state = parser->state->current_state;
+ iprops_context_t *iprops_ctx = baton;
- if (state == IPROPS_REPORT &&
- strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
+ if (leaving_state == IPROPS_ITEM)
{
- svn_ra_serf__xml_pop_state(parser);
+ APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
+ iprops_ctx->curr_iprop;
+
+ iprops_ctx->curr_iprop = NULL;
}
- else if (state == IPROPS_PATH
- && strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
+ else if (leaving_state == IPROPS_PATH)
{
- iprops_ctx->curr_iprop = apr_palloc(
- iprops_ctx->pool, sizeof(svn_prop_inherited_item_t));
+ /* Every <iprop-item> has a single <iprop-path> */
+ if (iprops_ctx->curr_iprop->path_or_url)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
iprops_ctx->curr_iprop->path_or_url =
svn_path_url_add_component2(iprops_ctx->repos_root_url,
- iprops_ctx->curr_path->data,
+ cdata->data,
iprops_ctx->pool);
- iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
- svn_ra_serf__xml_pop_state(parser);
}
- else if (state == IPROPS_PROPVAL
- && strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
+ else if (leaving_state == IPROPS_PROPNAME)
{
- const svn_string_t *prop_val;
+ if (iprops_ctx->curr_propname->len)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
- if (iprops_ctx->curr_prop_val_encoding)
- {
- svn_string_t encoded_prop_val;
+ /* Store propname for value */
+ svn_stringbuf_set(iprops_ctx->curr_propname, cdata->data);
+ }
+ else if (leaving_state == IPROPS_PROPVAL)
+ {
+ const char *encoding;
+ const svn_string_t *val_str;
+
+ if (! iprops_ctx->curr_propname->len)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
- if (strcmp(iprops_ctx->curr_prop_val_encoding, "base64") != 0)
- return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+ encoding = svn_hash_gets(attrs, "V:encoding");
- encoded_prop_val.data = iprops_ctx->curr_propval->data;
- encoded_prop_val.len = iprops_ctx->curr_propval->len;
- prop_val = svn_base64_decode_string(&encoded_prop_val,
- iprops_ctx->pool);
+ if (encoding)
+ {
+ if (strcmp(encoding, "base64") != 0)
+ return svn_error_createf(SVN_ERR_XML_MALFORMED,
+ NULL,
+ _("Got unrecognized encoding '%s'"),
+ encoding);
+
+ /* Decode into the right pool. */
+ val_str = svn_base64_decode_string(cdata, iprops_ctx->pool);
}
else
{
- prop_val = svn_string_create_from_buf(iprops_ctx->curr_propval,
- iprops_ctx->pool);
+ /* Copy into the right pool. */
+ val_str = svn_string_dup(cdata, iprops_ctx->pool);
}
svn_hash_sets(iprops_ctx->curr_iprop->prop_hash,
apr_pstrdup(iprops_ctx->pool,
iprops_ctx->curr_propname->data),
- prop_val);
- /* Clear current propname and propval in the event there are
- multiple properties on the current path. */
+ val_str);
+ /* Clear current propname. */
svn_stringbuf_setempty(iprops_ctx->curr_propname);
- svn_stringbuf_setempty(iprops_ctx->curr_propval);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == IPROPS_PROPNAME
- && strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == IPROPS_ITEM
- && strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
- {
- APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
- iprops_ctx->curr_iprop;
- svn_ra_serf__xml_pop_state(parser);
- }
- return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
-cdata_handler(svn_ra_serf__xml_parser_t *parser,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- iprops_context_t *iprops_ctx = parser->user_data;
- iprops_state_e state = parser->state->current_state;
-
- switch (state)
- {
- case IPROPS_PATH:
- svn_stringbuf_appendbytes(iprops_ctx->curr_path, data, len);
- break;
-
- case IPROPS_PROPNAME:
- svn_stringbuf_appendbytes(iprops_ctx->curr_propname, data, len);
- break;
-
- case IPROPS_PROPVAL:
- svn_stringbuf_appendbytes(iprops_ctx->curr_propval, data, len);
- break;
-
- default:
- break;
}
+ else
+ SVN_ERR_MALFUNCTION(); /* Invalid transition table */
return SVN_NO_ERROR;
}
@@ -281,7 +234,7 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
iprops_context_t *iprops_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
const char *req_url;
SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
@@ -295,19 +248,20 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
SVN_ERR_ASSERT(session->repos_root_str);
iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
- iprops_ctx->done = FALSE;
iprops_ctx->repos_root_url = session->repos_root_str;
iprops_ctx->pool = result_pool;
- iprops_ctx->curr_path = svn_stringbuf_create_empty(scratch_pool);
iprops_ctx->curr_propname = svn_stringbuf_create_empty(scratch_pool);
- iprops_ctx->curr_propval = svn_stringbuf_create_empty(scratch_pool);
iprops_ctx->curr_iprop = NULL;
iprops_ctx->iprops = apr_array_make(result_pool, 1,
sizeof(svn_prop_inherited_item_t *));
iprops_ctx->path = path;
iprops_ctx->revision = revision;
- handler = apr_pcalloc(scratch_pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(iprops_table,
+ iprops_opened, iprops_closed, NULL,
+ iprops_ctx,
+ scratch_pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool);
handler->method = "REPORT";
handler->path = req_url;
@@ -318,18 +272,6 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
handler->body_type = "text/xml";
handler->handler_pool = scratch_pool;
- parser_ctx = apr_pcalloc(scratch_pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = scratch_pool;
- parser_ctx->user_data = iprops_ctx;
- parser_ctx->start = start_element;
- parser_ctx->end = end_element;
- parser_ctx->cdata = cdata_handler;
- parser_ctx->done = &iprops_ctx->done;
-
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
-
err = svn_ra_serf__context_run_one(handler, scratch_pool);
SVN_ERR(svn_error_compose_create(
svn_ra_serf__error_on_status(handler->sline,
@@ -337,8 +279,7 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
handler->location),
err));
- if (iprops_ctx->done)
- *iprops = iprops_ctx->iprops;
+ *iprops = iprops_ctx->iprops;
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_ra_serf/locks.c b/subversion/libsvn_ra_serf/locks.c
index db2d37125a00b..252c30182a5f5 100644
--- a/subversion/libsvn_ra_serf/locks.c
+++ b/subversion/libsvn_ra_serf/locks.c
@@ -156,11 +156,20 @@ locks_closed(svn_ra_serf__xml_estate_t *xes,
if (leaving_state == TIMEOUT)
{
- if (strcmp(cdata->data, "Infinite") == 0)
+ if (strcasecmp(cdata->data, "Infinite") == 0)
lock_ctx->lock->expiration_date = 0;
+ else if (strncasecmp(cdata->data, "Second-", 7) == 0)
+ {
+ unsigned n;
+ SVN_ERR(svn_cstring_atoui(&n, cdata->data+7));
+
+ lock_ctx->lock->expiration_date = apr_time_now() +
+ apr_time_from_sec(n);
+ }
else
- SVN_ERR(svn_time_from_cstring(&lock_ctx->lock->creation_date,
- cdata->data, lock_ctx->pool));
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("Invalid LOCK timeout value '%s'"),
+ cdata->data);
}
else if (leaving_state == HREF)
{
@@ -362,29 +371,30 @@ svn_error_t *
svn_ra_serf__get_lock(svn_ra_session_t *ra_session,
svn_lock_t **lock,
const char *path,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
+ apr_pool_t *scratch_pool = svn_pool_create(result_pool);
lock_info_t *lock_ctx;
const char *req_url;
svn_error_t *err;
- req_url = svn_path_url_add_component2(session->session_url.path, path, pool);
-
- lock_ctx = apr_pcalloc(pool, sizeof(*lock_ctx));
+ req_url = svn_path_url_add_component2(session->session_url.path, path,
+ scratch_pool);
- lock_ctx->pool = pool;
+ lock_ctx = apr_pcalloc(scratch_pool, sizeof(*lock_ctx));
+ lock_ctx->pool = result_pool;
lock_ctx->path = req_url;
- lock_ctx->lock = svn_lock_create(pool);
- lock_ctx->lock->path = apr_pstrdup(pool, path); /* be sure */
+ lock_ctx->lock = svn_lock_create(result_pool);
+ lock_ctx->lock->path = apr_pstrdup(result_pool, path);
xmlctx = svn_ra_serf__xml_context_create(locks_ttable,
NULL, locks_closed, NULL,
lock_ctx,
- pool);
- handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
+ scratch_pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool);
handler->method = "PROPFIND";
handler->path = req_url;
@@ -405,7 +415,7 @@ svn_ra_serf__get_lock(svn_ra_session_t *ra_session,
lock_ctx->handler = handler;
- err = svn_ra_serf__context_run_one(handler, pool);
+ err = svn_ra_serf__context_run_one(handler, scratch_pool);
err = determine_error(handler, err);
if (handler->sline.code == 404)
@@ -420,7 +430,12 @@ svn_ra_serf__get_lock(svn_ra_session_t *ra_session,
_("Server does not support locking features"));
}
- *lock = lock_ctx->lock;
+ if (lock_ctx->lock && lock_ctx->lock->token)
+ *lock = lock_ctx->lock;
+ else
+ *lock = NULL;
+
+ svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
@@ -574,7 +589,7 @@ svn_ra_serf__unlock(svn_ra_session_t *ra_session,
{
SVN_ERR(svn_ra_serf__get_lock(ra_session, &existing_lock, path,
iterpool));
- token = existing_lock->token;
+ token = existing_lock ? existing_lock->token : NULL;
if (!token)
{
err = svn_error_createf(SVN_ERR_RA_NOT_LOCKED, NULL,
diff --git a/subversion/libsvn_ra_serf/log.c b/subversion/libsvn_ra_serf/log.c
index 58a57d890ee42..02f2f2995e5fc 100644
--- a/subversion/libsvn_ra_serf/log.c
+++ b/subversion/libsvn_ra_serf/log.c
@@ -571,7 +571,7 @@ svn_ra_serf__get_log(svn_ra_session_t *ra_session,
/* At this point, we may have a deleted file. So, we'll match ra_neon's
* behavior and use the larger of start or end as our 'peg' rev.
*/
- peg_rev = (start > end) ? start : end;
+ peg_rev = (start == SVN_INVALID_REVNUM || start > end) ? start : end;
SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
session, NULL /* conn */,
diff --git a/subversion/libsvn_ra_serf/update.c b/subversion/libsvn_ra_serf/update.c
index 06a16c06effd5..88488ff206f52 100644
--- a/subversion/libsvn_ra_serf/update.c
+++ b/subversion/libsvn_ra_serf/update.c
@@ -329,9 +329,6 @@ struct report_context_t {
files/dirs? */
svn_boolean_t add_props_included;
- /* Path -> lock token mapping. */
- apr_hash_t *lock_path_tokens;
-
/* Path -> const char *repos_relpath mapping */
apr_hash_t *switched_paths;
@@ -2248,8 +2245,6 @@ end_report(svn_ra_serf__xml_parser_t *parser,
info->pool);
}
- info->lock_token = svn_hash_gets(ctx->lock_path_tokens, info->name);
-
if (info->lock_token && !info->fetch_props)
info->fetch_props = TRUE;
@@ -2578,13 +2573,6 @@ set_path(void *report_baton,
SVN_ERR(svn_io_file_write_full(report->body_file, buf->data, buf->len,
NULL, pool));
- if (lock_token)
- {
- svn_hash_sets(report->lock_path_tokens,
- apr_pstrdup(report->pool, path),
- apr_pstrdup(report->pool, lock_token));
- }
-
return SVN_NO_ERROR;
}
@@ -2660,12 +2648,6 @@ link_path(void *report_baton,
if (!*path)
report->root_is_switched = TRUE;
- if (lock_token)
- {
- svn_hash_sets(report->lock_path_tokens,
- path, apr_pstrdup(report->pool, lock_token));
- }
-
return APR_SUCCESS;
}
@@ -3193,7 +3175,6 @@ make_update_reporter(svn_ra_session_t *ra_session,
report->ignore_ancestry = ignore_ancestry;
report->send_copyfrom_args = send_copyfrom_args;
report->text_deltas = text_deltas;
- report->lock_path_tokens = apr_hash_make(report->pool);
report->switched_paths = apr_hash_make(report->pool);
report->source = src_path;