diff options
Diffstat (limited to 'subversion/libsvn_ra_serf/property.c')
-rw-r--r-- | subversion/libsvn_ra_serf/property.c | 760 |
1 files changed, 207 insertions, 553 deletions
diff --git a/subversion/libsvn_ra_serf/property.c b/subversion/libsvn_ra_serf/property.c index 586d38ff46ca..b7e03183c4c7 100644 --- a/subversion/libsvn_ra_serf/property.c +++ b/subversion/libsvn_ra_serf/property.c @@ -42,7 +42,7 @@ /* Our current parsing state we're in for the PROPFIND response. */ typedef enum prop_state_e { - INITIAL = 0, + INITIAL = XML_STATE_INITIAL, MULTISTATUS, RESPONSE, HREF, @@ -59,20 +59,12 @@ typedef enum prop_state_e { * This structure represents a pending PROPFIND response. */ typedef struct propfind_context_t { - /* pool to issue allocations from */ - apr_pool_t *pool; - svn_ra_serf__handler_t *handler; - /* associated serf session */ - svn_ra_serf__session_t *sess; - svn_ra_serf__connection_t *conn; - /* the requested path */ const char *path; - /* the requested version (number and string form) */ - svn_revnum_t rev; + /* the requested version (in string form) */ const char *label; /* the request depth */ @@ -81,12 +73,8 @@ typedef struct propfind_context_t { /* the list of requested properties */ const svn_ra_serf__dav_props_t *find_props; - /* hash table that will be updated with the properties - * - * This can be shared between multiple propfind_context_t - * structures - */ - apr_hash_t *ret_props; + svn_ra_serf__prop_func_t prop_func; + void *prop_func_baton; /* hash table containing all the properties associated with the * "current" <propstat> tag. These will get copied into RET_PROPS @@ -94,12 +82,6 @@ typedef struct propfind_context_t { * "good"; otherwise, they'll get discarded. */ 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; @@ -136,10 +118,14 @@ static const svn_ra_serf__xml_transition_t propfind_ttable[] = { { 0 } }; +static const int propfind_expected_status[] = { + 207, + 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) +static apr_int64_t parse_status_code(const char *status_line) { /* STATUS_LINE should be of form: "HTTP/1.1 200 OK" */ if (status_line[0] == 'H' && @@ -159,24 +145,6 @@ static int parse_status_code(const char *status_line) 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, @@ -189,17 +157,40 @@ propfind_opened(svn_ra_serf__xml_estate_t *xes, if (entered_state == PROPVAL) { - svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->namespace); + svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->xmlns); svn_ra_serf__xml_note(xes, PROPVAL, "name", tag->name); } else if (entered_state == PROPSTAT) { - ctx->ps_props = apr_hash_make(ctx->pool); + ctx->ps_props = apr_hash_make(svn_ra_serf__xml_state_pool(xes)); } return SVN_NO_ERROR; } +/* Set PROPS for NS:NAME VAL. Helper for propfind_closed */ +static void +set_ns_prop(apr_hash_t *ns_props, + const char *ns, const char *name, + const svn_string_t *val, apr_pool_t *result_pool) +{ + apr_hash_t *props = svn_hash_gets(ns_props, ns); + + if (!props) + { + props = apr_hash_make(result_pool); + ns = apr_pstrdup(result_pool, ns); + svn_hash_sets(ns_props, ns, props); + } + + if (val) + { + name = apr_pstrdup(result_pool, name); + val = svn_string_dup(val, result_pool); + } + + svn_hash_sets(props, name, val); +} /* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * @@ -218,17 +209,10 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, 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); @@ -237,11 +221,10 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, 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); + SVN_ERR(ctx->prop_func(ctx->prop_func_baton, + path, + D_, "href", + cdata, scratch_pool)); } else if (leaving_state == COLLECTION) { @@ -257,21 +240,23 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, 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); + apr_int64_t 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 = svn_hash_gets(attrs, "V:encoding"); + const char *encoding; 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 ((altvalue = svn_hash_gets(attrs, "altvalue")) != NULL) + { + val_str = svn_string_create(altvalue, scratch_pool); + } + else if ((encoding = svn_hash_gets(attrs, "V:encoding")) != NULL) { if (strcmp(encoding, "base64") != 0) return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, @@ -280,17 +265,15 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, encoding); /* Decode into the right pool. */ - val_str = svn_base64_decode_string(cdata, ctx->pool); + val_str = svn_base64_decode_string(cdata, scratch_pool); } else { /* Copy into the right pool. */ - val_str = svn_string_dup(cdata, ctx->pool); + val_str = cdata; } - /* 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. + /* The current path sits on the RESPONSE state. Now, it would be nice if we could, at this point, know that the status code for this property indicated a problem -- then @@ -300,24 +283,12 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, 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 = svn_hash_gets(gathered, "path"); - if (path == NULL) - path = ctx->path; ns = svn_hash_gets(attrs, "ns"); - name = apr_pstrdup(ctx->pool, - svn_hash_gets(attrs, "name")); - - altvalue = svn_hash_gets(attrs, "altvalue"); - if (altvalue != NULL) - val_str = svn_string_create(altvalue, ctx->pool); + name = svn_hash_gets(attrs, "name"); - svn_ra_serf__set_ver_prop(ctx->ps_props, - path, ctx->rev, ns, name, val_str, - ctx->pool); + set_ns_prop(ctx->ps_props, ns, name, val_str, + apr_hash_pool_get(ctx->ps_props)); } else { @@ -325,146 +296,60 @@ propfind_closed(svn_ra_serf__xml_estate_t *xes, SVN_ERR_ASSERT(leaving_state == PROPSTAT); - gathered = svn_ra_serf__xml_gather_since(xes, PROPSTAT); + gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE); /* 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 (! svn_hash_gets(gathered, "ignore-prop")) { - SVN_ERR(svn_ra_serf__walk_all_paths(ctx->ps_props, ctx->rev, - copy_into_ret_props, ctx, - scratch_pool)); - } + apr_hash_index_t *hi_ns; + const char *path; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); - ctx->ps_props = NULL; - } - - return SVN_NO_ERROR; -} + path = svn_hash_gets(gathered, "path"); + if (!path) + path = ctx->path; -const svn_string_t * -svn_ra_serf__get_ver_prop_string(apr_hash_t *props, - const char *path, - svn_revnum_t rev, - const char *ns, - const char *name) -{ - apr_hash_t *ver_props, *path_props, *ns_props; - void *val = NULL; - - ver_props = apr_hash_get(props, &rev, sizeof(rev)); - if (ver_props) - { - path_props = svn_hash_gets(ver_props, path); - - if (path_props) - { - ns_props = svn_hash_gets(path_props, ns); - if (ns_props) + for (hi_ns = apr_hash_first(scratch_pool, ctx->ps_props); + hi_ns; + hi_ns = apr_hash_next(hi_ns)) { - val = svn_hash_gets(ns_props, name); + const char *ns = apr_hash_this_key(hi_ns); + apr_hash_t *props = apr_hash_this_val(hi_ns); + apr_hash_index_t *hi_prop; + + svn_pool_clear(iterpool); + + for (hi_prop = apr_hash_first(iterpool, props); + hi_prop; + hi_prop = apr_hash_next(hi_prop)) + { + const char *name = apr_hash_this_key(hi_prop); + const svn_string_t *value = apr_hash_this_val(hi_prop); + + SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path, + ns, name, value, iterpool)); + } } - } - } - - return val; -} - -const char * -svn_ra_serf__get_ver_prop(apr_hash_t *props, - const char *path, - svn_revnum_t rev, - const char *ns, - const char *name) -{ - const svn_string_t *val; - val = svn_ra_serf__get_ver_prop_string(props, path, rev, ns, name); - - if (val) - { - return val->data; - } - - return NULL; -} - -const svn_string_t * -svn_ra_serf__get_prop_string(apr_hash_t *props, - const char *path, - const char *ns, - const char *name) -{ - return svn_ra_serf__get_ver_prop_string(props, path, SVN_INVALID_REVNUM, - ns, name); -} - -const char * -svn_ra_serf__get_prop(apr_hash_t *props, - const char *path, - const char *ns, - const char *name) -{ - return svn_ra_serf__get_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name); -} - -void -svn_ra_serf__set_ver_prop(apr_hash_t *props, - const char *path, svn_revnum_t rev, - const char *ns, const char *name, - const svn_string_t *val, apr_pool_t *pool) -{ - apr_hash_t *ver_props, *path_props, *ns_props; - - ver_props = apr_hash_get(props, &rev, sizeof(rev)); - if (!ver_props) - { - ver_props = apr_hash_make(pool); - apr_hash_set(props, apr_pmemdup(pool, &rev, sizeof(rev)), sizeof(rev), - ver_props); - } - - path_props = svn_hash_gets(ver_props, path); - - if (!path_props) - { - path_props = apr_hash_make(pool); - path = apr_pstrdup(pool, path); - svn_hash_sets(ver_props, path, path_props); - - /* todo: we know that we'll fail the next check, but fall through - * for now for simplicity's sake. - */ - } + svn_pool_destroy(iterpool); + } - ns_props = svn_hash_gets(path_props, ns); - if (!ns_props) - { - ns_props = apr_hash_make(pool); - ns = apr_pstrdup(pool, ns); - svn_hash_sets(path_props, ns, ns_props); + ctx->ps_props = NULL; /* Allocated in PROPSTAT state pool */ } - svn_hash_sets(ns_props, name, val); + return SVN_NO_ERROR; } -void -svn_ra_serf__set_prop(apr_hash_t *props, - const char *path, - const char *ns, const char *name, - const svn_string_t *val, apr_pool_t *pool) -{ - svn_ra_serf__set_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name, - val, pool); -} static svn_error_t * setup_propfind_headers(serf_bucket_t *headers, - void *setup_baton, - apr_pool_t *pool) + void *setup_baton, + apr_pool_t *pool /* request pool */, + apr_pool_t *scratch_pool) { propfind_context_t *ctx = setup_baton; @@ -480,11 +365,13 @@ setup_propfind_headers(serf_bucket_t *headers, #define PROPFIND_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\">" #define PROPFIND_TRAILER "</propfind>" +/* Implements svn_ra_serf__request_body_delegate_t */ static svn_error_t * create_propfind_body(serf_bucket_t **bkt, void *setup_baton, serf_bucket_alloc_t *alloc, - apr_pool_t *pool) + apr_pool_t *pool /* request pool */, + apr_pool_t *scratch_pool) { propfind_context_t *ctx = setup_baton; @@ -495,7 +382,7 @@ create_propfind_body(serf_bucket_t **bkt, body_bkt = serf_bucket_aggregate_create(alloc); prop = ctx->find_props; - while (prop && prop->namespace) + while (prop && prop->xmlns) { /* special case the allprop case. */ if (strcmp(prop->name, "allprop") == 0) @@ -515,7 +402,7 @@ create_propfind_body(serf_bucket_t **bkt, alloc); serf_bucket_aggregate_append(body_bkt, tmp); - tmp = SERF_BUCKET_SIMPLE_STRING(prop->namespace, alloc); + tmp = SERF_BUCKET_SIMPLE_STRING(prop->xmlns, alloc); serf_bucket_aggregate_append(body_bkt, tmp); tmp = SERF_BUCKET_SIMPLE_STRING_LEN("\"/>", sizeof("\"/>")-1, @@ -559,16 +446,15 @@ create_propfind_body(serf_bucket_t **bkt, svn_error_t * -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, - const char *path, - svn_revnum_t rev, - const char *depth, - const svn_ra_serf__dav_props_t *find_props, - svn_ra_serf__list_t **done_list, - apr_pool_t *pool) +svn_ra_serf__create_propfind_handler(svn_ra_serf__handler_t **propfind_handler, + svn_ra_serf__session_t *sess, + const char *path, + svn_revnum_t rev, + const char *depth, + const svn_ra_serf__dav_props_t *find_props, + svn_ra_serf__prop_func_t prop_func, + void *prop_func_baton, + apr_pool_t *pool) { propfind_context_t *new_prop_ctx; svn_ra_serf__handler_t *handler; @@ -576,15 +462,11 @@ svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler, new_prop_ctx = apr_pcalloc(pool, sizeof(*new_prop_ctx)); - new_prop_ctx->pool = apr_hash_pool_get(ret_props); new_prop_ctx->path = path; new_prop_ctx->find_props = find_props; - new_prop_ctx->ret_props = ret_props; + new_prop_ctx->prop_func = prop_func; + new_prop_ctx->prop_func_baton = prop_func_baton; new_prop_ctx->depth = depth; - new_prop_ctx->sess = sess; - new_prop_ctx->conn = conn; - new_prop_ctx->rev = rev; - new_prop_ctx->done_list = done_list; if (SVN_IS_VALID_REVNUM(rev)) { @@ -601,7 +483,9 @@ svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler, NULL, new_prop_ctx, pool); - handler = svn_ra_serf__create_expat_handler(xmlctx, pool); + handler = svn_ra_serf__create_expat_handler(sess, xmlctx, + propfind_expected_status, + pool); handler->method = "PROPFIND"; handler->path = path; @@ -611,8 +495,7 @@ svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler, handler->header_delegate = setup_propfind_headers; handler->header_delegate_baton = new_prop_ctx; - handler->session = new_prop_ctx->sess; - handler->conn = new_prop_ctx->conn; + handler->no_dav_headers = TRUE; new_prop_ctx->handler = handler; @@ -621,208 +504,85 @@ svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler, return SVN_NO_ERROR; } - -/* - * 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__handler_t *handler, - apr_pool_t *scratch_pool) +svn_ra_serf__deliver_svn_props(void *baton, + const char *path, + const char *ns, + const char *name, + const svn_string_t *value, + apr_pool_t *scratch_pool) { - svn_error_t *err; - svn_error_t *err2; + apr_hash_t *props = baton; + apr_pool_t *result_pool = apr_hash_pool_get(props); + const char *prop_name; - err = svn_ra_serf__context_run_one(handler, scratch_pool); + prop_name = svn_ra_serf__svnname_from_wirename(ns, name, result_pool); + if (prop_name == NULL) + return SVN_NO_ERROR; - err2 = svn_ra_serf__error_on_status(handler->sline, - handler->path, - handler->location); + svn_hash_sets(props, prop_name, svn_string_dup(value, result_pool)); - return svn_error_compose_create(err2, err); + return SVN_NO_ERROR; } /* - * This is a blocking version of deliver_props. + * Implementation of svn_ra_serf__prop_func_t that delivers all DAV properties + * in (const char * -> apr_hash_t *) on Namespace pointing to a second hash + * (const char * -> svn_string_t *) to the values. */ -svn_error_t * -svn_ra_serf__retrieve_props(apr_hash_t **results, - svn_ra_serf__session_t *sess, - svn_ra_serf__connection_t *conn, - const char *url, - svn_revnum_t rev, - const char *depth, - const svn_ra_serf__dav_props_t *props, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +static svn_error_t * +deliver_node_props(void *baton, + const char *path, + const char *ns, + const char *name, + const svn_string_t *value, + apr_pool_t *scratch_pool) { - svn_ra_serf__handler_t *handler; + apr_hash_t *nss = baton; + apr_hash_t *props; + apr_pool_t *result_pool = apr_hash_pool_get(nss); - *results = apr_hash_make(result_pool); + props = svn_hash_gets(nss, ns); - 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(handler, scratch_pool)); + if (!props) + { + props = apr_hash_make(result_pool); + + ns = apr_pstrdup(result_pool, ns); + svn_hash_sets(nss, ns, props); + } + + name = apr_pstrdup(result_pool, name); + svn_hash_sets(props, name, svn_string_dup(value, result_pool)); return SVN_NO_ERROR; } - svn_error_t * svn_ra_serf__fetch_node_props(apr_hash_t **results, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, 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_t *multiprops; - apr_hash_t *ver_props; - - /* 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 = svn_hash_gets(ver_props, url); - 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")); -} - - -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, props); ns_hi; - ns_hi = apr_hash_next(ns_hi)) - { - void *ns_val; - const void *ns_name; - apr_hash_index_t *name_hi; - - /* NOTE: We do not clear ITERPOOL in this loop. Generally, there are - very few namespaces, so this loop will not have many iterations. - Instead, ITERPOOL is used for the inner loop. */ - - apr_hash_this(ns_hi, &ns_name, NULL, &ns_val); - - for (name_hi = apr_hash_first(scratch_pool, ns_val); name_hi; - name_hi = apr_hash_next(name_hi)) - { - void *prop_val; - const void *prop_name; - - /* See note above, regarding clearing of this pool. */ - svn_pool_clear(iterpool); - - apr_hash_this(name_hi, &prop_name, NULL, &prop_val); - - SVN_ERR(walker(baton, ns_name, prop_name, prop_val, iterpool)); - } - } - svn_pool_destroy(iterpool); - - 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) -{ - 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 = svn_hash_gets(ver_props, name); - 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, - void *baton, - apr_pool_t *pool) -{ - apr_hash_index_t *path_hi; - apr_hash_t *ver_props; + apr_hash_t *props; + svn_ra_serf__handler_t *handler; - ver_props = apr_hash_get(props, &rev, sizeof(rev)); + props = apr_hash_make(result_pool); - if (!ver_props) - { - return SVN_NO_ERROR; - } + SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session, + url, revision, "0", which_props, + deliver_node_props, + props, scratch_pool)); - for (path_hi = apr_hash_first(pool, ver_props); path_hi; - path_hi = apr_hash_next(path_hi)) - { - void *path_props; - const void *path_name; - apr_ssize_t path_len; - apr_hash_index_t *ns_hi; - - apr_hash_this(path_hi, &path_name, &path_len, &path_props); - for (ns_hi = apr_hash_first(pool, path_props); ns_hi; - ns_hi = apr_hash_next(ns_hi)) - { - void *ns_val; - const void *ns_name; - apr_ssize_t ns_len; - apr_hash_index_t *name_hi; - apr_hash_this(ns_hi, &ns_name, &ns_len, &ns_val); - for (name_hi = apr_hash_first(pool, ns_val); name_hi; - name_hi = apr_hash_next(name_hi)) - { - void *prop_val; - const void *prop_name; - apr_ssize_t prop_len; - - apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val); - /* use a subpool? */ - SVN_ERR(walker(baton, path_name, path_len, ns_name, ns_len, - prop_name, prop_len, prop_val, pool)); - } - } - } + SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool)); + *results = props; return SVN_NO_ERROR; } - const char * svn_ra_serf__svnname_from_wirename(const char *ns, const char *name, @@ -832,10 +592,10 @@ svn_ra_serf__svnname_from_wirename(const char *ns, return apr_pstrdup(result_pool, name); if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0) - return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL); + return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, SVN_VA_NULL); if (strcmp(ns, SVN_PROP_PREFIX) == 0) - return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL); + return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, SVN_VA_NULL); if (strcmp(name, SVN_DAV__VERSION_NAME) == 0) return SVN_PROP_ENTRY_COMMITTED_REV; @@ -863,99 +623,9 @@ svn_ra_serf__svnname_from_wirename(const char *ns, } /* An unknown namespace, must be a custom property. */ - return apr_pstrcat(result_pool, ns, name, (char *)NULL); + return apr_pstrcat(result_pool, ns, name, SVN_VA_NULL); } - -/* Conforms to svn_ra_serf__walker_visitor_t */ -static svn_error_t * -set_flat_props(void *baton, - const char *ns, - const char *name, - const svn_string_t *value, - apr_pool_t *pool) -{ - apr_hash_t *props = baton; - apr_pool_t *result_pool = apr_hash_pool_get(props); - const char *prop_name; - - /* ### is VAL in the proper pool? */ - - prop_name = svn_ra_serf__svnname_from_wirename(ns, name, result_pool); - if (prop_name != NULL) - svn_hash_sets(props, prop_name, value); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_ra_serf__flatten_props(apr_hash_t **flat_props, - apr_hash_t *props, - 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_node_props( - props, - set_flat_props, - *flat_props /* baton */, - scratch_pool)); -} - - -static svn_error_t * -select_revprops(void *baton, - const char *ns, - const char *name, - const svn_string_t *val, - apr_pool_t *scratch_pool) -{ - apr_hash_t *revprops = baton; - apr_pool_t *result_pool = apr_hash_pool_get(revprops); - const char *prop_name; - - /* ### copy NAME into the RESULT_POOL? */ - /* ### copy VAL into the RESULT_POOL? */ - - if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0) - prop_name = name; - else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0) - prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL); - else if (strcmp(ns, SVN_PROP_PREFIX) == 0) - prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL); - else if (strcmp(ns, "") == 0) - prop_name = name; - else - { - /* do nothing for now? */ - return SVN_NO_ERROR; - } - - svn_hash_sets(revprops, prop_name, val); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_ra_serf__select_revprops(apr_hash_t **revprops, - const char *name, - svn_revnum_t rev, - apr_hash_t *all_revprops, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - *revprops = apr_hash_make(result_pool); - - return svn_error_trace(svn_ra_serf__walk_all_props( - all_revprops, name, rev, - select_revprops, *revprops, - scratch_pool)); -} - - /* * Contact the server (using CONN) to calculate baseline * information for BASELINE_URL at REVISION (which may be @@ -969,7 +639,7 @@ svn_ra_serf__select_revprops(apr_hash_t **revprops, static svn_error_t * retrieve_baseline_info(svn_revnum_t *actual_revision, const char **basecoll_url_p, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, const char *baseline_url, svn_revnum_t revision, apr_pool_t *result_pool, @@ -979,7 +649,7 @@ retrieve_baseline_info(svn_revnum_t *actual_revision, apr_hash_t *dav_props; const char *basecoll_url; - SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn, + SVN_ERR(svn_ra_serf__fetch_node_props(&props, session, baseline_url, revision, baseline_props, scratch_pool, scratch_pool)); @@ -1000,12 +670,18 @@ retrieve_baseline_info(svn_revnum_t *actual_revision, const char *version_name; version_name = svn_prop_get_value(dav_props, SVN_DAV__VERSION_NAME); - if (!version_name) + if (version_name) + { + apr_int64_t rev; + + SVN_ERR(svn_cstring_atoi64(&rev, version_name)); + *actual_revision = (svn_revnum_t)rev; + } + + if (!version_name || !SVN_IS_VALID_REVNUM(*actual_revision)) 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; @@ -1023,7 +699,7 @@ retrieve_baseline_info(svn_revnum_t *actual_revision, static svn_error_t * v1_get_youngest_revnum(svn_revnum_t *youngest, const char **basecoll_url, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, const char *vcc_url, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -1033,7 +709,7 @@ v1_get_youngest_revnum(svn_revnum_t *youngest, /* 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_ERR(svn_ra_serf__fetch_dav_prop(&baseline_url, session, vcc_url, SVN_INVALID_REVNUM, "checked-in", scratch_pool, scratch_pool)); @@ -1052,15 +728,15 @@ v1_get_youngest_revnum(svn_revnum_t *youngest, /* First check baseline information cache. */ SVN_ERR(svn_ra_serf__blncache_get_baseline_info(&bc_url, youngest, - conn->session->blncache, + session->blncache, baseline_url, scratch_pool)); if (!bc_url) { - SVN_ERR(retrieve_baseline_info(youngest, &bc_url, conn, + SVN_ERR(retrieve_baseline_info(youngest, &bc_url, session, baseline_url, SVN_INVALID_REVNUM, scratch_pool, scratch_pool)); - SVN_ERR(svn_ra_serf__blncache_set(conn->session->blncache, + SVN_ERR(svn_ra_serf__blncache_set(session->blncache, baseline_url, *youngest, bc_url, scratch_pool)); } @@ -1081,12 +757,12 @@ svn_ra_serf__get_youngest_revnum(svn_revnum_t *youngest, 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)); + youngest, session, scratch_pool)); - SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, scratch_pool)); + SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, scratch_pool)); return svn_error_trace(v1_get_youngest_revnum(youngest, NULL, - session->conns[0], vcc_url, + session, vcc_url, scratch_pool, scratch_pool)); } @@ -1103,9 +779,9 @@ 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) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { /* If we detected HTTP v2 support on the server, we can construct the baseline collection URL ourselves, and fetch the latest @@ -1119,14 +795,10 @@ get_baseline_info(const char **bc_url, else { 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")); + revnum_used, session, scratch_pool)); } - *bc_url = apr_psprintf(pool, "%s/%ld", + *bc_url = apr_psprintf(result_pool, "%s/%ld", session->rev_root_stub, *revnum_used); } @@ -1135,20 +807,22 @@ get_baseline_info(const char **bc_url, { const char *vcc_url; - SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, conn, pool)); + SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, scratch_pool)); if (SVN_IS_VALID_REVNUM(revision)) { /* First check baseline information cache. */ SVN_ERR(svn_ra_serf__blncache_get_bc_url(bc_url, session->blncache, - revision, pool)); + revision, result_pool)); if (!*bc_url) { - SVN_ERR(retrieve_baseline_info(NULL, bc_url, conn, - vcc_url, revision, pool, pool)); + SVN_ERR(retrieve_baseline_info(NULL, bc_url, session, + vcc_url, revision, + result_pool, scratch_pool)); SVN_ERR(svn_ra_serf__blncache_set(session->blncache, NULL, - revision, *bc_url, pool)); + revision, *bc_url, + scratch_pool)); } *revnum_used = revision; @@ -1156,8 +830,8 @@ get_baseline_info(const char **bc_url, else { SVN_ERR(v1_get_youngest_revnum(revnum_used, bc_url, - conn, vcc_url, - pool, pool)); + session, vcc_url, + result_pool, scratch_pool)); } } @@ -1169,7 +843,6 @@ 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, @@ -1183,15 +856,10 @@ svn_ra_serf__get_stable_url(const char **stable_url, if (! url) url = session->session_url.path; - /* 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)); + session, revision, scratch_pool, scratch_pool)); SVN_ERR(svn_ra_serf__get_relative_path(&repos_relpath, url, - session, conn, scratch_pool)); + session, scratch_pool)); *stable_url = svn_path_url_add_component2(basecoll_url, repos_relpath, result_pool); @@ -1203,38 +871,8 @@ svn_ra_serf__get_stable_url(const char **stable_url, svn_error_t * -svn_ra_serf__get_resource_type(svn_node_kind_t *kind, - apr_hash_t *props) -{ - apr_hash_t *dav_props; - const char *res_type; - - 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")); - } - - if (strcmp(res_type, "collection") == 0) - { - *kind = svn_node_dir; - } - else - { - *kind = svn_node_file; - } - - return SVN_NO_ERROR; -} - - -svn_error_t * svn_ra_serf__fetch_dav_prop(const char **value, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, const char *url, svn_revnum_t revision, const char *propname, @@ -1244,7 +882,7 @@ svn_ra_serf__fetch_dav_prop(const char **value, apr_hash_t *props; apr_hash_t *dav_props; - SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn, url, revision, + SVN_ERR(svn_ra_serf__fetch_node_props(&props, session, url, revision, checked_in_props, scratch_pool, scratch_pool)); dav_props = apr_hash_get(props, "DAV:", 4); @@ -1261,3 +899,19 @@ svn_ra_serf__fetch_dav_prop(const char **value, return SVN_NO_ERROR; } + +/* Removes all non regular properties from PROPS */ +void +svn_ra_serf__keep_only_regular_props(apr_hash_t *props, + apr_pool_t *scratch_pool) +{ + apr_hash_index_t *hi; + + for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi)) + { + const char *propname = apr_hash_this_key(hi); + + if (svn_property_kind2(propname) != svn_prop_regular_kind) + svn_hash_sets(props, propname, NULL); + } +} |