diff options
Diffstat (limited to 'subversion/libsvn_ra_neon/options.c')
-rw-r--r-- | subversion/libsvn_ra_neon/options.c | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/subversion/libsvn_ra_neon/options.c b/subversion/libsvn_ra_neon/options.c deleted file mode 100644 index 5667e66..0000000 --- a/subversion/libsvn_ra_neon/options.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * options.c : routines for performing OPTIONS server requests - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ - - - -#include "svn_pools.h" -#include "svn_error.h" -#include "svn_dirent_uri.h" -#include "svn_private_config.h" -#include "../libsvn_ra/ra_loader.h" - -#include "private/svn_fspath.h" - -#include "ra_neon.h" - - -/* In a debug build, setting this environment variable to "yes" will force - the client to speak v1, even if the server is capable of speaking v2. */ -#define SVN_IGNORE_V2_ENV_VAR "SVN_I_LIKE_LATENCY_SO_IGNORE_HTTPV2" - -static const svn_ra_neon__xml_elm_t options_elements[] = -{ - { "DAV:", "activity-collection-set", ELEM_activity_coll_set, 0 }, - { "DAV:", "href", ELEM_href, SVN_RA_NEON__XML_CDATA }, - { "DAV:", "options-response", ELEM_options_response, 0 }, - - { NULL } -}; - -typedef struct options_ctx_t { - /*WARNING: WANT_CDATA should stay the first element in the baton: - svn_ra_neon__xml_collect_cdata() assumes the baton starts with a stringbuf. - */ - svn_stringbuf_t *want_cdata; - svn_stringbuf_t *cdata; - apr_pool_t *pool; - svn_string_t *activity_coll; -} options_ctx_t; - -static int -validate_element(svn_ra_neon__xml_elmid parent, svn_ra_neon__xml_elmid child) -{ - switch (parent) - { - case ELEM_root: - if (child == ELEM_options_response) - return child; - else - return SVN_RA_NEON__XML_INVALID; - - case ELEM_options_response: - if (child == ELEM_activity_coll_set) - return child; - else - return SVN_RA_NEON__XML_DECLINE; /* not concerned with other response */ - - case ELEM_activity_coll_set: - if (child == ELEM_href) - return child; - else - return SVN_RA_NEON__XML_DECLINE; /* not concerned with unknown crud */ - - default: - return SVN_RA_NEON__XML_DECLINE; - } - - /* NOTREACHED */ -} - -static svn_error_t * -start_element(int *elem, void *baton, int parent, - const char *nspace, const char *name, const char **atts) -{ - options_ctx_t *oc = baton; - const svn_ra_neon__xml_elm_t *elm - = svn_ra_neon__lookup_xml_elem(options_elements, nspace, name); - - *elem = elm ? validate_element(parent, elm->id) : SVN_RA_NEON__XML_DECLINE; - if (*elem < 1) /* Not a valid element */ - return SVN_NO_ERROR; - - if (elm->id == ELEM_href) - oc->want_cdata = oc->cdata; - else - oc->want_cdata = NULL; - - return SVN_NO_ERROR; -} - -static svn_error_t * -end_element(void *baton, int state, - const char *nspace, const char *name) -{ - options_ctx_t *oc = baton; - - if (state == ELEM_href) - oc->activity_coll = - svn_string_create(svn_urlpath__canonicalize(oc->cdata->data, oc->pool), - oc->pool); - - return SVN_NO_ERROR; -} - - -/** Capabilities exchange. */ - -/* Both server and repository support the capability. */ -static const char *capability_yes = "yes"; -/* Either server or repository does not support the capability. */ -static const char *capability_no = "no"; -/* Server supports the capability, but don't yet know if repository does. */ -static const char *capability_server_yes = "server-yes"; - - -/* Store in RAS the capabilities and other interesting tidbits of - information discovered from REQ's headers. Use POOL for temporary - allocation only. - - Also, if YOUNGEST_REV is not NULL, set *YOUNGEST_REV to the current - youngest revision if we can detect that from the OPTIONS exchange, or - to SVN_INVALID_REVNUM otherwise. */ -static void -parse_capabilities(ne_request *req, - svn_ra_neon__session_t *ras, - svn_revnum_t *youngest_rev, - apr_pool_t *pool) -{ - const char *val; - - if (youngest_rev) - *youngest_rev = SVN_INVALID_REVNUM; - - /* Start out assuming all capabilities are unsupported. */ - apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY, - APR_HASH_KEY_STRING, capability_no); - apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH, - APR_HASH_KEY_STRING, capability_no); - apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO, - APR_HASH_KEY_STRING, capability_no); - apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS, - APR_HASH_KEY_STRING, capability_no); - apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS, - APR_HASH_KEY_STRING, capability_no); - - /* Then find out which ones are supported. */ - val = ne_get_response_header(req, "dav"); - if (val) - { - /* Multiple headers of the same name will have been merged - together by the time we see them (either by an intermediary, - as is permitted in HTTP, or by neon) -- merged in the sense - that if a header "foo" appears multiple times, all the values - will be concatenated together, with spaces at the splice - points. For example, if the server sent: - - DAV: 1,2 - DAV: version-control,checkout,working-resource - DAV: merge,baseline,activity,version-controlled-collection - DAV: http://subversion.tigris.org/xmlns/dav/svn/depth - - Here we might see: - - val == "1,2, version-control,checkout,working-resource, merge,baseline,activity,version-controlled-collection, http://subversion.tigris.org/xmlns/dav/svn/depth, <http://apache.org/dav/propset/fs/1>" - - (Deliberately not line-wrapping that, so you can see what - we're about to parse.) - */ - - apr_array_header_t *vals = - svn_cstring_split(val, ",", TRUE, pool); - - /* Right now we only have a few capabilities to detect, so - just seek for them directly. This could be written - slightly more efficiently, but that wouldn't be worth it - until we have many more capabilities. */ - - if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals)) - apr_hash_set(ras->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(ras->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(ras->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(ras->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(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY, - APR_HASH_KEY_STRING, capability_yes); - } - - /* Not strictly capabilities, but while we're here, we might as well... */ - if ((val = ne_get_response_header(req, SVN_DAV_YOUNGEST_REV_HEADER))) - { - if (youngest_rev) - *youngest_rev = SVN_STR_TO_REV(val); - } - if ((val = ne_get_response_header(req, SVN_DAV_REPOS_UUID_HEADER))) - { - ras->uuid = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_ROOT_URI_HEADER))) - { - ne_uri root_uri = ras->root; - - root_uri.path = (char *)val; - ras->repos_root = svn_ra_neon__uri_unparse(&root_uri, ras->pool); - } - - /* HTTP v2 stuff */ - if ((val = ne_get_response_header(req, SVN_DAV_ME_RESOURCE_HEADER))) - { -#ifdef SVN_DEBUG - char *ignore_v2_env_var = getenv(SVN_IGNORE_V2_ENV_VAR); - - if (! (ignore_v2_env_var - && apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0)) - ras->me_resource = apr_pstrdup(ras->pool, val); -#else - ras->me_resource = apr_pstrdup(ras->pool, val); -#endif - } - if ((val = ne_get_response_header(req, SVN_DAV_REV_ROOT_STUB_HEADER))) - { - ras->rev_root_stub = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_REV_STUB_HEADER))) - { - ras->rev_stub = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_TXN_ROOT_STUB_HEADER))) - { - ras->txn_root_stub = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_TXN_STUB_HEADER))) - { - ras->txn_stub = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_VTXN_ROOT_STUB_HEADER))) - { - ras->vtxn_root_stub = apr_pstrdup(ras->pool, val); - } - if ((val = ne_get_response_header(req, SVN_DAV_VTXN_STUB_HEADER))) - { - ras->vtxn_stub = apr_pstrdup(ras->pool, val); - } -} - - -svn_error_t * -svn_ra_neon__exchange_capabilities(svn_ra_neon__session_t *ras, - const char **relocation_location, - svn_revnum_t *youngest_rev, - apr_pool_t *pool) -{ - svn_ra_neon__request_t* req; - svn_error_t *err = SVN_NO_ERROR; - ne_xml_parser *parser = NULL; - options_ctx_t oc = { 0 }; - int status_code; - - oc.pool = pool; - oc.cdata = svn_stringbuf_create("", pool); - - if (youngest_rev) - *youngest_rev = SVN_INVALID_REVNUM; - if (relocation_location) - *relocation_location = NULL; - - SVN_ERR(svn_ra_neon__request_create(&req, ras, "OPTIONS", ras->url->data, - pool)); - - /* ### Use a symbolic name somewhere for this MIME type? */ - ne_add_request_header(req->ne_req, "Content-Type", "text/xml"); - - /* Create a parser to read the normal response body */ - parser = svn_ra_neon__xml_parser_create(req, ne_accept_2xx, start_element, - svn_ra_neon__xml_collect_cdata, - end_element, &oc); - - /* Run the request and get the resulting status code. */ - if ((err = svn_ra_neon__request_dispatch(&status_code, req, NULL, - "<?xml version=\"1.0\" " - "encoding=\"utf-8\"?>" - "<D:options xmlns:D=\"DAV:\">" - "<D:activity-collection-set/>" - "</D:options>", - 200, - relocation_location ? 301 : 0, - pool))) - goto cleanup; - - if (req->code == 301) - { - *relocation_location = svn_ra_neon__request_get_location(req, pool); - goto cleanup; - } - - /* Was there an XML parse error somewhere? */ - err = svn_ra_neon__check_parse_error("OPTIONS", parser, ras->url->data); - if (err) - goto cleanup; - - /* We asked for, and therefore expect, to have found an activity - collection in the response. */ - if (oc.activity_coll == NULL) - { - err = svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, - _("The OPTIONS response did not include the " - "requested activity-collection-set; this often " - "means that the URL is not WebDAV-enabled")); - goto cleanup; - } - - ras->act_coll = apr_pstrdup(ras->pool, oc.activity_coll->data); - parse_capabilities(req->ne_req, ras, youngest_rev, pool); - - cleanup: - svn_ra_neon__request_destroy(req); - - return err; -} - - -svn_error_t * -svn_ra_neon__get_activity_collection(const svn_string_t **activity_coll, - svn_ra_neon__session_t *ras, - apr_pool_t *pool) -{ - if (! ras->act_coll) - SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL, NULL, pool)); - *activity_coll = svn_string_create(ras->act_coll, pool); - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_ra_neon__has_capability(svn_ra_session_t *session, - svn_boolean_t *has, - const char *capability, - apr_pool_t *pool) -{ - svn_ra_neon__session_t *ras = session->priv; - const char *cap_result; - - /* This capability doesn't rely on anything server side. */ - if (strcmp(capability, SVN_RA_CAPABILITY_COMMIT_REVPROPS) == 0) - { - *has = TRUE; - return SVN_NO_ERROR; - } - - cap_result = apr_hash_get(ras->capabilities, - capability, - APR_HASH_KEY_STRING); - - /* If any capability is unknown, they're all unknown, so ask. */ - if (cap_result == NULL) - { - SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL, NULL, pool)); - } - - - /* Try again, now that we've fetched the capabilities. */ - cap_result = apr_hash_get(ras->capabilities, - capability, APR_HASH_KEY_STRING); - - /* Some capabilities depend on the repository as well as the server. - NOTE: svn_ra_serf__has_capability() has a very similar code block. If - you change something here, check there as well. */ - if (cap_result == capability_server_yes) - { - if (strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO) == 0) - { - /* Handle mergeinfo specially. Mergeinfo depends on the - repository as well as the server, but the server routine - that answered our svn_ra_neon__exchange_capabilities() call - above didn't even know which repository we were interested in - -- it just told us whether the server supports mergeinfo. - If the answer was 'no', there's no point checking the - particular repository; but if it was 'yes', we still must - change it to 'no' iff the repository itself doesn't - support mergeinfo. */ - svn_mergeinfo_catalog_t ignored; - svn_error_t *err; - apr_array_header_t *paths = apr_array_make(pool, 1, - sizeof(char *)); - APR_ARRAY_PUSH(paths, const char *) = ""; - - err = svn_ra_neon__get_mergeinfo(session, &ignored, paths, 0, - FALSE, FALSE, pool); - - if (err) - { - if (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE) - { - svn_error_clear(err); - cap_result = capability_no; - } - else if (err->apr_err == SVN_ERR_FS_NOT_FOUND) - { - /* Mergeinfo requests use relative paths, and - anyway we're in r0, so this is a likely error, - but it means the repository supports mergeinfo! */ - svn_error_clear(err); - cap_result = capability_yes; - } - else - return err; - - } - else - cap_result = capability_yes; - - apr_hash_set(ras->capabilities, - SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING, - cap_result); - } - else - { - return svn_error_createf - (SVN_ERR_UNKNOWN_CAPABILITY, NULL, - _("Don't know how to handle '%s' for capability '%s'"), - capability_server_yes, capability); - } - } - - if (cap_result == capability_yes) - { - *has = TRUE; - } - else if (cap_result == capability_no) - { - *has = FALSE; - } - else if (cap_result == NULL) - { - return svn_error_createf - (SVN_ERR_UNKNOWN_CAPABILITY, NULL, - _("Don't know anything about capability '%s'"), capability); - } - else /* "can't happen" */ - { - /* Well, let's hope it's a string. */ - return svn_error_createf - (SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, - _("Attempt to fetch capability '%s' resulted in '%s'"), - capability, cap_result); - } - - return SVN_NO_ERROR; -} |