You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2012/08/16 12:18:03 UTC
svn commit: r1373783 [19/50] - in /subversion/branches/compressed-pristines:
./ build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/client-side/emacs/ contrib/client-side/svn-push/
contrib/client-side/svnmerge/ cont...
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/mergeinfo.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/mergeinfo.c Thu Aug 16 10:17:48 2012
@@ -40,7 +40,7 @@
/* The current state of our XML parsing. */
typedef enum mergeinfo_state_e {
- NONE = 0,
+ INITIAL = 0,
MERGEINFO_REPORT,
MERGEINFO_ITEM,
MERGEINFO_PATH,
@@ -49,135 +49,88 @@ typedef enum mergeinfo_state_e {
/* Baton for accumulating mergeinfo. RESULT_CATALOG stores the final
mergeinfo catalog result we are going to hand back to the caller of
- get_mergeinfo. curr_path and curr_info contain the value of the
- CDATA from the mergeinfo items as we get them from the server. */
-
+ get_mergeinfo. */
typedef struct mergeinfo_context_t {
apr_pool_t *pool;
- svn_stringbuf_t *curr_path;
- svn_stringbuf_t *curr_info;
svn_mergeinfo_t result_catalog;
- svn_boolean_t done;
const apr_array_header_t *paths;
svn_revnum_t revision;
svn_mergeinfo_inheritance_t inherit;
svn_boolean_t include_descendants;
} mergeinfo_context_t;
-static svn_error_t *
-start_element(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- mergeinfo_context_t *mergeinfo_ctx = parser->user_data;
- mergeinfo_state_e state;
- state = parser->state->current_state;
- if (state == NONE && strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0)
- {
- svn_ra_serf__xml_push_state(parser, MERGEINFO_REPORT);
- }
- else if (state == MERGEINFO_REPORT &&
- strcmp(name.name, SVN_DAV__MERGEINFO_ITEM) == 0)
- {
- svn_ra_serf__xml_push_state(parser, MERGEINFO_ITEM);
- svn_stringbuf_setempty(mergeinfo_ctx->curr_path);
- svn_stringbuf_setempty(mergeinfo_ctx->curr_info);
- }
- else if (state == MERGEINFO_ITEM &&
- strcmp(name.name, SVN_DAV__MERGEINFO_PATH) == 0)
- {
- svn_ra_serf__xml_push_state(parser, MERGEINFO_PATH);
- }
- else if (state == MERGEINFO_ITEM &&
- strcmp(name.name, SVN_DAV__MERGEINFO_INFO) == 0)
- {
- svn_ra_serf__xml_push_state(parser, MERGEINFO_INFO);
- }
- return SVN_NO_ERROR;
-}
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t mergeinfo_ttable[] = {
+ { INITIAL, S_, SVN_DAV__MERGEINFO_REPORT, MERGEINFO_REPORT,
+ FALSE, { NULL }, FALSE },
+
+ { MERGEINFO_REPORT, S_, SVN_DAV__MERGEINFO_ITEM, MERGEINFO_ITEM,
+ FALSE, { NULL }, TRUE },
+
+ { MERGEINFO_ITEM, S_, SVN_DAV__MERGEINFO_PATH, MERGEINFO_PATH,
+ TRUE, { NULL }, TRUE },
+
+ { MERGEINFO_ITEM, S_, SVN_DAV__MERGEINFO_INFO, MERGEINFO_INFO,
+ TRUE, { NULL }, TRUE },
+
+ { 0 }
+};
+
+/* 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)
+mergeinfo_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)
{
- mergeinfo_context_t *mergeinfo_ctx = parser->user_data;
- mergeinfo_state_e state;
-
- state = parser->state->current_state;
+ mergeinfo_context_t *mergeinfo_ctx = baton;
- if (state == MERGEINFO_REPORT &&
- strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0)
+ if (leaving_state == MERGEINFO_ITEM)
{
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == MERGEINFO_ITEM
- && strcmp(name.name, SVN_DAV__MERGEINFO_ITEM) == 0)
- {
- if (mergeinfo_ctx->curr_info && mergeinfo_ctx->curr_path)
+ /* Placed here from the child elements. */
+ const char *path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING);
+ const char *info = apr_hash_get(attrs, "info", APR_HASH_KEY_STRING);
+
+ if (path != NULL && info != NULL)
{
svn_mergeinfo_t path_mergeinfo;
- const char *path;
- SVN_ERR_ASSERT(mergeinfo_ctx->curr_path->data);
- path = apr_pstrdup(mergeinfo_ctx->pool,
- mergeinfo_ctx->curr_path->data);
- SVN_ERR(svn_mergeinfo_parse(&path_mergeinfo,
- mergeinfo_ctx->curr_info->data,
- mergeinfo_ctx->pool));
/* Correct for naughty servers that send "relative" paths
with leading slashes! */
+ if (path[0] == '/')
+ ++path;
+
+ SVN_ERR(svn_mergeinfo_parse(&path_mergeinfo, info,
+ mergeinfo_ctx->pool));
+
apr_hash_set(mergeinfo_ctx->result_catalog,
- path[0] == '/' ? path + 1 : path,
- APR_HASH_KEY_STRING, path_mergeinfo);
+ apr_pstrdup(mergeinfo_ctx->pool, path),
+ APR_HASH_KEY_STRING,
+ path_mergeinfo);
}
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == MERGEINFO_PATH
- && strcmp(name.name, SVN_DAV__MERGEINFO_PATH) == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
}
- else if (state == MERGEINFO_INFO
- && strcmp(name.name, SVN_DAV__MERGEINFO_INFO) == 0)
- {
- 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)
-{
- mergeinfo_context_t *mergeinfo_ctx = parser->user_data;
- mergeinfo_state_e state;
-
- state = parser->state->current_state;
- switch (state)
+ else
{
- case MERGEINFO_PATH:
- if (mergeinfo_ctx->curr_path)
- svn_stringbuf_appendbytes(mergeinfo_ctx->curr_path, data, len);
- break;
-
- case MERGEINFO_INFO:
- if (mergeinfo_ctx->curr_info)
- svn_stringbuf_appendbytes(mergeinfo_ctx->curr_info, data, len);
- break;
+ SVN_ERR_ASSERT(leaving_state == MERGEINFO_PATH
+ || leaving_state == MERGEINFO_INFO);
- default:
- break;
+ /* Stash the value onto the parent MERGEINFO_ITEM. */
+ svn_ra_serf__xml_note(xes, MERGEINFO_ITEM,
+ leaving_state == MERGEINFO_PATH
+ ? "path"
+ : "info",
+ cdata->data);
}
return SVN_NO_ERROR;
}
+
static svn_error_t *
create_mergeinfo_body(serf_bucket_t **bkt,
void *baton,
@@ -229,8 +182,6 @@ create_mergeinfo_body(serf_bucket_t **bk
return SVN_NO_ERROR;
}
-/* Request a mergeinfo-report from the URL attached to SESSION,
- and fill in the MERGEINFO hash with the results. */
svn_error_t *
svn_ra_serf__get_mergeinfo(svn_ra_session_t *ra_session,
svn_mergeinfo_catalog_t *catalog,
@@ -241,34 +192,32 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
apr_pool_t *pool)
{
svn_error_t *err, *err2;
- int status_code;
-
mergeinfo_context_t *mergeinfo_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
- const char *relative_url, *basecoll_url;
+ svn_ra_serf__xml_context_t *xmlctx;
const char *path;
*catalog = NULL;
- SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
- NULL, NULL, revision, NULL, pool));
-
- path = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+ SVN_ERR(svn_ra_serf__get_stable_url(&path, NULL /* latest_revnum */,
+ session, NULL /* conn */,
+ NULL /* url */, revision,
+ pool, pool));
mergeinfo_ctx = apr_pcalloc(pool, sizeof(*mergeinfo_ctx));
mergeinfo_ctx->pool = pool;
- mergeinfo_ctx->curr_path = svn_stringbuf_create_empty(pool);
- mergeinfo_ctx->curr_info = svn_stringbuf_create_empty(pool);
- mergeinfo_ctx->done = FALSE;
mergeinfo_ctx->result_catalog = apr_hash_make(pool);
mergeinfo_ctx->paths = paths;
mergeinfo_ctx->revision = revision;
mergeinfo_ctx->inherit = inherit;
mergeinfo_ctx->include_descendants = include_descendants;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(mergeinfo_ttable,
+ NULL, mergeinfo_closed, NULL,
+ mergeinfo_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "REPORT";
handler->path = path;
@@ -278,25 +227,10 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
handler->body_delegate_baton = mergeinfo_ctx;
handler->body_type = "text/xml";
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = pool;
- parser_ctx->user_data = mergeinfo_ctx;
- parser_ctx->start = start_element;
- parser_ctx->end = end_element;
- parser_ctx->cdata = cdata_handler;
- parser_ctx->done = &mergeinfo_ctx->done;
- parser_ctx->status_code = &status_code;
-
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
-
- svn_ra_serf__request_create(handler);
-
- err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool);
+ err = svn_ra_serf__context_run_one(handler, pool);
- err2 = svn_ra_serf__error_on_status(status_code, handler->path,
- parser_ctx->location);
+ err2 = svn_ra_serf__error_on_status(handler->sline.code, handler->path,
+ handler->location);
if (err2)
{
svn_error_clear(err);
@@ -305,7 +239,7 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
SVN_ERR(err);
- if (mergeinfo_ctx->done && apr_hash_count(mergeinfo_ctx->result_catalog))
+ if (handler->done && apr_hash_count(mergeinfo_ctx->result_catalog))
*catalog = mergeinfo_ctx->result_catalog;
return SVN_NO_ERROR;
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c Thu Aug 16 10:17:48 2012
@@ -48,165 +48,68 @@
/*
* This enum represents the current state of our XML parsing for an OPTIONS.
*/
-typedef enum options_state_e {
+enum options_state_e {
+ INITIAL = 0,
OPTIONS,
ACTIVITY_COLLECTION,
HREF
-} options_state_e;
-
-typedef struct options_state_list_t {
- /* The current state that we are in now. */
- options_state_e state;
-
- /* The previous state we were in. */
- struct options_state_list_t *prev;
-} options_state_list_t;
+};
-struct svn_ra_serf__options_context_t {
+typedef struct options_context_t {
/* pool to allocate memory from */
apr_pool_t *pool;
- /* Buffer for the activity-collection */
- svn_stringbuf_t *acbuf;
- svn_boolean_t collect_cdata;
-
- /* Current state we're in */
- options_state_list_t *state;
- options_state_list_t *free_state;
-
- /* HTTP Status code */
- int status_code;
-
- /* are we done? */
- svn_boolean_t done;
+ /* Have we extracted options values from the headers already? */
+ svn_boolean_t headers_processed;
svn_ra_serf__session_t *session;
svn_ra_serf__connection_t *conn;
+ svn_ra_serf__handler_t *handler;
- const char *path;
+ svn_ra_serf__response_handler_t inner_handler;
+ void *inner_baton;
const char *activity_collection;
svn_revnum_t youngest_rev;
- serf_response_acceptor_t acceptor;
- serf_response_handler_t handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+} options_context_t;
-};
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t options_ttable[] = {
+ { INITIAL, D_, "options-response", OPTIONS,
+ FALSE, { NULL }, FALSE },
-static void
-push_state(svn_ra_serf__options_context_t *options_ctx, options_state_e state)
-{
- options_state_list_t *new_state;
+ { OPTIONS, D_, "activity-collection-set", ACTIVITY_COLLECTION,
+ FALSE, { NULL }, FALSE },
- if (!options_ctx->free_state)
- {
- new_state = apr_palloc(options_ctx->pool, sizeof(*options_ctx->state));
- }
- else
- {
- new_state = options_ctx->free_state;
- options_ctx->free_state = options_ctx->free_state->prev;
- }
- new_state->state = state;
+ { ACTIVITY_COLLECTION, D_, "href", HREF,
+ TRUE, { NULL }, TRUE },
- /* Add it to the state chain. */
- new_state->prev = options_ctx->state;
- options_ctx->state = new_state;
-}
-
-static void pop_state(svn_ra_serf__options_context_t *options_ctx)
-{
- options_state_list_t *free_state;
- free_state = options_ctx->state;
- /* advance the current state */
- options_ctx->state = options_ctx->state->prev;
- free_state->prev = options_ctx->free_state;
- options_ctx->free_state = free_state;
-}
-
-static svn_error_t *
-start_options(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__options_context_t *options_ctx = parser->user_data;
-
- if (!options_ctx->state && strcmp(name.name, "options-response") == 0)
- {
- push_state(options_ctx, OPTIONS);
- }
- else if (!options_ctx->state)
- {
- /* Nothing to do. */
- return SVN_NO_ERROR;
- }
- else if (options_ctx->state->state == OPTIONS &&
- strcmp(name.name, "activity-collection-set") == 0)
- {
- push_state(options_ctx, ACTIVITY_COLLECTION);
- }
- else if (options_ctx->state->state == ACTIVITY_COLLECTION &&
- strcmp(name.name, "href") == 0)
- {
- options_ctx->collect_cdata = TRUE;
- push_state(options_ctx, HREF);
- }
+ { 0 }
+};
- return SVN_NO_ERROR;
-}
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_options(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+options_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)
{
- svn_ra_serf__options_context_t *options_ctx = parser->user_data;
- options_state_list_t *cur_state;
-
- if (!options_ctx->state)
- {
- return SVN_NO_ERROR;
- }
+ options_context_t *opt_ctx = baton;
- cur_state = options_ctx->state;
+ SVN_ERR_ASSERT(leaving_state == HREF);
+ SVN_ERR_ASSERT(cdata != NULL);
- if (cur_state->state == OPTIONS &&
- strcmp(name.name, "options-response") == 0)
- {
- pop_state(options_ctx);
- }
- else if (cur_state->state == ACTIVITY_COLLECTION &&
- strcmp(name.name, "activity-collection-set") == 0)
- {
- pop_state(options_ctx);
- }
- else if (cur_state->state == HREF &&
- strcmp(name.name, "href") == 0)
- {
- options_ctx->collect_cdata = FALSE;
- options_ctx->activity_collection =
- svn_urlpath__canonicalize(options_ctx->acbuf->data, options_ctx->pool);
- pop_state(options_ctx);
- }
+ opt_ctx->activity_collection = svn_urlpath__canonicalize(cdata->data,
+ opt_ctx->pool);
return SVN_NO_ERROR;
}
-static svn_error_t *
-cdata_options(svn_ra_serf__xml_parser_t *parser,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__options_context_t *ctx = parser->user_data;
-
- if (ctx->collect_cdata)
- svn_stringbuf_appendbytes(ctx->acbuf, data, len);
-
- return SVN_NO_ERROR;
-}
static svn_error_t *
create_options_body(serf_bucket_t **body_bkt,
@@ -227,47 +130,17 @@ create_options_body(serf_bucket_t **body
return SVN_NO_ERROR;
}
-svn_boolean_t*
-svn_ra_serf__get_options_done_ptr(svn_ra_serf__options_context_t *ctx)
-{
- return &ctx->done;
-}
-
-const char *
-svn_ra_serf__options_get_activity_collection(svn_ra_serf__options_context_t *ctx)
-{
- return ctx->activity_collection;
-}
-
-svn_revnum_t
-svn_ra_serf__options_get_youngest_rev(svn_ra_serf__options_context_t *ctx)
-{
- return ctx->youngest_rev;
-}
-
-/* Context for both options_response_handler() and capabilities callback. */
-struct options_response_ctx_t {
- /* Baton for __handle_xml_parser() */
- svn_ra_serf__xml_parser_t *parser_ctx;
-
- /* Session into which we'll store server capabilities */
- svn_ra_serf__session_t *session;
-
- /* For temporary work only. */
- apr_pool_t *pool;
-};
-
/* We use these static pointers so we can employ pointer comparison
* of our capabilities hash members instead of strcmp()ing all over
* the place.
*/
/* Both server and repository support the capability. */
-static const char *capability_yes = "yes";
+static const char *const capability_yes = "yes";
/* Either server or repository does not support the capability. */
-static const char *capability_no = "no";
+static const char *const capability_no = "no";
/* Server supports the capability, but don't yet know if repository does. */
-static const char *capability_server_yes = "server-yes";
+static const char *const capability_server_yes = "server-yes";
/* This implements serf_bucket_headers_do_callback_fn_t.
@@ -277,7 +150,8 @@ capabilities_headers_iterator_callback(v
const char *key,
const char *val)
{
- struct options_response_ctx_t *orc = baton;
+ options_context_t *opt_ctx = baton;
+ svn_ra_serf__session_t *session = opt_ctx->session;
if (svn_cstring_casecmp(key, "dav") == 0)
{
@@ -285,7 +159,8 @@ capabilities_headers_iterator_callback(v
DAV: version-control,checkout,working-resource
DAV: merge,baseline,activity,version-controlled-collection
DAV: http://subversion.tigris.org/xmlns/dav/svn/depth */
- apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE, orc->pool);
+ apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
+ opt_ctx->pool);
/* Right now we only have a few capabilities to detect, so just
seek for them directly. This could be written slightly more
@@ -294,33 +169,35 @@ capabilities_headers_iterator_callback(v
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals))
{
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
- APR_HASH_KEY_STRING, capability_yes);
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_DEPTH, APR_HASH_KEY_STRING,
+ capability_yes);
}
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals))
{
/* The server doesn't know what repository we're referring
to, so it can't just say capability_yes. */
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_server_yes);
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING,
+ capability_server_yes);
}
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_LOG_REVPROPS,
- APR_HASH_KEY_STRING, capability_yes);
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_LOG_REVPROPS, APR_HASH_KEY_STRING,
+ capability_yes);
}
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS, vals))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
- APR_HASH_KEY_STRING, capability_yes);
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_ATOMIC_REVPROPS, APR_HASH_KEY_STRING,
+ capability_yes);
}
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_PARTIAL_REPLAY,
- APR_HASH_KEY_STRING, capability_yes);
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_PARTIAL_REPLAY, APR_HASH_KEY_STRING,
+ capability_yes);
}
}
@@ -329,14 +206,12 @@ capabilities_headers_iterator_callback(v
{
if (svn_cstring_casecmp(key, SVN_DAV_ROOT_URI_HEADER) == 0)
{
- orc->session->repos_root = orc->session->session_url;
- orc->session->repos_root.path = apr_pstrdup(orc->session->pool, val);
- orc->session->repos_root_str =
+ session->repos_root = session->session_url;
+ session->repos_root.path = apr_pstrdup(session->pool, val);
+ session->repos_root_str =
svn_urlpath__canonicalize(
- apr_uri_unparse(orc->session->pool,
- &orc->session->repos_root,
- 0),
- orc->session->pool);
+ apr_uri_unparse(session->pool, &session->repos_root, 0),
+ session->pool);
}
else if (svn_cstring_casecmp(key, SVN_DAV_ME_RESOURCE_HEADER) == 0)
{
@@ -345,44 +220,42 @@ capabilities_headers_iterator_callback(v
if (!(ignore_v2_env_var
&& apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0))
- orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
+ session->me_resource = apr_pstrdup(session->pool, val);
#else
- orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
+ session->me_resource = apr_pstrdup(session->pool, val);
#endif
}
else if (svn_cstring_casecmp(key, SVN_DAV_REV_STUB_HEADER) == 0)
{
- orc->session->rev_stub = apr_pstrdup(orc->session->pool, val);
+ session->rev_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_REV_ROOT_STUB_HEADER) == 0)
{
- orc->session->rev_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->rev_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_TXN_STUB_HEADER) == 0)
{
- orc->session->txn_stub = apr_pstrdup(orc->session->pool, val);
+ session->txn_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_TXN_ROOT_STUB_HEADER) == 0)
{
- orc->session->txn_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->txn_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_STUB_HEADER) == 0)
{
- orc->session->vtxn_stub = apr_pstrdup(orc->session->pool, val);
+ session->vtxn_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_ROOT_STUB_HEADER) == 0)
{
- orc->session->vtxn_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->vtxn_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_REPOS_UUID_HEADER) == 0)
{
- orc->session->uuid = apr_pstrdup(orc->session->pool, val);
+ session->uuid = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_YOUNGEST_REV_HEADER) == 0)
{
- struct svn_ra_serf__options_context_t *user_data =
- orc->parser_ctx->user_data;
- user_data->youngest_rev = SVN_STR_TO_REV(val);
+ opt_ctx->youngest_rev = SVN_STR_TO_REV(val);
}
}
@@ -391,7 +264,7 @@ capabilities_headers_iterator_callback(v
/* A custom serf_response_handler_t which is mostly a wrapper around
- svn_ra_serf__handle_xml_parser -- it just notices OPTIONS response
+ the expat-based response handler -- it just notices OPTIONS response
headers first, before handing off to the xml parser.
Implements svn_ra_serf__response_handler_t */
static svn_error_t *
@@ -400,88 +273,117 @@ options_response_handler(serf_request_t
void *baton,
apr_pool_t *pool)
{
- struct options_response_ctx_t *orc = baton;
- serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
+ options_context_t *opt_ctx = baton;
+
+ if (!opt_ctx->headers_processed)
+ {
+ svn_ra_serf__session_t *session = opt_ctx->session;
+ serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
- /* Start out assuming all capabilities are unsupported. */
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
- APR_HASH_KEY_STRING, capability_no);
+ /* Start out assuming all capabilities are unsupported. */
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
+ APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_DEPTH,
+ APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
+ APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
+ APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+ APR_HASH_KEY_STRING, capability_no);
+
+ /* Then see which ones we can discover. */
+ serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
+ opt_ctx);
- /* Then see which ones we can discover. */
- serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback, orc);
+ opt_ctx->headers_processed = TRUE;
+ }
/* Execute the 'real' response handler to XML-parse the repsonse body. */
- return svn_ra_serf__handle_xml_parser(request, response,
- orc->parser_ctx, pool);
+ return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
}
-svn_error_t *
-svn_ra_serf__create_options_req(svn_ra_serf__options_context_t **opt_ctx,
- svn_ra_serf__session_t *session,
- svn_ra_serf__connection_t *conn,
- const char *path,
- apr_pool_t *pool)
+static svn_error_t *
+create_options_req(options_context_t **opt_ctx,
+ svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *pool)
{
- svn_ra_serf__options_context_t *new_ctx;
+ options_context_t *new_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
- struct options_response_ctx_t *options_response_ctx;
new_ctx = apr_pcalloc(pool, sizeof(*new_ctx));
-
new_ctx->pool = pool;
-
- new_ctx->acbuf = svn_stringbuf_create_empty(pool);
-
- new_ctx->path = path;
- new_ctx->youngest_rev = SVN_INVALID_REVNUM;
-
new_ctx->session = session;
new_ctx->conn = conn;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ new_ctx->youngest_rev = SVN_INVALID_REVNUM;
+
+ xmlctx = svn_ra_serf__xml_context_create(options_ttable,
+ NULL, options_closed, NULL,
+ new_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "OPTIONS";
- handler->path = path;
+ handler->path = session->session_url.path;
handler->body_delegate = create_options_body;
handler->body_type = "text/xml";
handler->conn = conn;
handler->session = session;
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = pool;
- parser_ctx->user_data = new_ctx;
- parser_ctx->start = start_options;
- parser_ctx->end = end_options;
- parser_ctx->cdata = cdata_options;
- parser_ctx->done = &new_ctx->done;
- parser_ctx->status_code = &new_ctx->status_code;
-
- options_response_ctx = apr_pcalloc(pool, sizeof(*options_response_ctx));
- options_response_ctx->parser_ctx = parser_ctx;
- options_response_ctx->session = session;
- options_response_ctx->pool = pool;
+ new_ctx->handler = handler;
+ new_ctx->inner_handler = handler->response_handler;
+ new_ctx->inner_baton = handler->response_baton;
handler->response_handler = options_response_handler;
- handler->response_baton = options_response_ctx;
+ handler->response_baton = new_ctx;
+
+ *opt_ctx = new_ctx;
+
+ return SVN_NO_ERROR;
+}
+
- svn_ra_serf__request_create(handler);
+svn_error_t *
+svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = conn->session;
+ options_context_t *opt_ctx;
- new_ctx->parser_ctx = parser_ctx;
+ SVN_ERR_ASSERT(SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
- *opt_ctx = new_ctx;
+ SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
+ SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
+
+ *youngest = opt_ctx->youngest_rev;
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_serf__v1_get_activity_collection(const char **activity_url,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = conn->session;
+ options_context_t *opt_ctx;
+
+ SVN_ERR_ASSERT(!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
+
+ SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
+ SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
+
+ *activity_url = apr_pstrdup(result_pool, opt_ctx->activity_collection);
return SVN_NO_ERROR;
+
}
@@ -493,32 +395,29 @@ svn_ra_serf__exchange_capabilities(svn_r
const char **corrected_url,
apr_pool_t *pool)
{
- svn_ra_serf__options_context_t *opt_ctx;
+ options_context_t *opt_ctx;
svn_error_t *err;
/* This routine automatically fills in serf_sess->capabilities */
- SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, serf_sess,
- serf_sess->conns[0],
- serf_sess->session_url.path, pool));
+ SVN_ERR(create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0], pool));
- err = svn_ra_serf__context_run_wait(
- svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool);
+ err = svn_ra_serf__context_run_one(opt_ctx->handler, pool);
/* If our caller cares about server redirections, and our response
carries such a thing, report as much. We'll disregard ERR --
it's most likely just a complaint about the response body not
successfully parsing as XML or somesuch. */
- if (corrected_url && (opt_ctx->status_code == 301))
+ if (corrected_url && (opt_ctx->handler->sline.code == 301))
{
svn_error_clear(err);
- *corrected_url = opt_ctx->parser_ctx->location;
+ *corrected_url = opt_ctx->handler->location;
return SVN_NO_ERROR;
}
return svn_error_compose_create(
- svn_ra_serf__error_on_status(opt_ctx->status_code,
+ svn_ra_serf__error_on_status(opt_ctx->handler->sline.code,
serf_sess->session_url.path,
- opt_ctx->parser_ctx->location),
+ opt_ctx->handler->location),
err);
}
@@ -551,9 +450,7 @@ svn_ra_serf__has_capability(svn_ra_sessi
cap_result = apr_hash_get(serf_sess->capabilities,
capability, APR_HASH_KEY_STRING);
- /* Some capabilities depend on the repository as well as the server.
- NOTE: svn_ra_neon__has_capability() has a very similar code block. If
- you change something here, check there as well. */
+ /* Some capabilities depend on the repository as well as the server. */
if (cap_result == capability_server_yes)
{
if (strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO) == 0)
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c Thu Aug 16 10:17:48 2012
@@ -41,28 +41,23 @@
/* Our current parsing state we're in for the PROPFIND response. */
typedef enum prop_state_e {
- NONE = 0,
+ INITIAL = 0,
+ MULTISTATUS,
RESPONSE,
+ HREF,
+ PROPSTAT,
+ STATUS,
PROP,
- PROPVAL
+ PROPVAL,
+ COLLECTION,
+ HREF_VALUE
} prop_state_e;
-typedef struct prop_info_t {
- apr_pool_t *pool;
-
- /* Current ns, attribute name, and value of the property we're parsing */
- const char *ns;
- const char *name;
- svn_stringbuf_t *value;
-
- const char *encoding;
-
-} prop_info_t;
/*
* This structure represents a pending PROPFIND response.
*/
-struct svn_ra_serf__propfind_context_t {
+typedef struct propfind_context_t {
/* pool to issue allocations from */
apr_pool_t *pool;
@@ -87,31 +82,273 @@ struct svn_ra_serf__propfind_context_t {
/* hash table that will be updated with the properties
*
- * This can be shared between multiple svn_ra_serf__propfind_context_t
+ * This can be shared between multiple propfind_context_t
* structures
*/
apr_hash_t *ret_props;
- /* If we're dealing with a Depth: 1 response,
- * we may be dealing with multiple paths.
+ /* hash table containing all the properties associated with the
+ * "current" <propstat> tag. These will get copied into RET_PROPS
+ * if the status code similarly associated indicates that they are
+ * "good"; otherwise, they'll get discarded.
*/
- const char *current_path;
-
- /* Returned status code. */
- int status_code;
-
- /* Are we done issuing the PROPFIND? */
- svn_boolean_t done;
-
- /* Context from XML stream */
- svn_ra_serf__xml_parser_t *parser_ctx;
+ apr_hash_t *ps_props;
/* If not-NULL, add us to this list when we're done. */
svn_ra_serf__list_t **done_list;
svn_ra_serf__list_t done_item;
+
+} propfind_context_t;
+
+
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t propfind_ttable[] = {
+ { INITIAL, D_, "multistatus", MULTISTATUS,
+ FALSE, { NULL }, TRUE },
+
+ { MULTISTATUS, D_, "response", RESPONSE,
+ FALSE, { NULL }, FALSE },
+
+ { RESPONSE, D_, "href", HREF,
+ TRUE, { NULL }, TRUE },
+
+ { RESPONSE, D_, "propstat", PROPSTAT,
+ FALSE, { NULL }, TRUE },
+
+ { PROPSTAT, D_, "status", STATUS,
+ TRUE, { NULL }, TRUE },
+
+ { PROPSTAT, D_, "prop", PROP,
+ FALSE, { NULL }, FALSE },
+
+ { PROP, "*", "*", PROPVAL,
+ TRUE, { "?V:encoding", NULL }, TRUE },
+
+ { PROPVAL, D_, "collection", COLLECTION,
+ FALSE, { NULL }, TRUE },
+
+ { PROPVAL, D_, "href", HREF_VALUE,
+ TRUE, { NULL }, TRUE },
+
+ { 0 }
};
+
+/* Return the HTTP status code contained in STATUS_LINE, or 0 if
+ there's a problem parsing it. */
+static int parse_status_code(const char *status_line)
+{
+ /* STATUS_LINE should be of form: "HTTP/1.1 200 OK" */
+ if (status_line[0] == 'H' &&
+ status_line[1] == 'T' &&
+ status_line[2] == 'T' &&
+ status_line[3] == 'P' &&
+ status_line[4] == '/' &&
+ (status_line[5] >= '0' && status_line[5] <= '9') &&
+ status_line[6] == '.' &&
+ (status_line[7] >= '0' && status_line[7] <= '9') &&
+ status_line[8] == ' ')
+ {
+ char *reason;
+
+ return apr_strtoi64(status_line + 8, &reason, 10);
+ }
+ return 0;
+}
+
+
+/* Conforms to svn_ra_serf__path_rev_walker_t */
+static svn_error_t *
+copy_into_ret_props(void *baton,
+ const char *path, apr_ssize_t path_len,
+ const char *ns, apr_ssize_t ns_len,
+ const char *name, apr_ssize_t name_len,
+ const svn_string_t *val,
+ apr_pool_t *pool)
+{
+ propfind_context_t *ctx = baton;
+
+ svn_ra_serf__set_ver_prop(ctx->ret_props, path, ctx->rev, ns, name,
+ val, ctx->pool);
+ return SVN_NO_ERROR;
+}
+
+
+/* Conforms to svn_ra_serf__xml_opened_t */
+static svn_error_t *
+propfind_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)
+{
+ propfind_context_t *ctx = baton;
+
+ if (entered_state == PROPVAL)
+ {
+ svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->namespace);
+ svn_ra_serf__xml_note(xes, PROPVAL, "name", tag->name);
+ }
+ else if (entered_state == PROPSTAT)
+ {
+ ctx->ps_props = apr_hash_make(ctx->pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Conforms to svn_ra_serf__xml_closed_t */
+static svn_error_t *
+propfind_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)
+{
+ propfind_context_t *ctx = baton;
+
+ if (leaving_state == MULTISTATUS)
+ {
+ /* We've gathered all the data from the reponse. Add this item
+ onto the "done list". External callers will then know this
+ request has been completed (tho stray response bytes may still
+ arrive). */
+ if (ctx->done_list)
+ {
+ ctx->done_item.data = ctx->handler;
+ ctx->done_item.next = *ctx->done_list;
+ *ctx->done_list = &ctx->done_item;
+ }
+ }
+ else if (leaving_state == HREF)
+ {
+ const char *path;
+ const svn_string_t *val_str;
+
+ if (strcmp(ctx->depth, "1") == 0)
+ path = svn_urlpath__canonicalize(cdata->data, scratch_pool);
+ else
+ path = ctx->path;
+
+ svn_ra_serf__xml_note(xes, RESPONSE, "path", path);
+
+ /* Copy the value into the right pool, then save the HREF. */
+ val_str = svn_string_dup(cdata, ctx->pool);
+ svn_ra_serf__set_ver_prop(ctx->ret_props,
+ path, ctx->rev, D_, "href", val_str,
+ ctx->pool);
+ }
+ else if (leaving_state == COLLECTION)
+ {
+ svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", "collection");
+ }
+ else if (leaving_state == HREF_VALUE)
+ {
+ svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", cdata->data);
+ }
+ else if (leaving_state == STATUS)
+ {
+ /* Parse the status field, and remember if this is a property
+ that we wish to ignore. (Typically, if it's not a 200, the
+ status will be 404 to indicate that a property we
+ specifically requested from the server doesn't exist.) */
+ int status = parse_status_code(cdata->data);
+ if (status != 200)
+ svn_ra_serf__xml_note(xes, PROPSTAT, "ignore-prop", "*");
+ }
+ else if (leaving_state == PROPVAL)
+ {
+ const char *encoding = apr_hash_get(attrs, "V:encoding",
+ APR_HASH_KEY_STRING);
+ const svn_string_t *val_str;
+ apr_hash_t *gathered;
+ const char *path;
+ const char *ns;
+ const char *name;
+ const char *altvalue;
+
+ if (encoding)
+ {
+ if (strcmp(encoding, "base64") != 0)
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
+ NULL,
+ _("Got unrecognized encoding '%s'"),
+ encoding);
+
+ /* Decode into the right pool. */
+ val_str = svn_base64_decode_string(cdata, ctx->pool);
+ }
+ else
+ {
+ /* Copy into the right pool. */
+ val_str = svn_string_dup(cdata, ctx->pool);
+ }
+
+ /* The current path sits on the RESPONSE state. Gather up all the
+ state from this PROPVAL to the (grandparent) RESPONSE state,
+ and grab the path from there.
+
+ Now, it would be nice if we could, at this point, know that
+ the status code for this property indicated a problem -- then
+ we could simply bail out here and ignore the property.
+ Sadly, though, we might get the status code *after* we get
+ the property value. So we'll carry on with our processing
+ here, setting the property and value as expected. Once we
+ know for sure the status code associate with the property,
+ we'll decide its fate. */
+ gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE);
+
+ /* These will be dup'd into CTX->POOL, as necessary. */
+ path = apr_hash_get(gathered, "path", APR_HASH_KEY_STRING);
+ if (path == NULL)
+ path = ctx->path;
+
+ ns = apr_hash_get(attrs, "ns", APR_HASH_KEY_STRING);
+ name = apr_pstrdup(ctx->pool,
+ apr_hash_get(attrs, "name", APR_HASH_KEY_STRING));
+
+ altvalue = apr_hash_get(attrs, "altvalue", APR_HASH_KEY_STRING);
+ if (altvalue != NULL)
+ val_str = svn_string_create(altvalue, ctx->pool);
+
+ svn_ra_serf__set_ver_prop(ctx->ps_props,
+ path, ctx->rev, ns, name, val_str,
+ ctx->pool);
+ }
+ else
+ {
+ apr_hash_t *gathered;
+ const char *path;
+
+ SVN_ERR_ASSERT(leaving_state == PROPSTAT);
+
+ gathered = svn_ra_serf__xml_gather_since(xes, PROPSTAT);
+
+ path = apr_hash_get(gathered, "path", APR_HASH_KEY_STRING);
+ if (path == NULL)
+ path = ctx->path;
+
+ /* If we've squirreled away a note that says we want to ignore
+ these properties, we'll do so. Otherwise, we need to copy
+ them from the temporary hash into the ctx->ret_props hash. */
+ if (! apr_hash_get(gathered, "ignore-prop", APR_HASH_KEY_STRING))
+ {
+ SVN_ERR(svn_ra_serf__walk_all_paths(ctx->ps_props, ctx->rev,
+ copy_into_ret_props, ctx,
+ scratch_pool));
+ }
+
+ ctx->ps_props = NULL;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
const svn_string_t *
svn_ra_serf__get_ver_prop_string(apr_hash_t *props,
const char *path,
@@ -228,197 +465,15 @@ svn_ra_serf__set_prop(apr_hash_t *props,
val, pool);
}
-static prop_info_t *
-push_state(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__propfind_context_t *propfind,
- prop_state_e state)
-{
- svn_ra_serf__xml_push_state(parser, state);
-
- if (state == PROPVAL)
- {
- prop_info_t *info;
-
- info = apr_pcalloc(parser->state->pool, sizeof(*info));
- info->pool = parser->state->pool;
- info->value = svn_stringbuf_create_empty(info->pool);
-
- parser->state->private = info;
- }
-
- return parser->state->private;
-}
-
-/*
- * Expat callback invoked on a start element tag for a PROPFIND response.
- */
-static svn_error_t *
-start_propfind(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__propfind_context_t *ctx = parser->user_data;
- prop_state_e state;
- prop_info_t *info;
-
- state = parser->state->current_state;
-
- if (state == NONE && strcmp(name.name, "response") == 0)
- {
- svn_ra_serf__xml_push_state(parser, RESPONSE);
- }
- else if (state == RESPONSE && strcmp(name.name, "href") == 0)
- {
- info = push_state(parser, ctx, PROPVAL);
- info->ns = name.namespace;
- info->name = "href";
- }
- else if (state == RESPONSE && strcmp(name.name, "prop") == 0)
- {
- push_state(parser, ctx, PROP);
- }
- else if (state == PROP)
- {
- info = push_state(parser, ctx, PROPVAL);
- info->ns = name.namespace;
- info->name = apr_pstrdup(info->pool, name.name);
- info->encoding = apr_pstrdup(info->pool,
- svn_xml_get_attr_value("V:encoding", attrs));
- }
-
- return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on an end element tag for a PROPFIND response.
- */
-static svn_error_t *
-end_propfind(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__propfind_context_t *ctx = parser->user_data;
- prop_state_e state;
- prop_info_t *info;
-
- state = parser->state->current_state;
- info = parser->state->private;
-
- if (state == RESPONSE && strcmp(name.name, "response") == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PROP && strcmp(name.name, "prop") == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PROPVAL)
- {
- const char *ns;
- const char *pname;
- const svn_string_t *val_str = NULL;
-
- /* if we didn't see a CDATA element, we may want the tag name
- * as long as it isn't equivalent to the property name.
- */
- /* ### gstein sez: I have no idea what this is about. */
- if (*info->value->data == '\0')
- {
- if (strcmp(info->name, name.name) != 0)
- val_str = svn_string_create(name.name, ctx->pool);
- else
- val_str = svn_string_create_empty(ctx->pool);
- }
-
- if (parser->state->prev->current_state == RESPONSE &&
- strcmp(name.name, "href") == 0)
- {
- if (strcmp(ctx->depth, "1") == 0)
- {
- ctx->current_path =
- svn_urlpath__canonicalize(info->value->data, ctx->pool);
- }
- else
- {
- ctx->current_path = ctx->path;
- }
- }
- else if (info->encoding)
- {
- if (strcmp(info->encoding, "base64") == 0)
- {
- const svn_string_t *morph;
-
- morph = svn_stringbuf__morph_into_string(info->value);
-#ifdef SVN_DEBUG
- info->value = NULL; /* morph killed the stringbuf. */
-#endif
- val_str = svn_base64_decode_string(morph, ctx->pool);
- }
- else
- {
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
- NULL,
- _("Got unrecognized encoding '%s'"),
- info->encoding);
- }
- }
-
- /* ### there may be better logic to ensure this is set above, but just
- ### going for the easy win here. */
- if (val_str == NULL)
- val_str = svn_string_create_from_buf(info->value, ctx->pool);
-
- ns = apr_pstrdup(ctx->pool, info->ns);
- pname = apr_pstrdup(ctx->pool, info->name);
-
- /* set the return props and update our cache too. */
- svn_ra_serf__set_ver_prop(ctx->ret_props,
- ctx->current_path, ctx->rev,
- ns, pname, val_str,
- ctx->pool);
-
- svn_ra_serf__xml_pop_state(parser);
- }
-
- return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on CDATA elements in a PROPFIND response.
- *
- * This callback can be called multiple times.
- */
-static svn_error_t *
-cdata_propfind(svn_ra_serf__xml_parser_t *parser,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__propfind_context_t *ctx = parser->user_data;
- prop_state_e state;
- prop_info_t *info;
-
- UNUSED_CTX(ctx);
-
- state = parser->state->current_state;
- info = parser->state->private;
-
- if (state == PROPVAL)
- svn_stringbuf_appendbytes(info->value, data, len);
-
- return SVN_NO_ERROR;
-}
static svn_error_t *
setup_propfind_headers(serf_bucket_t *headers,
void *setup_baton,
apr_pool_t *pool)
{
- svn_ra_serf__propfind_context_t *ctx = setup_baton;
+ propfind_context_t *ctx = setup_baton;
- if (ctx->conn->using_compression)
+ if (ctx->sess->using_compression)
{
serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
}
@@ -440,7 +495,7 @@ create_propfind_body(serf_bucket_t **bkt
serf_bucket_alloc_t *alloc,
apr_pool_t *pool)
{
- svn_ra_serf__propfind_context_t *ctx = setup_baton;
+ propfind_context_t *ctx = setup_baton;
serf_bucket_t *body_bkt, *tmp;
const svn_ra_serf__dav_props_t *prop;
@@ -513,7 +568,7 @@ create_propfind_body(serf_bucket_t **bkt
svn_error_t *
-svn_ra_serf__deliver_props(svn_ra_serf__propfind_context_t **prop_ctx,
+svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler,
apr_hash_t *ret_props,
svn_ra_serf__session_t *sess,
svn_ra_serf__connection_t *conn,
@@ -524,9 +579,9 @@ svn_ra_serf__deliver_props(svn_ra_serf__
svn_ra_serf__list_t **done_list,
apr_pool_t *pool)
{
- svn_ra_serf__propfind_context_t *new_prop_ctx;
+ propfind_context_t *new_prop_ctx;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
new_prop_ctx = apr_pcalloc(pool, sizeof(*new_prop_ctx));
@@ -535,7 +590,6 @@ svn_ra_serf__deliver_props(svn_ra_serf__
new_prop_ctx->find_props = find_props;
new_prop_ctx->ret_props = ret_props;
new_prop_ctx->depth = depth;
- new_prop_ctx->done = FALSE;
new_prop_ctx->sess = sess;
new_prop_ctx->conn = conn;
new_prop_ctx->rev = rev;
@@ -550,7 +604,13 @@ svn_ra_serf__deliver_props(svn_ra_serf__
new_prop_ctx->label = NULL;
}
- handler = apr_pcalloc(pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(propfind_ttable,
+ propfind_opened,
+ propfind_closed,
+ NULL,
+ new_prop_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "PROPFIND";
handler->path = path;
@@ -565,57 +625,28 @@ svn_ra_serf__deliver_props(svn_ra_serf__
new_prop_ctx->handler = handler;
- parser_ctx = apr_pcalloc(pool, sizeof(*new_prop_ctx->parser_ctx));
- parser_ctx->pool = pool;
- parser_ctx->user_data = new_prop_ctx;
- parser_ctx->start = start_propfind;
- parser_ctx->end = end_propfind;
- parser_ctx->cdata = cdata_propfind;
- parser_ctx->status_code = &new_prop_ctx->status_code;
- parser_ctx->done = &new_prop_ctx->done;
- parser_ctx->done_list = new_prop_ctx->done_list;
- parser_ctx->done_item = &new_prop_ctx->done_item;
-
- new_prop_ctx->parser_ctx = parser_ctx;
-
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
-
- /* create request */
- svn_ra_serf__request_create(new_prop_ctx->handler);
-
- *prop_ctx = new_prop_ctx;
+ *propfind_handler = handler;
return SVN_NO_ERROR;
}
-svn_boolean_t
-svn_ra_serf__propfind_is_done(svn_ra_serf__propfind_context_t *ctx)
-{
- return ctx->done;
-}
-
-int
-svn_ra_serf__propfind_status_code(svn_ra_serf__propfind_context_t *ctx)
-{
- return ctx->status_code;
-}
/*
* This helper function will block until the PROP_CTX indicates that is done
* or another error is returned.
*/
svn_error_t *
-svn_ra_serf__wait_for_props(svn_ra_serf__propfind_context_t *prop_ctx,
- svn_ra_serf__session_t *sess,
- apr_pool_t *pool)
+svn_ra_serf__wait_for_props(svn_ra_serf__handler_t *handler,
+ apr_pool_t *scratch_pool)
{
- svn_error_t *err, *err2;
+ svn_error_t *err;
+ svn_error_t *err2;
- err = svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
+ err = svn_ra_serf__context_run_one(handler, scratch_pool);
- err2 = svn_ra_serf__error_on_status(prop_ctx->status_code,
- prop_ctx->path, NULL);
+ err2 = svn_ra_serf__error_on_status(handler->sline.code,
+ handler->path,
+ NULL);
if (err2)
{
svn_error_clear(err);
@@ -639,45 +670,63 @@ svn_ra_serf__retrieve_props(apr_hash_t *
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_ra_serf__propfind_context_t *prop_ctx;
+ svn_ra_serf__handler_t *handler;
*results = apr_hash_make(result_pool);
- SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx, *results, sess, conn, url,
+ SVN_ERR(svn_ra_serf__deliver_props(&handler, *results, sess, conn, url,
rev, depth, props, NULL, result_pool));
- SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx, sess, result_pool));
+ SVN_ERR(svn_ra_serf__wait_for_props(handler, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
-svn_ra_serf__walk_all_props(apr_hash_t *props,
- const char *name,
- svn_revnum_t rev,
- svn_ra_serf__walker_visitor_t walker,
- void *baton,
- apr_pool_t *scratch_pool)
+svn_ra_serf__fetch_node_props(apr_hash_t **results,
+ svn_ra_serf__connection_t *conn,
+ const char *url,
+ svn_revnum_t revision,
+ const svn_ra_serf__dav_props_t *which_props,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_hash_index_t *ns_hi;
+ apr_hash_t *multiprops;
apr_hash_t *ver_props;
- apr_hash_t *path_props;
- apr_pool_t *iterpool;
- ver_props = apr_hash_get(props, &rev, sizeof(rev));
- if (!ver_props)
- {
- return SVN_NO_ERROR;
- }
+ /* Note: a couple extra hash tables and whatnot get into RESULT_POOL.
+ Not a big deal at this point. Theoretically, we could fetch all
+ props into SCRATCH_POOL, then copy just the REVISION/URL props
+ into RESULT_POOL. Too much work for too little gain... */
+ SVN_ERR(svn_ra_serf__retrieve_props(&multiprops, conn->session, conn,
+ url, revision, "0", which_props,
+ result_pool, scratch_pool));
+
+ ver_props = apr_hash_get(multiprops, &revision, sizeof(revision));
+ if (ver_props != NULL)
+ {
+ *results = apr_hash_get(ver_props, url, APR_HASH_KEY_STRING);
+ if (*results != NULL)
+ return SVN_NO_ERROR;
+ }
+
+ return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
+ _("The PROPFIND response did not include "
+ "the requested properties"));
+}
- path_props = apr_hash_get(ver_props, name, APR_HASH_KEY_STRING);
- if (!path_props)
- {
- return SVN_NO_ERROR;
- }
+
+svn_error_t *
+svn_ra_serf__walk_node_props(apr_hash_t *props,
+ svn_ra_serf__walker_visitor_t walker,
+ void *baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool;
+ apr_hash_index_t *ns_hi;
iterpool = svn_pool_create(scratch_pool);
- for (ns_hi = apr_hash_first(scratch_pool, path_props); ns_hi;
+ for (ns_hi = apr_hash_first(scratch_pool, props); ns_hi;
ns_hi = apr_hash_next(ns_hi))
{
void *ns_val;
@@ -711,6 +760,31 @@ svn_ra_serf__walk_all_props(apr_hash_t *
svn_error_t *
+svn_ra_serf__walk_all_props(apr_hash_t *props,
+ const char *name,
+ svn_revnum_t rev,
+ svn_ra_serf__walker_visitor_t walker,
+ void *baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *ver_props;
+ apr_hash_t *path_props;
+
+ ver_props = apr_hash_get(props, &rev, sizeof(rev));
+ if (!ver_props)
+ return SVN_NO_ERROR;
+
+ path_props = apr_hash_get(ver_props, name, APR_HASH_KEY_STRING);
+ if (!path_props)
+ return SVN_NO_ERROR;
+
+ return svn_error_trace(svn_ra_serf__walk_node_props(path_props,
+ walker, baton,
+ scratch_pool));
+}
+
+
+svn_error_t *
svn_ra_serf__walk_all_paths(apr_hash_t *props,
svn_revnum_t rev,
svn_ra_serf__path_rev_walker_t walker,
@@ -832,15 +906,13 @@ set_flat_props(void *baton,
svn_error_t *
svn_ra_serf__flatten_props(apr_hash_t **flat_props,
apr_hash_t *props,
- const char *path,
- svn_revnum_t revision,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
*flat_props = apr_hash_make(result_pool);
- return svn_error_trace(svn_ra_serf__walk_all_props(
- props, path, revision,
+ return svn_error_trace(svn_ra_serf__walk_node_props(
+ props,
set_flat_props,
*flat_props /* baton */,
scratch_pool));
@@ -899,7 +971,7 @@ svn_ra_serf__select_revprops(apr_hash_t
/*
- * Contact the server (using SESSION and CONN) to calculate baseline
+ * Contact the server (using CONN) to calculate baseline
* information for BASELINE_URL at REVISION (which may be
* SVN_INVALID_REVNUM to query the HEAD revision).
*
@@ -911,209 +983,295 @@ svn_ra_serf__select_revprops(apr_hash_t
static svn_error_t *
retrieve_baseline_info(svn_revnum_t *actual_revision,
const char **basecoll_url_p,
- svn_ra_serf__session_t *session,
svn_ra_serf__connection_t *conn,
const char *baseline_url,
svn_revnum_t revision,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_hash_t *props;
+ apr_hash_t *dav_props;
const char *basecoll_url;
- const char *version_name;
-
- SVN_ERR(svn_ra_serf__retrieve_props(&props, session, conn,
- baseline_url, revision, "0",
- baseline_props,
- pool, pool));
- basecoll_url = svn_ra_serf__get_ver_prop(props, baseline_url, revision,
- "DAV:", "baseline-collection");
+ SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn,
+ baseline_url, revision,
+ baseline_props,
+ scratch_pool, scratch_pool));
+ dav_props = apr_hash_get(props, "DAV:", 4);
+ /* If DAV_PROPS is NULL, then svn_prop_get_value() will return NULL. */
+ basecoll_url = svn_prop_get_value(dav_props, "baseline-collection");
if (!basecoll_url)
{
return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
_("The PROPFIND response did not include "
"the requested baseline-collection value"));
}
-
- *basecoll_url_p = svn_urlpath__canonicalize(basecoll_url, pool);
-
- version_name = svn_ra_serf__get_ver_prop(props, baseline_url, revision,
- "DAV:", SVN_DAV__VERSION_NAME);
- if (!version_name)
- {
- return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
- _("The PROPFIND response did not include "
- "the requested version-name value"));
- }
+ *basecoll_url_p = svn_urlpath__canonicalize(basecoll_url, result_pool);
if (actual_revision)
{
+ const char *version_name;
+
+ version_name = svn_prop_get_value(dav_props, SVN_DAV__VERSION_NAME);
+ if (!version_name)
+ return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
+ _("The PROPFIND response did not include "
+ "the requested version-name value"));
+
*actual_revision = SVN_STR_TO_REV(version_name);
}
return SVN_NO_ERROR;
}
+
+/* For HTTPv1 servers, do a PROPFIND dance on the VCC to fetch the youngest
+ revnum. If BASECOLL_URL is non-NULL, then the corresponding baseline
+ collection URL is also returned.
+
+ Do the work over CONN.
+
+ *BASECOLL_URL (if requested) will be allocated in RESULT_POOL. All
+ temporary allocations will be made in SCRATCH_POOL. */
+static svn_error_t *
+v1_get_youngest_revnum(svn_revnum_t *youngest,
+ const char **basecoll_url,
+ svn_ra_serf__connection_t *conn,
+ const char *vcc_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *baseline_url;
+ const char *bc_url;
+
+ /* Fetching DAV:checked-in from the VCC (with no Label: to specify a
+ revision) will return the latest Baseline resource's URL. */
+ SVN_ERR(svn_ra_serf__fetch_dav_prop(&baseline_url, conn, vcc_url,
+ SVN_INVALID_REVNUM,
+ "checked-in",
+ scratch_pool, scratch_pool));
+ if (!baseline_url)
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
+ _("The OPTIONS response did not include "
+ "the requested checked-in value"));
+ }
+ baseline_url = svn_urlpath__canonicalize(baseline_url, scratch_pool);
+
+ /* From the Baseline resource, we can fetch the DAV:baseline-collection
+ and DAV:version-name properties. The latter is the revision number,
+ which is formally the name used in Label: headers. */
+
+ /* First check baseline information cache. */
+ SVN_ERR(svn_ra_serf__blncache_get_baseline_info(&bc_url,
+ youngest,
+ conn->session->blncache,
+ baseline_url,
+ scratch_pool));
+ if (!bc_url)
+ {
+ SVN_ERR(retrieve_baseline_info(youngest, &bc_url, conn,
+ baseline_url, SVN_INVALID_REVNUM,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_ra_serf__blncache_set(conn->session->blncache,
+ baseline_url, *youngest,
+ bc_url, scratch_pool));
+ }
+
+ if (basecoll_url != NULL)
+ *basecoll_url = apr_pstrdup(result_pool, bc_url);
+
+ return SVN_NO_ERROR;
+}
+
+
svn_error_t *
-svn_ra_serf__get_baseline_info(const char **bc_url,
- const char **bc_relative,
- svn_ra_serf__session_t *session,
- svn_ra_serf__connection_t *conn,
- const char *url,
- svn_revnum_t revision,
- svn_revnum_t *latest_revnum,
- apr_pool_t *pool)
+svn_ra_serf__get_youngest_revnum(svn_revnum_t *youngest,
+ svn_ra_serf__session_t *session,
+ apr_pool_t *scratch_pool)
{
- const char *vcc_url, *relative_url, *basecoll_url, *baseline_url;
+ const char *vcc_url;
- /* No URL? No sweat. We'll use the session URL. */
- if (! url)
- url = session->session_url.path;
+ if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
+ return svn_error_trace(svn_ra_serf__v2_get_youngest_revnum(
+ youngest, session->conns[0], scratch_pool));
- /* If the caller didn't provide a specific connection for us to use,
- we'll use the default one. */
- if (! conn)
- conn = session->conns[0];
+ SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, scratch_pool));
+
+ return svn_error_trace(v1_get_youngest_revnum(youngest, NULL,
+ session->conns[0], vcc_url,
+ scratch_pool, scratch_pool));
+}
+
+/* Set *BC_URL to the baseline collection url for REVISION. If REVISION
+ is SVN_INVALID_REVNUM, then the youngest revnum ("HEAD") is used.
+
+ *REVNUM_USED will be set to the revision used.
+
+ Uses the specified CONN, which is part of SESSION.
+
+ All allocations (results and temporary) are performed in POOL. */
+static svn_error_t *
+get_baseline_info(const char **bc_url,
+ svn_revnum_t *revnum_used,
+ svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
/* If we detected HTTP v2 support on the server, we can construct
the baseline collection URL ourselves, and fetch the latest
revision (if needed) with an OPTIONS request. */
if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
{
- svn_revnum_t actual_revision;
-
if (SVN_IS_VALID_REVNUM(revision))
{
- actual_revision = revision;
+ *revnum_used = revision;
}
else
{
- svn_ra_serf__options_context_t *opt_ctx;
-
- SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, session, conn,
- session->session_url.path,
- pool));
- SVN_ERR(svn_ra_serf__context_run_wait(
- svn_ra_serf__get_options_done_ptr(opt_ctx), session, pool));
-
- actual_revision = svn_ra_serf__options_get_youngest_rev(opt_ctx);
- if (! SVN_IS_VALID_REVNUM(actual_revision))
+ SVN_ERR(svn_ra_serf__v2_get_youngest_revnum(
+ revnum_used, conn, pool));
+ if (! SVN_IS_VALID_REVNUM(*revnum_used))
return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
_("The OPTIONS response did not include "
"the youngest revision"));
}
- basecoll_url = apr_psprintf(pool, "%s/%ld",
- session->rev_root_stub, actual_revision);
- if (latest_revnum)
- *latest_revnum = actual_revision;
+ *bc_url = apr_psprintf(pool, "%s/%ld",
+ session->rev_root_stub, *revnum_used);
}
/* Otherwise, we fall back to the old VCC_URL PROPFIND hunt. */
else
{
+ const char *vcc_url;
+
SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, conn, pool));
if (SVN_IS_VALID_REVNUM(revision))
{
/* First check baseline information cache. */
- SVN_ERR(svn_ra_serf__blncache_get_bc_url(&basecoll_url,
+ SVN_ERR(svn_ra_serf__blncache_get_bc_url(bc_url,
session->blncache,
revision, pool));
-
- if (!basecoll_url)
+ if (!*bc_url)
{
- SVN_ERR(retrieve_baseline_info(NULL, &basecoll_url, session,
- conn, vcc_url, revision, pool));
+ SVN_ERR(retrieve_baseline_info(NULL, bc_url, conn,
+ vcc_url, revision, pool, pool));
SVN_ERR(svn_ra_serf__blncache_set(session->blncache, NULL,
- revision, basecoll_url, pool));
+ revision, *bc_url, pool));
}
- if (latest_revnum)
- {
- *latest_revnum = revision;
- }
+ *revnum_used = revision;
}
else
{
- apr_hash_t *props;
- svn_revnum_t actual_revision;
+ SVN_ERR(v1_get_youngest_revnum(revnum_used, bc_url,
+ conn, vcc_url,
+ pool, pool));
+ }
+ }
- SVN_ERR(svn_ra_serf__retrieve_props(&props, session, conn,
- vcc_url, revision, "0",
- checked_in_props,
- pool, pool));
- baseline_url = svn_ra_serf__get_ver_prop(props, vcc_url, revision,
- "DAV:", "checked-in");
- if (!baseline_url)
- {
- return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
- _("The OPTIONS response did not include "
- "the requested checked-in value"));
- }
+ return SVN_NO_ERROR;
+}
- baseline_url = svn_urlpath__canonicalize(baseline_url, pool);
- /* First check baseline information cache. */
- SVN_ERR(svn_ra_serf__blncache_get_baseline_info(&basecoll_url,
- &actual_revision,
- session->blncache,
- baseline_url,
- pool));
- if (!basecoll_url)
- {
- SVN_ERR(retrieve_baseline_info(&actual_revision, &basecoll_url,
- session, conn,
- baseline_url, revision, pool));
- SVN_ERR(svn_ra_serf__blncache_set(session->blncache,
- baseline_url, actual_revision,
- basecoll_url, pool));
- }
+svn_error_t *
+svn_ra_serf__get_stable_url(const char **stable_url,
+ svn_revnum_t *latest_revnum,
+ svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ const char *url,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *basecoll_url;
+ const char *repos_relpath;
+ svn_revnum_t revnum_used;
- if (latest_revnum)
- {
- *latest_revnum = actual_revision;
- }
- }
- }
+ /* No URL? No sweat. We'll use the session URL. */
+ if (! url)
+ url = session->session_url.path;
- /* And let's not forget to calculate our relative path. */
- SVN_ERR(svn_ra_serf__get_relative_path(&relative_url, url, session,
- conn, pool));
+ /* If the caller didn't provide a specific connection for us to use,
+ we'll use the default connection. */
+ if (! conn)
+ conn = session->conns[0];
+
+ SVN_ERR(get_baseline_info(&basecoll_url, &revnum_used,
+ session, conn, revision, scratch_pool));
+ SVN_ERR(svn_ra_serf__get_relative_path(&repos_relpath, url,
+ session, conn, scratch_pool));
+
+ *stable_url = svn_path_url_add_component2(basecoll_url, repos_relpath,
+ result_pool);
+ if (latest_revnum)
+ *latest_revnum = revnum_used;
- *bc_url = basecoll_url;
- *bc_relative = relative_url;
return SVN_NO_ERROR;
}
svn_error_t *
-svn_ra_serf__get_resource_type(svn_node_kind_t *kind,
- apr_hash_t *props,
- const char *url,
- svn_revnum_t revision)
+svn_ra_serf__get_resource_type(svn_kind_t *kind,
+ apr_hash_t *props)
{
+ apr_hash_t *dav_props;
const char *res_type;
- res_type = svn_ra_serf__get_ver_prop(props, url, revision,
- "DAV:", "resourcetype");
+ dav_props = apr_hash_get(props, "DAV:", 4);
+ res_type = svn_prop_get_value(dav_props, "resourcetype");
if (!res_type)
{
/* How did this happen? */
return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
_("The PROPFIND response did not include the "
- "requested resourcetype value"));
+ "requested resourcetype value"));
}
if (strcmp(res_type, "collection") == 0)
{
- *kind = svn_node_dir;
+ *kind = svn_kind_dir;
}
else
{
- *kind = svn_node_file;
+ *kind = svn_kind_file;
}
return SVN_NO_ERROR;
}
+
+
+svn_error_t *
+svn_ra_serf__fetch_dav_prop(const char **value,
+ svn_ra_serf__connection_t *conn,
+ const char *url,
+ svn_revnum_t revision,
+ const char *propname,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *props;
+ apr_hash_t *dav_props;
+
+ SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn, url, revision,
+ checked_in_props,
+ scratch_pool, scratch_pool));
+ dav_props = apr_hash_get(props, "DAV:", 4);
+ if (dav_props == NULL)
+ return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
+ _("The PROPFIND response did not include "
+ "the requested 'DAV:' properties"));
+
+ /* We wouldn't get here if the resource was not found (404), so the
+ property should be present.
+
+ Note: it is okay to call apr_pstrdup() with NULL. */
+ *value = apr_pstrdup(result_pool, svn_prop_get_value(dav_props, propname));
+
+ return SVN_NO_ERROR;
+}