diff options
Diffstat (limited to 'subversion/libsvn_ra_serf/options.c')
-rw-r--r-- | subversion/libsvn_ra_serf/options.c | 148 |
1 files changed, 101 insertions, 47 deletions
diff --git a/subversion/libsvn_ra_serf/options.c b/subversion/libsvn_ra_serf/options.c index 5389b04..a52977b 100644 --- a/subversion/libsvn_ra_serf/options.c +++ b/subversion/libsvn_ra_serf/options.c @@ -30,6 +30,7 @@ #include "svn_dirent_uri.h" #include "svn_hash.h" #include "svn_pools.h" +#include "svn_path.h" #include "svn_ra.h" #include "svn_dav.h" #include "svn_xml.h" @@ -51,7 +52,7 @@ * This enum represents the current state of our XML parsing for an OPTIONS. */ enum options_state_e { - INITIAL = 0, + INITIAL = XML_STATE_INITIAL, OPTIONS, ACTIVITY_COLLECTION, HREF @@ -65,7 +66,6 @@ typedef struct options_context_t { svn_boolean_t headers_processed; svn_ra_serf__session_t *session; - svn_ra_serf__connection_t *conn; svn_ra_serf__handler_t *handler; svn_ra_serf__response_handler_t inner_handler; @@ -112,19 +112,20 @@ options_closed(svn_ra_serf__xml_estate_t *xes, return SVN_NO_ERROR; } - +/* Implements svn_ra_serf__request_body_delegate_t */ static svn_error_t * create_options_body(serf_bucket_t **body_bkt, void *baton, serf_bucket_alloc_t *alloc, - apr_pool_t *pool) + apr_pool_t *pool /* request pool */, + apr_pool_t *scratch_pool) { serf_bucket_t *body; body = serf_bucket_aggregate_create(alloc); svn_ra_serf__add_xml_header_buckets(body, alloc); svn_ra_serf__add_open_tag_buckets(body, alloc, "D:options", "xmlns:D", "DAV:", - NULL); + SVN_VA_NULL); svn_ra_serf__add_tag_buckets(body, "D:activity-collection-set", NULL, alloc); svn_ra_serf__add_close_tag_buckets(body, alloc, "D:options"); @@ -372,7 +373,7 @@ options_response_handler(serf_request_t *request, serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback, opt_ctx); - /* Assume mergeinfo capability unsupported, if didn't recieve information + /* Assume mergeinfo capability unsupported, if didn't receive information about server or repository mergeinfo capability. */ if (!svn_hash_gets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO)) svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO, @@ -389,7 +390,6 @@ options_response_handler(serf_request_t *request, 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) { options_context_t *new_ctx; @@ -399,7 +399,6 @@ create_options_req(options_context_t **opt_ctx, new_ctx = apr_pcalloc(pool, sizeof(*new_ctx)); new_ctx->pool = pool; new_ctx->session = session; - new_ctx->conn = conn; new_ctx->youngest_rev = SVN_INVALID_REVNUM; @@ -407,14 +406,12 @@ create_options_req(options_context_t **opt_ctx, NULL, options_closed, NULL, new_ctx, pool); - handler = svn_ra_serf__create_expat_handler(xmlctx, pool); + handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL, pool); handler->method = "OPTIONS"; handler->path = session->session_url.path; handler->body_delegate = create_options_body; handler->body_type = "text/xml"; - handler->conn = conn; - handler->session = session; new_ctx->handler = handler; @@ -431,22 +428,25 @@ create_options_req(options_context_t **opt_ctx, svn_error_t * svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, 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(create_options_req(&opt_ctx, session, scratch_pool)); SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool)); - SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline, - opt_ctx->handler->path, - opt_ctx->handler->location)); + + if (opt_ctx->handler->sline.code != 200) + return svn_error_trace(svn_ra_serf__unexpected_status(opt_ctx->handler)); + + if (! SVN_IS_VALID_REVNUM(opt_ctx->youngest_rev)) + return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, + _("The OPTIONS response did not include " + "the youngest revision")); *youngest = opt_ctx->youngest_rev; - SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(*youngest)); return SVN_NO_ERROR; } @@ -454,21 +454,39 @@ svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest, svn_error_t * svn_ra_serf__v1_get_activity_collection(const char **activity_url, - svn_ra_serf__connection_t *conn, + svn_ra_serf__session_t *session, 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)); + if (session->activity_collection_url) + { + *activity_url = apr_pstrdup(result_pool, + session->activity_collection_url); + return SVN_NO_ERROR; + } + + SVN_ERR(create_options_req(&opt_ctx, session, scratch_pool)); SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool)); - SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline, - opt_ctx->handler->path, - opt_ctx->handler->location)); + if (opt_ctx->handler->sline.code != 200) + return svn_error_trace(svn_ra_serf__unexpected_status(opt_ctx->handler)); + + /* Cache the result. */ + if (opt_ctx->activity_collection) + { + session->activity_collection_url = + apr_pstrdup(session->pool, opt_ctx->activity_collection); + } + else + { + return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, + _("The OPTIONS response did not include the " + "requested activity-collection-set value")); + } *activity_url = apr_pstrdup(result_pool, opt_ctx->activity_collection); @@ -483,15 +501,20 @@ svn_ra_serf__v1_get_activity_collection(const char **activity_url, svn_error_t * svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess, const char **corrected_url, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { options_context_t *opt_ctx; - svn_error_t *err; + + if (corrected_url) + *corrected_url = NULL; /* This routine automatically fills in serf_sess->capabilities */ - SVN_ERR(create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0], pool)); + SVN_ERR(create_options_req(&opt_ctx, serf_sess, scratch_pool)); - err = svn_ra_serf__context_run_one(opt_ctx->handler, pool); + opt_ctx->handler->no_fail_on_http_redirect_status = TRUE; + + SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool)); /* If our caller cares about server redirections, and our response carries such a thing, report as much. We'll disregard ERR -- @@ -499,16 +522,47 @@ svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess, successfully parsing as XML or somesuch. */ if (corrected_url && (opt_ctx->handler->sline.code == 301)) { - svn_error_clear(err); - *corrected_url = opt_ctx->handler->location; + if (!opt_ctx->handler->location || !*opt_ctx->handler->location) + { + return svn_error_create( + SVN_ERR_RA_DAV_RESPONSE_HEADER_BADNESS, NULL, + _("Location header not set on redirect response")); + } + else if (svn_path_is_url(opt_ctx->handler->location)) + { + *corrected_url = svn_uri_canonicalize(opt_ctx->handler->location, + result_pool); + } + else + { + /* RFC1945 and RFC2616 state that the Location header's value + (from whence this CORRECTED_URL comes), if present, must be an + absolute URI. But some Apache versions (those older than 2.2.11, + it seems) transmit only the path portion of the URI. + See issue #3775 for details. */ + + apr_uri_t corrected_URI = serf_sess->session_url; + + corrected_URI.path = (char *)corrected_url; + *corrected_url = svn_uri_canonicalize( + apr_uri_unparse(scratch_pool, &corrected_URI, 0), + result_pool); + } + return SVN_NO_ERROR; } + else if (opt_ctx->handler->sline.code >= 300 + && opt_ctx->handler->sline.code < 399) + { + return svn_error_createf(SVN_ERR_RA_SESSION_URL_MISMATCH, NULL, + (opt_ctx->handler->sline.code == 301 + ? _("Repository moved permanently to '%s'") + : _("Repository moved temporarily to '%s'")), + opt_ctx->handler->location); + } - SVN_ERR(svn_error_compose_create( - svn_ra_serf__error_on_status(opt_ctx->handler->sline, - serf_sess->session_url.path, - opt_ctx->handler->location), - err)); + if (opt_ctx->handler->sline.code != 200) + return svn_error_trace(svn_ra_serf__unexpected_status(opt_ctx->handler)); /* Opportunistically cache any reported activity URL. (We don't want to have to ask for this again later, potentially against an @@ -522,12 +576,13 @@ svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess, return SVN_NO_ERROR; } - +/* Implements svn_ra_serf__request_body_delegate_t */ static svn_error_t * create_simple_options_body(serf_bucket_t **body_bkt, void *baton, serf_bucket_alloc_t *alloc, - apr_pool_t *pool) + apr_pool_t *pool /* request pool */, + apr_pool_t *scratch_pool) { serf_bucket_t *body; serf_bucket_t *s; @@ -549,18 +604,16 @@ svn_ra_serf__probe_proxy(svn_ra_serf__session_t *serf_sess, { svn_ra_serf__handler_t *handler; - handler = apr_pcalloc(scratch_pool, sizeof(*handler)); - handler->handler_pool = scratch_pool; + handler = svn_ra_serf__create_handler(serf_sess, scratch_pool); handler->method = "OPTIONS"; handler->path = serf_sess->session_url.path; - handler->conn = serf_sess->conns[0]; - handler->session = serf_sess; /* We don't care about the response body, so discard it. */ handler->response_handler = svn_ra_serf__handle_discard_body; /* We need a simple body, in order to send it in chunked format. */ handler->body_delegate = create_simple_options_body; + handler->no_fail_on_http_failure_status = TRUE; /* No special headers. */ @@ -574,9 +627,8 @@ svn_ra_serf__probe_proxy(svn_ra_serf__session_t *serf_sess, return SVN_NO_ERROR; } - SVN_ERR(svn_ra_serf__error_on_status(handler->sline, - handler->path, - handler->location)); + if (handler->sline.code != 200) + SVN_ERR(svn_ra_serf__unexpected_status(handler)); return SVN_NO_ERROR; } @@ -602,7 +654,7 @@ svn_ra_serf__has_capability(svn_ra_session_t *ra_session, /* If any capability is unknown, they're all unknown, so ask. */ if (cap_result == NULL) - SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, NULL, pool)); + SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, NULL, pool, pool)); /* Try again, now that we've fetched the capabilities. */ cap_result = svn_hash_gets(serf_sess->capabilities, capability); @@ -628,7 +680,9 @@ svn_ra_serf__has_capability(svn_ra_session_t *ra_session, APR_ARRAY_PUSH(paths, const char *) = ""; err = svn_ra_serf__get_mergeinfo(ra_session, &ignored, paths, 0, - FALSE, FALSE, pool); + svn_mergeinfo_explicit, + FALSE /* include_descendants */, + pool); if (err) { @@ -646,7 +700,7 @@ svn_ra_serf__has_capability(svn_ra_session_t *ra_session, cap_result = capability_yes; } else - return err; + return svn_error_trace(err); } else cap_result = capability_yes; |