summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_serf/getlocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_serf/getlocks.c')
-rw-r--r--subversion/libsvn_ra_serf/getlocks.c338
1 files changed, 129 insertions, 209 deletions
diff --git a/subversion/libsvn_ra_serf/getlocks.c b/subversion/libsvn_ra_serf/getlocks.c
index 719e4f0..df201a7 100644
--- a/subversion/libsvn_ra_serf/getlocks.c
+++ b/subversion/libsvn_ra_serf/getlocks.c
@@ -27,6 +27,7 @@
#include <serf.h>
+#include "svn_hash.h"
#include "svn_path.h"
#include "svn_pools.h"
#include "svn_ra.h"
@@ -46,8 +47,8 @@
/*
* This enum represents the current state of our XML parsing for a REPORT.
*/
-typedef enum lock_state_e {
- NONE = 0,
+enum {
+ INITIAL = 0,
REPORT,
LOCK,
PATH,
@@ -56,19 +57,7 @@ typedef enum lock_state_e {
COMMENT,
CREATION_DATE,
EXPIRATION_DATE
-} lock_state_e;
-
-typedef struct lock_info_t {
- /* Temporary pool */
- apr_pool_t *pool;
-
- svn_lock_t *lock;
-
- /* The currently collected value as we build it up */
- const char *tmp;
- apr_size_t tmp_len;
-
-} lock_info_t;
+};
typedef struct lock_context_t {
apr_pool_t *pool;
@@ -80,107 +69,56 @@ typedef struct lock_context_t {
/* return hash */
apr_hash_t *hash;
- /* are we done? */
- svn_boolean_t done;
-
} lock_context_t;
-
-static lock_info_t *
-push_state(svn_ra_serf__xml_parser_t *parser,
- lock_context_t *lock_ctx,
- lock_state_e state)
-{
- svn_ra_serf__xml_push_state(parser, state);
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t getlocks_ttable[] = {
+ { INITIAL, S_, "get-locks-report", REPORT,
+ FALSE, { NULL }, FALSE },
- if (state == LOCK)
- {
- lock_info_t *info;
+ { REPORT, S_, "lock", LOCK,
+ FALSE, { NULL }, TRUE },
- info = apr_pcalloc(parser->state->pool, sizeof(*info));
+ { LOCK, S_, "path", PATH,
+ TRUE, { NULL }, TRUE },
- info->pool = lock_ctx->pool;
- info->lock = svn_lock_create(lock_ctx->pool);
- info->lock->path =
+ { LOCK, S_, "token", TOKEN,
+ TRUE, { NULL }, TRUE },
- parser->state->private = info;
- }
+ { LOCK, S_, "owner", OWNER,
+ TRUE, { NULL }, TRUE },
- return parser->state->private;
-}
+ { LOCK, S_, "comment", COMMENT,
+ TRUE, { NULL }, TRUE },
-static svn_error_t *
-start_getlocks(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name,
- const char **attrs)
-{
- lock_context_t *lock_ctx = userData;
- lock_state_e state;
+ { LOCK, S_, SVN_DAV__CREATIONDATE, CREATION_DATE,
+ TRUE, { NULL }, TRUE },
- state = parser->state->current_state;
+ { LOCK, S_, "expirationdate", EXPIRATION_DATE,
+ TRUE, { NULL }, TRUE },
- if (state == NONE &&
- strcmp(name.name, "get-locks-report") == 0)
- {
- push_state(parser, lock_ctx, REPORT);
- }
- else if (state == REPORT &&
- strcmp(name.name, "lock") == 0)
- {
- push_state(parser, lock_ctx, LOCK);
- }
- else if (state == LOCK)
- {
- if (strcmp(name.name, "path") == 0)
- {
- push_state(parser, lock_ctx, PATH);
- }
- else if (strcmp(name.name, "token") == 0)
- {
- push_state(parser, lock_ctx, TOKEN);
- }
- else if (strcmp(name.name, "owner") == 0)
- {
- push_state(parser, lock_ctx, OWNER);
- }
- else if (strcmp(name.name, "comment") == 0)
- {
- push_state(parser, lock_ctx, COMMENT);
- }
- else if (strcmp(name.name, SVN_DAV__CREATIONDATE) == 0)
- {
- push_state(parser, lock_ctx, CREATION_DATE);
- }
- else if (strcmp(name.name, "expirationdate") == 0)
- {
- push_state(parser, lock_ctx, EXPIRATION_DATE);
- }
- }
-
- return SVN_NO_ERROR;
-}
+ { 0 }
+};
+
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_getlocks(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name)
+getlocks_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)
{
- lock_context_t *lock_ctx = userData;
- lock_state_e state;
- lock_info_t *info;
-
- state = parser->state->current_state;
- info = parser->state->private;
+ lock_context_t *lock_ctx = baton;
- if (state == REPORT &&
- strcmp(name.name, "get-locks-report") == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == LOCK &&
- strcmp(name.name, "lock") == 0)
+ 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
locks on files, we can treat depth=immediates the same as
depth=files for filtering purposes. Meaning, we'll keep
@@ -191,106 +129,84 @@ end_getlocks(svn_ra_serf__xml_parser_t *parser,
c) we've asked for depth=files or depth=immediates, and this
lock is on an immediate child of our query path.
*/
- if ((strcmp(lock_ctx->path, info->lock->path) == 0)
- || (lock_ctx->requested_depth == svn_depth_infinity))
+ if (! token)
{
- apr_hash_set(lock_ctx->hash, info->lock->path,
- APR_HASH_KEY_STRING, info->lock);
+ /* A lock without a token is not a lock; just an answer that there
+ is no lock on the node. */
+ save_lock = FALSE;
}
- else if ((lock_ctx->requested_depth == svn_depth_files) ||
- (lock_ctx->requested_depth == svn_depth_immediates))
+ if (strcmp(lock_ctx->path, path) == 0
+ || lock_ctx->requested_depth == svn_depth_infinity)
{
- const char *rel_path = svn_fspath__is_child(lock_ctx->path,
- info->lock->path,
- info->pool);
- if (rel_path && (svn_path_component_count(rel_path) == 1))
- apr_hash_set(lock_ctx->hash, info->lock->path,
- APR_HASH_KEY_STRING, info->lock);
+ save_lock = TRUE;
+ }
+ else if (lock_ctx->requested_depth == svn_depth_files
+ || lock_ctx->requested_depth == svn_depth_immediates)
+ {
+ const char *relpath = svn_fspath__skip_ancestor(lock_ctx->path,
+ path);
+ if (relpath && (svn_path_component_count(relpath) == 1))
+ save_lock = TRUE;
}
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PATH &&
- strcmp(name.name, "path") == 0)
- {
- info->lock->path = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len);
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == TOKEN &&
- strcmp(name.name, "token") == 0)
- {
- info->lock->token = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len);
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == OWNER &&
- strcmp(name.name, "owner") == 0)
- {
- info->lock->owner = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len);
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == COMMENT &&
- strcmp(name.name, "comment") == 0)
- {
- info->lock->comment = apr_pstrmemdup(info->pool,
- info->tmp, info->tmp_len);
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == CREATION_DATE &&
- strcmp(name.name, SVN_DAV__CREATIONDATE) == 0)
- {
- SVN_ERR(svn_time_from_cstring(&info->lock->creation_date,
- info->tmp, info->pool));
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
+ if (save_lock)
+ {
+ /* We get to put the structure on the stack rather than using
+ svn_lock_create(). Bwahahaha.... */
+ svn_lock_t lock = { 0 };
+ const char *date;
+ svn_lock_t *result_lock;
+
+ /* Note: these "attributes" came from child elements. Some of
+ them may have not been sent, so the value will be NULL. */
+
+ lock.path = path;
+ lock.token = token;
+ lock.owner = svn_hash_gets(attrs, "owner");
+ lock.comment = svn_hash_gets(attrs, "comment");
+
+ date = svn_hash_gets(attrs, SVN_DAV__CREATIONDATE);
+ if (date)
+ SVN_ERR(svn_time_from_cstring(&lock.creation_date, date,
+ scratch_pool));
+
+ date = svn_hash_gets(attrs, "expirationdate");
+ if (date)
+ SVN_ERR(svn_time_from_cstring(&lock.expiration_date, date,
+ scratch_pool));
+
+ result_lock = svn_lock_dup(&lock, lock_ctx->pool);
+ svn_hash_sets(lock_ctx->hash, result_lock->path, result_lock);
+ }
}
- else if (state == EXPIRATION_DATE &&
- strcmp(name.name, "expirationdate") == 0)
+ else
{
- SVN_ERR(svn_time_from_cstring(&info->lock->expiration_date,
- info->tmp, info->pool));
- info->tmp_len = 0;
- svn_ra_serf__xml_pop_state(parser);
+ const char *name;
+
+ SVN_ERR_ASSERT(cdata != NULL);
+
+ if (leaving_state == PATH)
+ name = "path";
+ else if (leaving_state == TOKEN)
+ name = "token";
+ else if (leaving_state == OWNER)
+ name = "owner";
+ else if (leaving_state == COMMENT)
+ name = "comment";
+ else if (leaving_state == CREATION_DATE)
+ name = SVN_DAV__CREATIONDATE;
+ else if (leaving_state == EXPIRATION_DATE)
+ name = "expirationdate";
+ else
+ SVN_ERR_MALFUNCTION();
+
+ /* Store the lock information onto the LOCK elemstate. */
+ svn_ra_serf__xml_note(xes, LOCK, name, cdata->data);
}
return SVN_NO_ERROR;
}
-static svn_error_t *
-cdata_getlocks(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- const char *data,
- apr_size_t len)
-{
- lock_context_t *lock_ctx = userData;
- lock_state_e state;
- lock_info_t *info;
-
- UNUSED_CTX(lock_ctx);
-
- state = parser->state->current_state;
- info = parser->state->private;
-
- switch (state)
- {
- case PATH:
- case TOKEN:
- case OWNER:
- case COMMENT:
- case CREATION_DATE:
- case EXPIRATION_DATE:
- svn_ra_serf__expand_string(&info->tmp, &info->tmp_len,
- data, len, parser->state->pool);
- break;
- default:
- break;
- }
-
- return SVN_NO_ERROR;
-}
/* Implements svn_ra_serf__request_body_delegate_t */
static svn_error_t *
@@ -323,9 +239,9 @@ svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
lock_context_t *lock_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, *rel_path;
- int status_code;
+ 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,
@@ -336,9 +252,12 @@ svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
lock_ctx->path = apr_pstrcat(pool, "/", rel_path, (char *)NULL);
lock_ctx->requested_depth = depth;
lock_ctx->hash = apr_hash_make(pool);
- lock_ctx->done = FALSE;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(getlocks_ttable,
+ NULL, getlocks_closed, NULL,
+ lock_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "REPORT";
handler->path = req_url;
@@ -346,25 +265,26 @@ svn_ra_serf__get_locks(svn_ra_session_t *ra_session,
handler->conn = session->conns[0];
handler->session = session;
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = pool;
- parser_ctx->user_data = lock_ctx;
- parser_ctx->start = start_getlocks;
- parser_ctx->end = end_getlocks;
- parser_ctx->cdata = cdata_getlocks;
- parser_ctx->done = &lock_ctx->done;
- parser_ctx->status_code = &status_code;
-
handler->body_delegate = create_getlocks_body;
handler->body_delegate_baton = lock_ctx;
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
-
- svn_ra_serf__request_create(handler);
-
- SVN_ERR(svn_ra_serf__context_run_wait(&lock_ctx->done, session, 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' */
+ if (handler->sline.code != 404)
+ {
+ SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location));
+ }
*locks = lock_ctx->hash;