summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_neon/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_neon/options.c')
-rw-r--r--subversion/libsvn_ra_neon/options.c480
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;
-}