summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_neon/get_locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_neon/get_locks.c')
-rw-r--r--subversion/libsvn_ra_neon/get_locks.c440
1 files changed, 0 insertions, 440 deletions
diff --git a/subversion/libsvn_ra_neon/get_locks.c b/subversion/libsvn_ra_neon/get_locks.c
deleted file mode 100644
index ef1fefe..0000000
--- a/subversion/libsvn_ra_neon/get_locks.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * get_locks.c : RA get-locks API implementation
- *
- * ====================================================================
- * 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.
- * ====================================================================
- */
-
-
-
-#define APR_WANT_STRFUNC
-#include <apr_want.h> /* for strcmp() */
-
-#include <apr_pools.h>
-#include <apr_tables.h>
-#include <apr_strings.h>
-#include <apr_xml.h>
-
-#include <ne_basic.h>
-
-#include "svn_error.h"
-#include "svn_pools.h"
-#include "svn_base64.h"
-#include "svn_ra.h"
-#include "../libsvn_ra/ra_loader.h"
-#include "svn_path.h"
-#include "svn_xml.h"
-#include "svn_dav.h"
-#include "svn_time.h"
-
-#include "private/svn_dav_protocol.h"
-#include "private/svn_fspath.h"
-#include "svn_private_config.h"
-
-#include "ra_neon.h"
-
-/* -------------------------------------------------------------------------
-**
-** GET-LOCKS REPORT HANDLING
-**
-** DeltaV provides a mechanism for fetching a list of locks below a
-** path, but it's often unscalable. It requires doing a PROPFIND of
-** depth infinity, looking for the 'DAV:lockdiscovery' prop on every
-** resource. But depth-infinity propfinds can sometimes behave like a
-** DoS attack, and mod_dav even disables them by default!
-**
-** So we send a custom 'get-locks' REPORT on a public URI... which is
-** fine, since all lock queries are always against HEAD anyway. The
-** response is a just a list of svn_lock_t's. (Generic DAV clients,
-** of course, are free to do infinite PROPFINDs as they wish, assuming
-** the server allows it.)
-*/
-
-/* Elements used in a get-locks-report response */
-static const svn_ra_neon__xml_elm_t getlocks_report_elements[] =
-{
- { SVN_XML_NAMESPACE, "get-locks-report", ELEM_get_locks_report, 0 },
- { SVN_XML_NAMESPACE, "lock", ELEM_lock, 0},
- { SVN_XML_NAMESPACE, "path", ELEM_lock_path, SVN_RA_NEON__XML_CDATA },
- { SVN_XML_NAMESPACE, "token", ELEM_lock_token, SVN_RA_NEON__XML_CDATA },
- { SVN_XML_NAMESPACE, "owner", ELEM_lock_owner, SVN_RA_NEON__XML_CDATA },
- { SVN_XML_NAMESPACE, "comment", ELEM_lock_comment, SVN_RA_NEON__XML_CDATA },
- { SVN_XML_NAMESPACE, SVN_DAV__CREATIONDATE,
- ELEM_lock_creationdate, SVN_RA_NEON__XML_CDATA },
- { SVN_XML_NAMESPACE, "expirationdate",
- ELEM_lock_expirationdate, SVN_RA_NEON__XML_CDATA },
- { NULL }
-};
-
-/*
- * The get-locks-report xml request body is super-simple.
- * The server doesn't need anything but the URI in the REPORT request line.
- *
- * <S:get-locks-report [depth=DEPTH] xmlns...>
- * </S:get-locks-report>
- *
- * The get-locks-report xml response is just a list of svn_lock_t's
- * that exist at or "below" the request URI. (The server runs
- * svn_repos_fs_get_locks()).
- *
- * <S:get-locks-report xmlns...>
- * <S:lock>
- * <S:path>/foo/bar/baz</S:path>
- * <S:token>opaquelocktoken:706689a6-8cef-0310-9809-fb7545cbd44e
- * </S:token>
- * <S:owner>fred</S:owner>
- * <S:comment encoding="base64">ET39IGCB93LL4M</S:comment>
- * <S:creationdate>2005-02-07T14:17:08Z</S:creationdate>
- * <S:expirationdate>2005-02-08T14:17:08Z</S:expirationdate>
- * </S:lock>
- * ...
- * </S:get-locks-report>
- *
- *
- * The <path> and <token> and date-element cdata is xml-escaped by mod_dav_svn.
- *
- * The <owner> and <comment> cdata is always xml-escaped, but
- * possibly also base64-encoded if necessary, as indicated by the
- * encoding attribute.
- *
- * The absence of <expirationdate> means that there's no expiration.
- *
- * If there are no locks to return, then the response will look just
- * like the request.
- */
-
-
-/* Context for parsing server's response. */
-typedef struct get_locks_baton_t {
- const char *path; /* fspath target of the report */
- svn_depth_t requested_depth; /* requested depth of the report */
- svn_lock_t *current_lock; /* the lock being constructed */
- svn_stringbuf_t *cdata_accum; /* a place to accumulate cdata */
- const char *encoding; /* normally NULL, else the value of
- 'encoding' attribute on cdata's tag.*/
- apr_hash_t *lock_hash; /* the final hash returned */
-
- apr_pool_t *scratchpool; /* temporary stuff goes in here */
- apr_pool_t *pool; /* permanent stuff goes in here */
-
-} get_locks_baton_t;
-
-
-
-/* This implements the `svn_ra_neon__startelm_cb_t' prototype. */
-static svn_error_t *
-getlocks_start_element(int *elem, void *userdata, int parent_state,
- const char *ns, const char *ln, const char **atts)
-{
- get_locks_baton_t *baton = userdata;
- const svn_ra_neon__xml_elm_t *elm;
-
- elm = svn_ra_neon__lookup_xml_elem(getlocks_report_elements, ns, ln);
-
- /* Just skip unknown elements. */
- if (!elm)
- {
- *elem = NE_XML_DECLINE;
- return SVN_NO_ERROR;
- }
-
- if (elm->id == ELEM_lock)
- {
- if (parent_state != ELEM_get_locks_report)
- return UNEXPECTED_ELEMENT(ns, ln);
- else
- /* allocate a new svn_lock_t in the permanent pool */
- baton->current_lock = svn_lock_create(baton->pool);
- }
-
- else if (elm->id == ELEM_lock_path
- || elm->id == ELEM_lock_token
- || elm->id == ELEM_lock_owner
- || elm->id == ELEM_lock_comment
- || elm->id == ELEM_lock_creationdate
- || elm->id == ELEM_lock_expirationdate)
- {
- const char *encoding;
-
- if (parent_state != ELEM_lock)
- return UNEXPECTED_ELEMENT(ns, ln);
-
- /* look for any incoming encodings on these elements. */
- encoding = svn_xml_get_attr_value("encoding", atts);
- if (encoding)
- baton->encoding = apr_pstrdup(baton->scratchpool, encoding);
- }
-
- *elem = elm->id;
-
- return SVN_NO_ERROR;
-}
-
-
-/* This implements the `svn_ra_svn__cdata_cb_t' prototype. */
-static svn_error_t *
-getlocks_cdata_handler(void *userdata, int state,
- const char *cdata, size_t len)
-{
- get_locks_baton_t *baton = userdata;
-
- switch(state)
- {
- case ELEM_lock_path:
- case ELEM_lock_token:
- case ELEM_lock_owner:
- case ELEM_lock_comment:
- case ELEM_lock_creationdate:
- case ELEM_lock_expirationdate:
- /* accumulate cdata in the scratchpool. */
- svn_stringbuf_appendbytes(baton->cdata_accum, cdata, len);
- break;
- }
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* This implements the `svn_ra_neon__endelm_cb_t' prototype. */
-static svn_error_t *
-getlocks_end_element(void *userdata, int state,
- const char *ns, const char *ln)
-{
- get_locks_baton_t *baton = userdata;
- const svn_ra_neon__xml_elm_t *elm;
-
- elm = svn_ra_neon__lookup_xml_elem(getlocks_report_elements, ns, ln);
-
- /* Just skip unknown elements. */
- if (elm == NULL)
- return SVN_NO_ERROR;
-
- switch (elm->id)
- {
- case ELEM_lock:
- /* is the final svn_lock_t valid? all fields must be present
- except for 'comment' and 'expiration_date'. */
- if ((! baton->current_lock->path)
- || (! baton->current_lock->token)
- || (! baton->current_lock->owner)
- || (! baton->current_lock->creation_date))
- SVN_ERR(svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("Incomplete lock data returned")));
-
- /* Filter out unwanted paths. Since Subversion only allows
- locks on files, we can treat depth=immediates the same as
- depth=files for filtering purposes. Meaning, we'll keep
- this lock if:
-
- a) its path is the very path we queried, or
- b) we've asked for a fully recursive answer, or
- c) we've asked for depth=files or depth=immediates, and this
- lock is on an immediate child of our query path.
- */
- if ((strcmp(baton->path, baton->current_lock->path) == 0)
- || (baton->requested_depth == svn_depth_infinity))
- {
- apr_hash_set(baton->lock_hash, baton->current_lock->path,
- APR_HASH_KEY_STRING, baton->current_lock);
- }
- else if ((baton->requested_depth == svn_depth_files) ||
- (baton->requested_depth == svn_depth_immediates))
- {
- const char *rel_uri = svn_fspath__is_child(baton->path,
- baton->current_lock->path,
- baton->scratchpool);
- if (rel_uri && (svn_path_component_count(rel_uri) == 1))
- apr_hash_set(baton->lock_hash, baton->current_lock->path,
- APR_HASH_KEY_STRING, baton->current_lock);
- svn_pool_clear(baton->scratchpool);
- }
- break;
-
- case ELEM_lock_path:
- /* neon has already xml-unescaped the cdata for us. */
- baton->current_lock->path =
- svn_fspath__canonicalize(apr_pstrmemdup(baton->scratchpool,
- baton->cdata_accum->data,
- baton->cdata_accum->len),
- baton->pool);
-
- /* clean up the accumulator. */
- svn_stringbuf_setempty(baton->cdata_accum);
- svn_pool_clear(baton->scratchpool);
- break;
-
- case ELEM_lock_token:
- /* neon has already xml-unescaped the cdata for us. */
- baton->current_lock->token = apr_pstrmemdup(baton->pool,
- baton->cdata_accum->data,
- baton->cdata_accum->len);
- /* clean up the accumulator. */
- svn_stringbuf_setempty(baton->cdata_accum);
- svn_pool_clear(baton->scratchpool);
- break;
-
- case ELEM_lock_creationdate:
- SVN_ERR(svn_time_from_cstring(&(baton->current_lock->creation_date),
- baton->cdata_accum->data,
- baton->scratchpool));
- /* clean up the accumulator. */
- svn_stringbuf_setempty(baton->cdata_accum);
- svn_pool_clear(baton->scratchpool);
- break;
-
- case ELEM_lock_expirationdate:
- SVN_ERR(svn_time_from_cstring(&(baton->current_lock->expiration_date),
- baton->cdata_accum->data,
- baton->scratchpool));
- /* clean up the accumulator. */
- svn_stringbuf_setempty(baton->cdata_accum);
- svn_pool_clear(baton->scratchpool);
- break;
-
- case ELEM_lock_owner:
- case ELEM_lock_comment:
- {
- const char *final_val;
-
- if (baton->encoding)
- {
- /* Possibly recognize other encodings someday. */
- if (strcmp(baton->encoding, "base64") == 0)
- {
- svn_string_t *encoded_val;
- const svn_string_t *decoded_val;
-
- encoded_val = svn_string_create_from_buf(baton->cdata_accum,
- baton->scratchpool);
- decoded_val = svn_base64_decode_string(encoded_val,
- baton->scratchpool);
- final_val = decoded_val->data;
- }
- else
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
- NULL,
- _("Got unrecognized encoding '%s'"),
- baton->encoding);
-
- baton->encoding = NULL;
- }
- else
- {
- /* neon has already xml-unescaped the cdata for us. */
- final_val = baton->cdata_accum->data;
- }
-
- if (elm->id == ELEM_lock_owner)
- baton->current_lock->owner = apr_pstrdup(baton->pool, final_val);
- if (elm->id == ELEM_lock_comment)
- baton->current_lock->comment = apr_pstrdup(baton->pool, final_val);
-
- /* clean up the accumulator. */
- svn_stringbuf_setempty(baton->cdata_accum);
- svn_pool_clear(baton->scratchpool);
- break;
- }
-
-
- default:
- break;
- }
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_ra_neon__get_locks(svn_ra_session_t *session,
- apr_hash_t **locks,
- const char *path,
- svn_depth_t depth,
- apr_pool_t *pool)
-{
- svn_ra_neon__session_t *ras = session->priv;
- const char *body, *url, *rel_path;
- svn_error_t *err;
- int status_code = 0;
- get_locks_baton_t baton;
-
- /* We always run the report on the 'public' URL, which represents
- HEAD anyway. If the path doesn't exist in HEAD, then there can't
- possibly be a lock, so we just return no locks. */
- url = svn_path_url_add_component2(ras->url->data, path, pool);
-
- SVN_ERR(svn_ra_neon__get_path_relative_to_root(session, &rel_path,
- url, pool));
-
- baton.lock_hash = apr_hash_make(pool);
- baton.path = svn_fspath__canonicalize(rel_path, pool);
- baton.requested_depth = depth;
- baton.pool = pool;
- baton.scratchpool = svn_pool_create(pool);
- baton.current_lock = NULL;
- baton.encoding = NULL;
- baton.cdata_accum = svn_stringbuf_create("", pool);
-
- body = apr_psprintf(pool,
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
- "<S:get-locks-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
- "xmlns:D=\"DAV:\" depth=\"%s\">"
- "</S:get-locks-report>",
- svn_depth_to_word(depth));
-
- err = svn_ra_neon__parsed_request(ras, "REPORT", url,
- body, NULL, NULL,
- getlocks_start_element,
- getlocks_cdata_handler,
- getlocks_end_element,
- &baton,
- NULL, /* extra headers */
- &status_code,
- FALSE,
- pool);
-
- svn_pool_destroy(baton.scratchpool);
-
- if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
- {
- svn_error_clear(err);
- *locks = baton.lock_hash;
- return SVN_NO_ERROR;
- }
-
- /* ### Should svn_ra_neon__parsed_request() take care of storing auth
- ### info itself? */
- err = svn_ra_neon__maybe_store_auth_info_after_result(err, ras, pool);
-
- /* Map status 501: Method Not Implemented to our not implemented error.
- 1.0.x servers and older don't support this report. */
- if (status_code == 501)
- return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err,
- _("Server does not support locking features"));
-
- if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
- return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err,
- _("Server does not support locking features"));
-
- else if (err)
- return err;
-
- *locks = baton.lock_hash;
- return SVN_NO_ERROR;
-}